Java-Day-31
多用户即时通信系统
无异常退出
-
问题指出:
- 客户端输入 9 退出的是输出在控制台的主线程,退出的是主菜单,并没有真正的退出
- 因为客户端启动后,相当于是开启了一个进程,在这个进程中启动了一个主线程 ( main 线程 ),在 main 主线程中又启动了一个客户端的线程 ( ClientConnectServerThread,即和服务端通信的线程 ),此线程 run 方法是在不断循环的
- 所以在输入 9 退出了 main 主线程,那个不断循环的 ClientConnectServerThread 并没有退出
-
解决方法之一:
-
客户端:
- 在 main 线程调用方法,给服务器端发送一个退出系统的 message
- 调用 System.exit(0) // 正常退出,直接关闭掉进程,从而此进程下的所有的线程就都结束了
-
服务端器:
- 服务器端和某个客户端通信的线程接收到一个退出系统的 message
- 把这个线程持有的 socket 关闭
- 退出该线程的 run 方法 ( 退出 while 循环 ),就相当于退出了这个线程
-
-
具体解决实现:
- 在客户端的 UserClientService 里编写发送退出 message 的方法
- 最好在获取输出流对象的时候,是从集合中拿到线程 —— 用户 id 得到所属 socket 的线程来获取:
ObjectOutputStream oos = new ObjectOutputStream(ManageClientConnectServerThread.getClientConnectServerThread(u.getUserId()).getSocket().getOutputStream());
- 注意要传对 message 的 type,确保是放进了 setMesType 中
- 最好在获取输出流对象的时候,是从集合中拿到线程 —— 用户 id 得到所属 socket 的线程来获取:
- 服务端的 ManageClientThreads 中编写移除对应 userId 的线程对象的方法,在 ServerConnectClientThread 中调用此方法,并关闭此与用户连接的 socket,break 退出循环
- 退出 run 方法,即退出所在的线程
- 在客户端的 UserClientService 里编写发送退出 message 的方法
私聊功能
- 思路:
- 客户端处,接收用户希望给其他用户聊天的内容,将消息构建成 Message 对象,通过对应 socket 发送给服务器
- 服务器处,读取想私聊发送的信息,在管理线程的集合中,根据 message 的私聊信息接收者的 id,从而找到对应线程的 socket,然后将 message 对象转发给指定的客户
- 指定的客户端处,读取 message 消息并显示
- 客户端 ( 发送方 ):
- 控制台输入接收方 id 和想发送的信息
- 为更好区分,新建 MessageOtherClientService 用于编写发送消息的方法,即私聊 / 群聊所用
- 方法里仍旧在新建存放完 message 后,为发送给服务端,通过用户 id,在集合中找到线程找到 socket 的输出流对象
- 服务端:
- serverConnectClientTreads 线程类中,接收如果是普通的信息发送,就根据接收方的 id 得到线程、socket、输出流对象
- 客户端 ( 接收方 ):
- UserClientService 判断如果是普通消息的发送,就直接拼接 message 的各个所需属性为字符串加以显示在控制台上
群聊
-
同私聊的区别就是群聊不是指定对象发送,是直接遍历所有的在线线程
-
服务端:需要遍历的时候就 get 方法拿到集合中的 HashMap,获取 key 遍历发送 message
-
客户端:ClientConnectServerThread 线程随时 run 接收群发 Type,直接控制台输出 message 即可