(多线程,客户端-服务器通信)在彩票管理系统的应用

1.多线程

在本项目中的线程安全体现在客户端的读线程, 通过人为的控制和调度, 保证共享资源的多线程访问成为线程安全, 保证结果的准确

 //一个对象一把锁,即所有客户端的读线程是共用一把锁
		synchronized (ClientDemo.class) {
			if (ClientDemo.lastResponse == null) {
				try {
					ClientDemo.class.wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}

			// 读到了消息
			MyResponse lastResponse = ClientDemo.lastResponse;
			ClientDemo.lastResponse = null;
			System.out.println(lastResponse.getrMeg().get(MyResponse.MEG_CONTENT));
			// 判断登入是否成功,成功则进入操作界面,不成功就返回到开始界面
			if (lastResponse.isSuccess()) {
				// 登入成功进入第二层操作界面
				this.uName = uName;
				SecondMenu sm = new SecondMenu(oos, lastResponse);
				sm.operateMenu(level, uName);// 登入成功后三个身份界面
			} else {
				startMenu();
			}

			ClientDemo.class.notify();
		}

	}

2.客户端-服务器通信

MyRequest类和MyResponse类为服务器和客户端两个项目共享

MyRequest是请求对象,由客户端写,服务器读,

MyResponse是响应对象,由服务器写,客户端读

MyRequest类

比如登录功能,输入用户名密码后,点击登录按钮,输入的用户名密码包装成request对象

客户端对myquest对象的包装方式:常量type是请求类型,放入成员属性type中,字典集中key为string类型常量,value为实际的信息.

如:key:MEG_UNAME  value:aa存放用户名

package com.bwf.jar;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;

public class MyRequest implements Serializable{
	/**
	 * 序列化
	 */
	private static final long serialVersionUID = -1837937764657754236L;
	
	private int type;
	private Map<String,String> umap = new HashMap<>();
	
	
	//常量
	public static final int TYPE_REGIST = 1;
	public static final int TYPE_LOGIN = 2;
	public static final int TYPE_LOGOUT = 16;
	//彩民
	public static final int TYPE_CHANGEPWD = 4;
	public static final int TYPE_RECHARGE = 5;
	public static final int TYPE_BET = 6;
	public static final int TYPE_SHOWMESSAGE = 7;
	public static final int TYPE_DELETEME = 8;
	public static final int TYPE_BET_FLUSH = 9;
	//管理员
	public static final int TYPE_ADMIN_ISSUE = 10;
	public static final int TYPE_ADMIN_FINDBUYER = 11;
	public static final int TYPE_ADMIN_SORTBUYER_BYID = 12;
	public static final int TYPE_ADMIN_SORTBUYER_BYMONEY = 13;
	public static final int TYPE_ADMIN_GETHISTORY = 19;
	//公证员
	public static final int TYPE_GREFFIER_DRAWLOTTERY = 14;
	public static final int TYPE_GREFFIER_SHOWLOTTERYMEG = 15;
	//登入者的信息
	public static final String MEG_USERNAME = "uName";
	public static final String MEG_USERPWD = "uPwd";
	public static final String MEG_LEVEL = "level";	//登入者的身份
	public static final String MEG_NEWPWD = "newPwd";//修改密码的时候需要设置
	public static final String MEG_ADDMONEY = "addMoney";//修改余额
	//彩票信息
	public static final String LOTTERY_SELECTNUM = "selectNum";//彩票号码
	public static final String LOTTERY_BUYCOUNT = "buyCount";//彩票注数
	public static final String LOTTERY_TIME = "time";//彩票期号
	public static final String LOTTERY_NEWPRICE = "newPrice";//新的单价
	public static final String LOTTERY_WINNUM = "winNum";//开奖号码
	
	public static final String ADMIN_BUYERID = "buyerId";//被查询的彩民ID
	
	public static final String MEG = "meg";
	
	public MyRequest(int type) {
		super();
		this.type = type;
	}
	
	

	public int getType() {
		return type;
	}
	public Map<String, String> getUmap() {
		return umap;
	}

	@Override
	public String toString() {
		return "MyRequest [type=" + type + ", umap=" + umap + "]";
	}
	
	
	

}

客户端写线程通过套接字的输出流把请求对象发送到服务器

package com.bwf.client;

import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.Socket;

import com.bwf.jar.MyRequest;
import com.bwf.jar.MyResponse;

public class ClientMenu {
	private Socket socket;
	private ObjectOutputStream oos;
	private String uName;

	public ClientMenu(Socket socket) throws IOException {
		super();
                //套接字由构造传入
		this.socket = socket;
		oos = new ObjectOutputStream(new BufferedOutputStream(socket.getOutputStream()));
	}

	// 这里放所有客户端的菜单方法

	public void startMenu() throws IOException {
		while (true) {
			// 开始界面就是登入界面
			login();
		}

	}

	private void login() throws IOException {
		// 这里修改成GUI的界面
		System.out.println("登入界面:");
		System.out.println("请输入你是否需要注册:0-是,1-不是");
		int chose = ClientDemo.sc.nextInt();
		if (chose == 0) {
			regist();
			return;
		}

		System.out.println("请输入用户名:");
		String uName = ClientDemo.sc.next();

		System.out.println("请输入密码:");
		String uPwd = ClientDemo.sc.next();

		System.out.println("还需要接收一个值,表示登入者的身份:");
		// 三个身份(1-彩民,2-管理员,3-公证员)这个身份也决定了服务器从那个表中查询数据
		String level = "彩民";

		// 包装成一个类
		MyRequest request = new MyRequest(MyRequest.TYPE_LOGIN);
		request.getUmap().put(MyRequest.MEG_USERNAME, uName);
		request.getUmap().put(MyRequest.MEG_USERPWD, uPwd);
		request.getUmap().put(MyRequest.MEG_LEVEL, level);

		// 包装好了,就发送过去,序列化
		oos.writeObject(request);
		oos.flush();
                //一个对象一把锁,即所有客户端的读线程是共用一把锁
		synchronized (ClientDemo.class) {
			if (ClientDemo.lastResponse == null) {
				try {
					ClientDemo.class.wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}

			// 读到了消息
			MyResponse lastResponse = ClientDemo.lastResponse;
			ClientDemo.lastResponse = null;
			System.out.println(lastResponse.getrMeg().get(MyResponse.MEG_CONTENT));
			// 判断登入是否成功,成功则进入操作界面,不成功就返回到开始界面
			if (lastResponse.isSuccess()) {
				// 登入成功进入第二层操作界面
				this.uName = uName;
				SecondMenu sm = new SecondMenu(oos, lastResponse);
				sm.operateMenu(level, uName);// 登入成功后三个身份界面
			} else {
				startMenu();
			}

			ClientDemo.class.notify();
		}

	}

	// private void tellServer() throws IOException {
	// MyRequest request = new MyRequest(MyRequest.TYPE_LOGOUT);
	// request.getUmap().put(MyRequest.MEG, "用户下线!!!");
	// request.getUmap().put(MyRequest.MEG_USERNAME, uName);
	//
	// oos.writeObject(request);
	// oos.flush();
	//
	// }

	private void regist() throws IOException {
		// 接受用户输入的用户名和密码
		System.out.println("请注册:");
		System.out.println("请输入用户名:");
		String uName = ClientDemo.sc.next();
		System.out.println("请输入密码:");
		String uPwd = ClientDemo.sc.next();

		// 包装成一个类
		MyRequest request = new MyRequest(MyRequest.TYPE_REGIST);
		request.getUmap().put(MyRequest.MEG_USERNAME, uName);
		request.getUmap().put(MyRequest.MEG_USERPWD, uPwd);

		// 包装好了,就发送过去,序列化
		oos.writeObject(request);
		oos.flush();

		synchronized (ClientDemo.class) {
			if (ClientDemo.lastResponse == null) {
				try {
					ClientDemo.class.wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}

			// 读到了消息
			MyResponse lastResponse = ClientDemo.lastResponse;
			ClientDemo.lastResponse = null;
			System.out.println(lastResponse.getrMeg().get(MyResponse.MEG_CONTENT));
			if (lastResponse.isSuccess()) {
				startMenu();
			}else {
				
				
			}

			notify();
		}

	}

}

服务器收到后根据响应类型转到相应的case进行处理

package com.bwf.server;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.net.SocketException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

import com.bwf.context.ApplicationContext;
import com.bwf.jar.MyRequest;
import com.bwf.jar.MyResponse;
import com.bwf.service.AdminService;
import com.bwf.service.UserService;

public class ServerThread implements Runnable {

	private Socket socket;

	private UserService us;
	private AdminService as;

	// 这个记录所有在线的客户
	public static Map<String, ObjectOutputStream> onLineMap = new HashMap<>();

	public ServerThread(Socket socket) {
		super();
		this.socket = socket;
	}

	@Override
	public void run() {
		ObjectInputStream ois = null;
		ObjectOutputStream oos = null;
		try {
//通过套接字获得输入输出流
			ois = new ObjectInputStream(new BufferedInputStream(socket.getInputStream()));
			oos = new ObjectOutputStream(new BufferedOutputStream(socket.getOutputStream()));
			MyRequest request = null;
			// 初始化读取xml文件,实例化对象并存入map,注入依赖
			ApplicationContext.init();
			us = (UserService) ApplicationContext.getBean("UserService");
			as = (AdminService) ApplicationContext.getBean("AdminService");
			while ((request = (MyRequest) ois.readObject()) != null) {
				System.out.println(request);// 测试通信

				MyResponse response = null;// 日志功能暂时不做,但是保留这个

				switch (request.getType()) {
				case MyRequest.TYPE_REGIST:
					try {
						response = us.doRegist(request, oos);
						System.out.println("注册成功!!");
					} catch (Exception e) {
						System.out.println(e.getMessage());
					}
					break;
				case MyRequest.TYPE_LOGIN:
					try {
						response = us.doLogin(request, oos);
						System.out.println(response.toString());
					} catch (Exception e) {
						System.out.println("登入失败!!");
						System.out.println(e.getMessage());
					}
					break;
				case MyRequest.TYPE_CHANGEPWD:
					try {
						response = us.doChangePwd(request, oos);
					} catch (Exception e) {
						System.out.println(e.getMessage());
					}
					break;
				case MyRequest.TYPE_RECHARGE:
					try {
						response = us.doRecharge(request, oos);
					} catch (Exception e) {
						System.out.println(e.getMessage());
					}
					break;
				case MyRequest.TYPE_BET:
					try {
						response = us.doBet(request, oos);
					} catch (Exception e) {
						System.out.println(e.getMessage());
					}
					break;
				case MyRequest.TYPE_SHOWMESSAGE:
					try {
						response = us.doShowMessage(request, oos);
					} catch (Exception e) {
						System.out.println(e.getMessage());
					}
					break;
				case MyRequest.TYPE_BET_FLUSH:
					try {
						response = us.doBetFlush(request, oos);
					} catch (Exception e) {
						System.out.println(e.getMessage());
					}
					break;
//				case MyRequest.TYPE_USER_LOGOUT:
//					try {
//						System.out.println(request);
//						response = us.doUserLogout(request,oos);
//					} catch (Exception e) {
//						System.out.println(e.getMessage());
//					}
//					break;
				// 从这里开始是管理员的功能
				case MyRequest.TYPE_ADMIN_ISSUE:
					try {
						response = as.doIssue(request, oos);
						System.out.println(response.isIssue());
					} catch (Exception e) {
						System.out.println(e.getMessage());
					}
					break;
				case MyRequest.TYPE_ADMIN_FINDBUYER:
					try {
						response = as.doFindBuyer(request, oos);
						System.out.println(response.isIssue());
					} catch (Exception e) {
						System.out.println(e.getMessage());
					}
					break;
				case MyRequest.TYPE_ADMIN_SORTBUYER_BYID:
					try {
						
						response = as.doSortBuyerById(request, oos);
						System.out.println(response.isIssue());
					} catch (Exception e) {
						System.out.println(e.getMessage());
					}
					break;
				case MyRequest.TYPE_ADMIN_SORTBUYER_BYMONEY:
					try {
						response = as.doSortBuyerByMoney(request, oos);
						System.out.println(response.toString());
					} catch (Exception e) {
						System.out.println(e.getMessage());
					}
					break;
//				case MyRequest.TYPE_ADMIN_SORTBUYER_BYMONEY:
//					try {
//						response = as.doSortBuyerByMoney(request, oos);
//						System.out.println(response.toString());
//					} catch (Exception e) {
//						System.out.println(e.getMessage());
//					}
//					break;
//					
				//这里开始是公证员的功能
				case MyRequest.TYPE_GREFFIER_DRAWLOTTERY:
					try {
						response = as.doDrawLottery(request, oos);
					} catch (Exception e) {
						System.out.println(e.getMessage());
					}
					break;
				case MyRequest.TYPE_GREFFIER_SHOWLOTTERYMEG:
					try {
						System.out.println(request);
						response = as.doShowLotteryMeg(request, oos);
					} catch (Exception e) {
						System.out.println(e.getMessage());
					}
					break;
				case MyRequest.TYPE_LOGOUT:
					delClientUser(request);
					break;

				default:
					break;
				}

				// if(response != null) {
				// LogRecord log = new LogRecord(new Date(), socket.getInetAddress().toString(),
				// request, response);
				// FileUtil.saveLog(log);
				// }
			}

		} catch (SocketException e) {

			Iterator<Entry<String, ObjectOutputStream>> iterator = onLineMap.entrySet().iterator();
			while (iterator.hasNext()) {
				Entry<String, ObjectOutputStream> next = iterator.next();
				if (next.getValue().equals(oos)) {
					iterator.remove();
					System.out.println(next.getKey() + "删除成功!!");
				}
			}

			System.out.println("客户端退出!!");
			return;
		} catch (IOException e1) {
			e1.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}

	}

	private void delClientUser(MyRequest request) {

		String name = request.getUmap().get(MyRequest.MEG_USERNAME);

		
		onLineMap.remove(name);

	}

	

	// private String getNewContent(String content, String name, String str) {
	// Date date = new Date();
	// SimpleDateFormat sdf = new SimpleDateFormat("yy/MM/dd HH:mm:ss ");
	// String s_date = sdf.format(date);
	//
	// StringBuilder sb = new
	// StringBuilder(s_date).append(name).append(str).append(" : ").append(content);
	// return sb.toString();
	// }

}

服务器处理完成后包装响应对象发送回客户端,响应对象和请求对象类似,故不做赘述.

客户端收到后根据响应类型作相应处理.

猜你喜欢

转载自blog.csdn.net/qq_36194262/article/details/82962966
今日推荐