为了能准确,精准的传递信息,我们在服务器和客户端互相发消息的基础上,需要进行细化分类。
服务器需要能识别客户端传来的是什么请求,也就是要区分是登录消息,是注册消息,还是聊天消息。那么在客户端,简单的直接发送就满足不了这些要求,需要像"打暗号"一样,先告诉服务端我发送的消息是哪一类的,在发送消息主体
至于分类,要先对服务端和客户端进行统一要求,确保发送和收到的"暗号"是同一个,那么就先创建一个类,来存储对应的暗号,代码如下
java
public class MessageType {
public static final byte LOGIN = 1; //登录
public static final byte REGISTER = 2; //注册
public static final byte PRIVATE = 3; //私聊
public static final byte GROUP = 4; //广播
public static final byte CHAT = 5;
public static final byte YES = 6;
public static final byte NO = 7;
}
这样,将这个类分别放在服务端和客户端中,统一口令
第二,服务端和客户端不是一对一的反应,一个服务端要同时接受多个客户端的请求,那么就要用到多线程。
服务端创建ServerSocket,用死循环等待每一个客户端的接入。在循环中,用accept阻塞操作,对每一个接入的用户创建一个线程。为了在线程中能找到对应的用户,在创建线程之前,就要对每个用户进行ID化,根据登录或注册的用户名和用户的Socket,创建一个Map,以键值对的形式存储用户接入的信息,以便后续的"广播"和"对话"。代码展示
java
//用户账号存储数组
public List<User> userList = new ArrayList();
public Server(){
//初始化注册账号
for(int i=1;i<=5;i++){
userList.add(new User(i+"1",i+"1"));
}
}
public void ServerStart() throws IOException {
ServerSocket serverSocket = new ServerSocket(19989);
System.out.println("服务器启动");
Map<Integer,Socket> map = new HashMap();
int userID=1;
while (true) {
Socket socket=serverSocket.accept();
map.put(userID,socket);
ServerThread serverThread=new ServerThread(socket,map,
userID++,userList);
new Thread (serverThread).start();
}
}
第三,处理传来的消息。为了能实时监听用户的消息,对每一个线程也需要进行死循环,并用read方法阻塞。前文提到的先传递消息类型,后传递消息主体,也就是需要进行两次接收,先接收消息类型,通过switch case的分类,再在对应的类中处理消息。
例如,我再客户端进行登录操作,那么我就需要先发送一个Message.LOGIN的消息给服务器,在发送我的账号密码给服务器,在服务器端进行账号密码的拆解,进行判断,返回登录成功或者失败的消息返回给客户端。
客户端接受到登录成功的消息,进而跳转到对应的界面,进行下一步对话。
以下是服务端代码展示
java
public void run(){
while (true) {
try {
int head = is.read();
String msg = readMsg();
switch (head) {
case MessageType.LOGIN:
handleLogin(msg);
break;
case MessageType.REGISTER:
break;
case MessageType.CHAT:
//判断聊天类型
String[] msgArr = msg.split(":");
if (msgArr[0].equals("g")) {
//广播
for (Map.Entry<Integer, Socket> entry : map.entrySet()) {
Socket s = entry.getValue();
if (s != socket) {
OutputStream os = s.getOutputStream();
sendMsg(os, msgArr[1]);
}
}
} else {
int id = Integer.parseInt(msgArr[0]);
//通过id找到socket
Socket s = map.get(id);
OutputStream os = s.getOutputStream();
sendMsg(os, msgArr[1]);
}
System.out.println("client:" + msg);
break;
default:
System.out.println("错误文件头");
break;
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}