• day04-1群聊功能


    多用户即时通讯系统04

    4.编码实现03

    4.5功能实现-群聊功能实现

    4.5.1思路分析

    群聊的实现思路和私聊的实现非常类似。

    不同的是:私聊时,服务端接收到消息后,只需要找出接收方的socket并发送消息即可

    群聊时,服务端在接收到消息后需要遍历集合中所有的线程,找出除了发送方的所有客户端的socket,并发送消息

    群聊思路:

    • 客户端 - 发送者:
      • 用户在控制台输入信息,客户端接收内容
      • 将消息构建成Messgae对象,通过对应的socket发送给服务器
    • 服务器:
      • 读取客户端(发送者)发送给所有用户(接收者)的消息
      • 从管理线程的集合中,遍历所有线程,获取所有socket(除了发送者本身)
      • 将Message对象转发给所有的接收者
    • 客户端 - 所有接收者:
      • 所有接受者分别在线程(通信线程)中,读取到发送者的message消息,并显示即可

    4.5.2代码实现

    1.客户端:
    1.修改MessageType接口

    在接口中增加新的消息类型

    String MESSAGE_TO_ALL_MES = "7";//表示群发消息包
    2.修改MessageClientService类

    在该类中增加sendMessageToAll方法,实现群发功能

    /**
    * 群发消息功能
    * @param content 内容
    * @param senderId 发送者
    */
    public void sendMessageToAll(String content,String senderId){
    //构建 message
    Message message = new Message();
    message.setMesType(MessageType.MESSAGE_TO_ALL_MES);//设置消息类型是群发消息
    message.setSender(senderId);
    message.setContent(content);
    message.setSendTime(new Date().toString());//发送时间也封装到 message对象中
    System.out.println(senderId + " 对大家说 " + content);
    //发送给服务端
    try {//在管理线程的集合中,通过userId来获取线程,通过线程来获取对应的socket,再通过socket获取输出流
    ObjectOutputStream oos =
    new ObjectOutputStream(ManageClientConnectServerThread.getClientConnectServerThread(senderId).getSocket().getOutputStream());
    oos.writeObject(message);
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    3.修改ClientConnectServerThread类

    在该类的run方法中增加新的逻辑业务,增加接收群发消息类型的判断,并在控制台显示

    else if (message.getMesType().equals(MessageType.MESSAGE_TO_ALL_MES)) {
    //接收到的是群发的消息
    //就把服务器转发的消息,显示到控制台即可
    System.out.println("\n" + message.getSendTime() + "\n" + message.getSender()
    + " 对大家说: " + "\n" + message.getContent());
    }

    image-20220923163214511

    4.修改QQView类

    在该类的内层循环中,调用群发功能的方法:

    case "2":
    System.out.println("请输入想对大家说的话");
    String s = Utility.readString(100);
    //调用一个方法,将消息封装成 message对象,发给服务端
    messageClientService.sendMessageToAll(s,userId);
    break;

    image-20220923163420586

    2.服务端:
    1.修改MessageType接口

    在接口中增加新的消息类型

    String MESSAGE_TO_ALL_MES = "7";//表示群发消息包
    2.修改ServerConnectClientThread类

    在该类中增加新的业务逻辑

    else if (message.getMesType().equals(MessageType.MESSAGE_TO_ALL_MES)) {
    //业务四:客户请求群发消息需要遍历管理线程的集合,把所有线程的socket都得到,然后将 message进行转发即可
    //得到hm
    HashMap hm = ManageClientThreads.getHm();
    //遍历
    Iterator iterator = hm.keySet().iterator();
    while (iterator.hasNext()) {
    //取出所有userId
    String onlineUserId = iterator.next().toString();
    //取出除了发送者的所有用户id
    if (!onlineUserId.equals(message.getSender())) {
    //转发message
    //从集合中取出线程,在线程中取出socket,根据socket获得输出流,将socket的输出流转化为对象输出流
    ObjectOutputStream oos =
    new ObjectOutputStream(hm.get(onlineUserId).getSocket().getOutputStream());
    oos.writeObject(message);
    }
    }
    }

    image-20220923163737014

    3.修改ManageClientThreads类

    在该类中增加方法,获取集合

    //返回hashmap
    public static HashMap getHm(){
    return hm;
    }

    运行程序:

    1.运行服务端,进行监听

    image-20220923164142319

    2.运行三个客户端,登录三个用户

    image-20220923164420287

    3.在 用户uid=100 的账号发送群发消息

    image-20220923164716432

    4.其他用户也接收到了消息

    image-20220923165201230 image-20220923165230471

    5.服务器端

    image-20220923165354965

    功能实现完毕

  • 相关阅读:
    使用Docker部署Jenkins
    ArcGIS制作规划图卫星影像地图虚化效果
    WIN11+OPENCV4.8 编译及下载失败处理方法
    C++笔记20•数据结构:哈希(Hash)•
    IntelliJ_IDEA的下载和安装的准备
    语音前处理技术在会议场景中的应用及挑战
    A星寻路优化方案
    红队内网攻防渗透:内网渗透之内网对抗:隧道技术篇&防火墙组策略&ICMP&DNS&SMB协议&出网判断&C2上线&解决方案
    记录一次线下渗透电气照明系统(分析与实战)
    快速构建后台管理系统-RUOYI学习之-VUE
  • 原文地址:https://www.cnblogs.com/liyuelian/p/16723966.html