day03-拉取在线用户功能

多用户即时通讯系统03

4.编码实现02

4.2功能实现-拉取在线用户

day03-拉取在线用户功能day03-拉取在线用户功能

4.2.1思路分析

客户端想要知道在线用户列表,就要向服务器发送请求(Message),因为只有服务器端保持着所有与客户端相连接的socket和uid信息。

整个流程大致为:对Message的种类进行扩展,然后客户端向服务器发送一个Message,服务端向客户端返回数据,客户端接收信息(Message),在接收的这个Message信息里面包含了在线的用户列表。

4.2.2代码实现

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

拓展了一些Message消息类型

package qqcommon;

/**
 * @author 李
 * @version 1.0
 * 表示消息类型
 */
public interface MessageType {
    //在接口中定义类一些常量,不同的常量的表示不同的消息类型
    String MESSAGE_LOGIN_SUCCEED = "1";//表示登录成功
    String MESSAGE_LOGIN_FAIL = "2";//表示登录失败
    String MESSAGE_COMM_MES = "3";//表示普通信息包
    String MESSAGE_GET_ONLINE_FRIEND = "4";//要求返回在线用户列表
    String MESSAGE_RET_ONLINE_FRIEND = "5";//返回的在线用户列表
    String MESSAGE_CLIENT_EXIT = "6";//客户端请求退出

}
2.修改:UserClientService类

在该类中添加onlineFriendList()方法,该方法向服务器发送要求,请求在线用户列表

    //先服务器端请求在线用户列表
    public void onlineFriendList() {
        //向服务器发送一个Message,类型MESSAGE_GET_ONLINE_FRIEND,要求返回在线用户列表
        Message message = new Message();
        message.setMesType(MessageType.MESSAGE_GET_ONLINE_FRIEND);
         message.setSender(u.getUserId());

        //发送给服务器
        try {
            //从管理线程的集合里面,通过userId,得到这个线程对象
            ClientConnectServerThread clientConnectServerThread =
                    ManageClientConnectServerThread.getClientConnectServerThread(u.getUserId());
            //通过这个线程中获取关联的socket
            Socket socket = clientConnectServerThread.getSocket();
            //得到当前线程的Socket对应的ObjectOutputStream对象
            ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
            oos.writeObject(message);//发送一个Message对象向服务器,要求在线用户列表
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
3.修改:ClientConnectServerThread类

在该类中的run方法中,增加判断Message的类型,然后做相应的业务处理

@Override
public void run() {
    //因为Thread需要在后台和服务器通信,因此我们使用while循环
    while (true) {
        try {
            System.out.println("客户端线程,等待读取从服务端发送的消息");
            ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());

            //如果服务器没有发送Message对象,线程会阻塞在这里
            Message message = (Message) ois.readObject();

            //判断Message的类型,然后做相应的业务处理
            //如果读取到的是 服务端返回的在线用户列表(MESSAGE_RET_ONLINE_FRIEND)
            if (message.getMesType().equals(MessageType.MESSAGE_RET_ONLINE_FRIEND)) {
                //取出在线用户列表信息,并展示
                //这里假定返回的用户列表是用空格隔开的id名(如:100 200 紫霞仙子 至尊宝 唐僧)
                String[] onlineUsers = message.getContent().split(" ");
                System.out.println("\n=======当前在线用户列表=======");
                for (int i = 0; i < onlineUsers.length; i++) {
                    System.out.println("用户:" + onlineUsers[i]);
                }

            } else {
                System.out.println("读取到的是其他类型的message,暂时不处理");
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
4.修改QQView类

修改该类中的第54行

使用上述编写的方法,完成拉取在线用户列表的操作

//这里写一个拉取用户在线列表的方法
userClientService.onlineFriendList();

day03-拉取在线用户功能
2.服务端

大致思路为:前面我们在服务端的线程的run方法中,使用for循环在不停地请求读取数据,这里我们可以在run方法里面拓展功能,读取客户端发送过来的拉取用户的Message对象,返回在线用户列表

1.修改:MessageType接口

和客户端一样,拓展Message消息类型

package qqcommon;

/**
 * @author 李
 * @version 1.0
 * 表示消息类型
 */
public interface MessageType {
    //在接口中定义类一些常量
    //不同的常量的表示不同的消息类型
    String MESSAGE_LOGIN_SUCCEED = "1";//表示登录成功
    String MESSAGE_LOGIN_FAIL = "2";//表示登录失败
    String MESSAGE_COMM_MES = "3";//表示普通信息包
    String MESSAGE_GET_ONLINE_FRIEND = "4";//要求返回在线用户列表
    String MESSAGE_RET_ONLINE_FRIEND = "5";//返回的在线用户列表
    String MESSAGE_CLIENT_EXIT = "6";//客户端请求退出
}
2.修改:ServerConnectClientThread类

在该类中的run方法添加了客户请求拉取在线用户列表 的业务操作

package qqserver.server;

import qqcommon.Message;
import qqcommon.MessageType;

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;

/**
 * @author 李
 * @version 1.0
 * 该类的一个对象和某个客户端保持通信
 */
public class ServerConnectClientThread extends Thread {
    private Socket socket;
    private String userId;//连接到服务端的用户id

    public ServerConnectClientThread(Socket socket, String userId) {
        this.socket = socket;
        this.userId = userId;
    }

    @Override
    public void run() {//这里线程处于run的状态,可以发送/接收消息

        while (true) {
            try {
                System.out.println("服务端和客户端" + userId + "保持通信,读取数据...");
                ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
                Message message = (Message) ois.readObject();

                //后面会使用message,根据message的类型,做相应的业务处理

                //业务-:客户请求拉取在线用户列表
                if (message.getMesType().equals(MessageType.MESSAGE_GET_ONLINE_FRIEND)) {
                    //客户请求拉取在线用户列表
                    //假定返回的用户列表是用空格隔开的id名(如:100 200 紫霞仙子 至尊宝 唐僧)
                    System.out.println(message.getSender()+" 要在线用户列表");
                    String onlineUser = ManageClientThreads.getOnlineUser();

                    //返回message
                    //构建一个Message对象(这个Message对象包含了在线用户列表信息),返回给客户端
                    Message message2 = new Message();
                    //设置消息类型--返回的在线用户列表类型-客户端会根据返回的消息类型来进行相应的业务处理
                    message2.setMesType(MessageType.MESSAGE_RET_ONLINE_FRIEND);
                    message2.setContent(onlineUser);//返回用户消息列表
                    //服务器发送的消息的接收者Getter 就是服务器接收的信息 的发送者Sender
                    message2.setGetter(message.getSender());

                    //返回给客户端
                    ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
                    oos.writeObject(message2);

                }else{
                    System.out.println("其他类型的message,暂时不处理");
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
3.修改:ManageClientThreads类

在该类中增加了getOnlineUser()方法,用来遍历取出userId,并在上面的ServerConnectClientThread的run方法中使用。

//这里编写方法,可以返回在线用户列表
public static String getOnlineUser() {
    //遍历集合,遍历 hashmap 的 key
    Iterator iterator = hm.keySet().iterator();//获取hm集合的ketSet集合的迭代器(这里的ketSet就是userId)
    String onlineUserList = "";
    while (iterator.hasNext()) {//遍历
        onlineUserList += iterator.next().toString() + " ";//遍历所有的userId,用空格拼接起来
    }
    return onlineUserList;
}

运行:

  1. 运行服务端:

day03-拉取在线用户功能
  1. 分别运行三个客户端,并进行登录,拉取在线用户: ​ 用户1:

day03-拉取在线用户功能 day03-拉取在线用户功能

​ 用户2:

day03-拉取在线用户功能 day03-拉取在线用户功能

​ 用户3:

day03-拉取在线用户功能 day03-拉取在线用户功能

此时服务端显示:

day03-拉取在线用户功能

Original: https://www.cnblogs.com/liyuelian/p/16720760.html
Author: 一刀一个小西瓜
Title: day03-拉取在线用户功能

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/598566/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • MySQL 基础

    MySQL 基础 SQL 介绍 SQL (Structured Query Language:结构化查询语言) 是用于管理关系数据库管理系统(RDBMS)。 SQL 的范围包括数据…

    数据库 2023年5月24日
    093
  • Vue 2.0 基础

    知识点 1.是一个MVVM框架 由MVC架构衍生,分为View(视图层)、ViewModel(数据视图层)、Model(数据层),MVVM 最标志性的特性就是 数据绑定,实现数据驱…

    数据库 2023年6月11日
    0105
  • 深入浅出的分析 Properties

    作者:炸鸡可乐原文出处:www.pzblog.cn 一、摘要 在集合系列的第一章,咱们了解到,Map 的实现类有 HashMap、LinkedHashMap、TreeMap、Ide…

    数据库 2023年6月14日
    079
  • 电脑卡.磁盘占用100% .解惑找不到Superfetch等服务问题

    公司电脑没有固态。磁盘io比较慢. 经常打满100% *1. 打开任务管理器发现是 一个叫system和DCFWinService的服务一直在占用磁盘读写 2. 解决方向. 禁用掉…

    数据库 2023年6月14日
    0692
  • 计算字符串中连续出现最多的字符串和长度

    public static void main(String[] args) { // 定义的字符&#x4E3…

    数据库 2023年6月11日
    099
  • 第十六章:接口

    本篇翻译自《Practical Go Lessons》 Chapter 16: Interfaces 1 你将在本章学到什么? 什么是类型接口? 如何定义接口。 “实现…

    数据库 2023年6月6日
    0102
  • 毫秒级!千万人脸库快速比对,上亿商品图片检索,背后的极速检索用了什么神器? ⛵

    💡 作者:韩信子@ShowMeAI📘 机器学习实战系列:https://www.showmeai.tech/tutorials/41📘 深度学习实战系列:https://www.s…

    数据库 2023年6月14日
    083
  • Mysql查询优化

    mysq查询l优化 指标:执行时间 检查的行数 返回的行数 explain关键字 — 实际SQL,查找用户名为Jefabc的员工 select * from emp where …

    数据库 2023年5月24日
    0119
  • 一张图弄懂sql的连接查询

    无意中看到一张图,非常直观的表现出了sql连接查询的结果集,对连接查询的理解十分有帮助,所以收藏了下来。 其中红色部分为可以查询出的数据,白色部分为不能查询出的数据 Origina…

    数据库 2023年6月14日
    0107
  • mac(m1)配置my.cnf

    今天开始学习了数据库,在安装MySQL之后启动一直报错,然后在网上找了很多解决方法,最后用以下方法解决 对于习惯了windows的小伙伴来说,直接去安装目录里边修改my.ini就可…

    数据库 2023年5月24日
    0105
  • SQLZOO练习7–Using NULL

    teacher表: iddeptnamephonemobile 101 1 Shrivell 2753 07986 555 1234 102 1 Throd 2754 07122 …

    数据库 2023年5月24日
    077
  • mysql的安装和下载

    1、 MySQL 下载地址为: MySQL 下载,这里下载的是mysql的msi安装文件,选择下面的470.2M的版本,点击download进行下载。 2、在下载页面直接选择: N…

    数据库 2023年5月24日
    096
  • Typora加七牛云实现实时图片自动上传

    Typora加七牛云实现实时图片自动上传 前言: ​ Typora是一款轻便简洁的Markdown编辑器,支持即时渲染技术,这也是与其他Markdown编辑器最显著的区别.重点是免…

    数据库 2023年6月9日
    0196
  • Kubeadm部署K8S(kubernetes)集群(测试、学习环境)-单主双从

    1. kubernetes介绍 1.1 kubernetes简介 kubernetes的本质是一组服务器集群,它可以在集群的每个节点上运行特定的程序,来对节点中的容器进行管理。目的…

    数据库 2023年6月9日
    087
  • 2022-8-23 css

    ✏️CSS 一个标签可以有多个css样式浏览器处理冲突的能力,如果一个属性通过两个相同的选择器设置到这个元素上,会根据样式的层叠规则样式的层叠规则——按照样式的声明顺序来层叠的【就…

    数据库 2023年6月14日
    073
  • Java8日期时间(LocalDate、LocalTime、LocalDateTime)

    在看题的时候发现了Java8中新加入的日期时间类,觉得这个小哥写的不错,自己也跟着练习下。原文地址:https://blog.csdn.net/yy139926/article/d…

    数据库 2023年6月14日
    083
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球