在实现韩顺平Java的多用户即使通信系统实战项目中:
对于客户端线程的停止,老韩是向服务器端发送一个消息对象,提示服务器端进行资源释放(包含线程集合资源以及socket连接断开)。对于客户端部分,使用如下代码:
// 编写一个方法,退出客户端,并给服务器端发送一个退出系统的消息对象 public void logout() { Message message = new Message(); message.setMesType(MessageType.MESSAGE_CLEAR_EXIT); message.setSender(u.getUserId()); // 发送message对象 try { ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream()); oos.writeObject(message); System.out.println(TimeGet.getLocalTime() + " 用户:" + u.getUserId() + " 退出系统 "); System.exit(0); // 结束虚拟机,客户端 } catch (IOException e) { e.printStackTrace(); } }
然而,当登录用户成功后,再进行退出系统操作,会发生java.io.EOFException:
定位到提示错误的代码行,发现这个错误其实是在说明客户端监听服务器端Message的线程依然在进行中:
public class ClientConnectServerThread extends Thread{ private Socket socket;//该线程需要持有Socket public ClientConnectServerThread(Socket socket) { this.socket = socket; } @Override public void run() { while (true) { try { ObjectInputStream ois = new ObjectInputStream(socket.getInputStream()); //报错的代码行 Message ms = (Message) ois.readObject();
解决方法:
服务器端在接收到客户端发来的退出系统消息后,向客户端发出回应,客户端监听到服务器端发来的回应后,立马取消监听。
服务器端:收到客户端退出系统消息后,向客户端回应
..................... } else if (message.getMesType().equals(MessageType.MESSAGE_CLEAR_EXIT)) { // 客户端要退出系统 // 解决方案============== Message message2 = new Message(); //设置当前message1是一条返回用户列表信息的信息对象 message2.setMesType(MessageType.MESSAGE_CLEAR_EXIT); message2.setGetter(message.getSender()); // 将message对象返回给客户端 ObjectOutputStream oos1 = new ObjectOutputStream(socket.getOutputStream()); oos1.writeObject(message2); // ========================= ManageClientThreads.removeClientThread(userId); // 释放服务器线程库资源 socket.close(); // 关闭连接 break; // 退出线程 } else { ..........
客户端:很简单,break,结束监听进程
else if (ms.getMesType().equals(MessageType.MESSAGE_CLEAR_EXIT)) { // ManageClientConnectServerThread.removeThreadSource(ms.getGetter()); // socket.close(); break; }
客户端完整的监听服务器端的代码:
public class ClientConnectServerThread extends Thread{ private Socket socket;//该线程需要持有Socket public ClientConnectServerThread(Socket socket) { //构造器 this.socket = socket; } @Override public void run() { while (true) {// 线程需要不停地监听服务器是否发送了Message try { ObjectInputStream ois = new ObjectInputStream(socket.getInputStream()); Message ms = (Message) ois.readObject();// 如果服务器没有发送Message对象,线程会阻塞在这里 // 根据服务器返回message对象的类型,进行相应的处理 if (ms.getMesType().equals(MessageType.MESSAGE_RET_ONLINE_FRIEND)) { String[] mesArray = ms.getComment().split(" "); // 服务器端每一条数据后,都用空格符进行区分 for (String s : mesArray) { System.out.println(s); } } else if (ms.getMesType().equals(MessageType.MESSAGE_CLEAR_EXIT)) { // ManageClientConnectServerThread.removeThreadSource(ms.getGetter()); // socket.close(); break; } else { System.out.println("其他消息暂时不处理!"); } } catch (Exception e) { e.printStackTrace(); } } } public Socket getSocket(){ return socket; } }