Java-Day-32( 多用户即时通信系统 —— 文件传输 + 服务器推送新闻 + 离线留言 )

发布时间 2023-07-16 17:59:26作者: 朱呀朱~

Java-Day-32

多用户即时通信系统

文件传输

  • 思路:
    • 客户端里先把文件读取到客户端为字节数组,把文件对应的字节数组封装到 message 对象,内含文件内容、sender、getter,将 message 对象发送给服务端
    • 拆解 message 对象获取 getterid,获取客户端被指定的接收用户的通信线程,把 message 转发给此指定用户
    • 负责接收的客户端获取包含有文件的消息后,将该文件保存到磁盘
  • 客户端 ( 发送方 ):
    • 新建 FileClientService 类用于存放和编写文件相关的服务方法
    • 类中编写方法,存放文件、发送路径、发送者与接收者的 id,要用文件输入流 + 字节数组,将文件存到字节数组中,再将数组存放到 message 中,关闭文件输入流 FileInputStream
    • 最后对象输出流 ObjectOutputStream 将 message 发送给服务端
      • 注意,ObjectOutputStream 不需要关闭流
  • 服务端:
    • ServerConnectClientThread 内 if 语句判断接收 type,如果是文件传输,那就通过 getGetter 获取接收方 socket 的 输出流,发送 message
  • 客户端 ( 接收方 ):
    • ClientConnectServerThread 内 if 语句判断,如果是文件传输,就用文件输出流 FileOutputStream 写入磁盘输出路径,再用 write 方法写读取文件字节数组即可
    • 客户端的控制台显示处不要忘了在正确的 case 处接收键盘输入和调用文件发送的方法

服务器推送新闻

  • 思路:
    • 功能本质就相当于是群发消息
  • 客户端:
    • 可以直接借用群发消息的处理方法
  • 服务端:
    • 新建 SendNewsToAllService 类作为一个线程
    • run 方法直接接收键盘输入,直接设定存储信息类型为群发信息的类型
    • 集合中获取所有在线用户,while 循环获取每一个在线用户的 socket 获取输出流对象于对象输出流
      • 集合.keySet().iterator 迭代器 while 循环 hasNext 遍历,.next 获取所有的用户
    • writeObject ( message )

离线留言

  • 正常发送,在服务端进行方法的编写时,判断如果在线用户的列表里有接收方时才做正常的操作

    • 发现会不太可行
  • 思路:

    • 新开一个集合 ConcurrentHashMap 存放离线 message:getterid:ArrayList< Message >
    • 服务端:
      • 当有客户发送消息或文件,如果用户不在线,就把 message 存放到服务的 db[CHM]
      • key —> getterid,value —> ArrayList,ArrayList 存放 message
      • 当用户登录后,到服务端 db 去查找,如果有 getter=userid,就取出 ArrayList 的 message对象,发送给对应客户端即可
      • 勿忘发送后 remove 离线转上线的用户 id
  • 服务端:

    • 普通信息发送的基础上,判断是否在线,不在线就存储离线线程 ManageOffClientThread 中 ( 内含接收者名为 key,传来的 message 集合为 value )

    • 离线线程里,判断是否存在此 key,若不存在就新建 List 存储,如果存在就 get 获取此 key 下的 List,在其基础上进行新的增加,然后再加入 HashMap 中

    • 注意以下语句是错的,因为第一次存储 iterator 始终都是空的,所以根本不会到 if 判断语句中,更别谈第一次存储了

      while (iterator.hasNext()) {
          String s = iterator.next();
          if (s.equals(userId)) { // hm.get(userId)
          } else {  // new ArrayList<>()  }
      
    • 所以第一次要使用 map 的 containsKey (key1) 方法判断 key1 是否存在,不存在就 new,存在就 get (key2) 获取信息 list.add 进行离线信息的增加与 map.put 的更新

    • 在用户登录成功后调用方法,判断该用户在离线线程集合中是否存在同 key,存在就获取此用户在集合中的离线信息集合,在迭代器循环获取离线信息 List 里的值,拼接所有信息,再携带离线 type 输出流发送给此已经上线的用户,并 remove 此用户的所有离线信息

  • 客户端:

    • 似普通信息的发送,接收为离线消息的 type,String 数组 split 分割后循环显示即可