首页 > 编程语言 >Java-Day-30( 多用户即时通信系统 —— 登录 + 获取在线用户列表 )

Java-Day-30( 多用户即时通信系统 —— 登录 + 获取在线用户列表 )

时间:2023-07-10 22:13:24浏览次数:43  
标签:Java socket 登录 30 用户 线程 Day 服务端 客户端

Java-Day-30

多用户即时通信系统

  • 需求分析
    • 用户登录
    • 拉取在线用户列表
    • 无异常退出
    • 私聊
    • 群聊
    • 发文件
    • 服务器推送新闻

用户登录

  • 功能说明

    • 我们暂时人为规定用户名 / id = 100,密码 123456 就可以登录,其他用户不能登录
    • 后面使用 HashMap 模拟数据库,可以多个用户登录
  • 思路分析

    • 为方便,客户端 A 的 socket 输出流发送数据时使用对象方式 ( 即使用对象流来读写 ) ,由服务端的 9999 端口监听,监听 accept 产生一个输入流 socket
      • 一个对象希望用 Object 对象流的方式进行读写的话,此对象所对应的类需要序列化 —— implements Serializable ( IO 流部分 ),并且为保证兼容性需要加上 —— private static final long serialVersionUID = 1L; —— 防止在随机分配时,若类修改,反序列化报错
    • 如果多个客户端访问的话,服务器端就产生多个 socket
      • 服务器端验证 User 对象,验证通过后才能到后面的发送信息等功能
    • 每获取一个 socket 就多一个线程,一个线程包裹着一个 socket,也可以说 socket 就是该线程的属性,只一个 socket 不方便维护
    • 为更好的管理线程,两端都需要使用集合,即多个线程都包裹在一个管理线程的集合中 ( 为了扩展,就算是只有一个 socket 也最好写到线程集合中 )
    • 每对 socket 对应一个通道 ( 两端之间也可能有多条通道 )

image-20230610210633741

  • 注意:客户端的线程中只有 socket,而服务端的线程中不仅要有 socket,还要有用于区分的客户端传来的身份验证的 userId

前提准备

  • 服务端和客户端都共有文件:Message、User 映射实体类,MessageType 内含各种信息类型的常量的接口

    • 信息 Message 包含所有发送的东西,例如客户向服务器发送请求类型是存在 Message 里,服务端将客户请求到的信息也存到 Message 中,即凡是要两端信息交互,就是通过 Message 来存储发送的

    • 接口中:

      //    在接口中定义了一些常量
      //    不同的常量的值,表示不同的消息类型
          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"; // 客户端请求退出
      

用户登录 —— 客户端

  • 为了用户信息可发送到服务端
    • QQView 为登录页面简单样式
    • UserClientService 为用户登录验证、用户注册等具体方法所在处
      • 如果登录成功,就将 socket 存入线程,线程启动并存入线程集合,关于线程与集合的具体如下
    • ClientConnectServerThread 为一个持有 Socket 的线程,始终保持着与服务端的连接,时刻处于可接收状态
      • 为了能够管理 socket,否则客户端多个 socket 时会很麻烦,而且只能做一件事情
      • 减缓了反复链接的延迟和资源浪费等
    • ManageClientConnectServerThread 类中,我们将线程放入到集合管理 ( 如上图所画 )
      • 主要是为了后面客户端的扩展,如果以后和服务端只会有一个连接的话,此处就不需要集合管理了
      • 内就仅含一个 HashMap、一个 ( id, 线程 ) 存放方法、一个根据 id 获取线程的方法

用户登录 —— 服务端

  • 为了验证客户端发来的信息,随后服务端发送信息对象给用户以登录结果
    • QQServer 中用 ServerSocket 来监听端口并获取 Socket
      • 端口可以写在配置文件中
      • 注意:监听也同样是一个循环不断的操作,并不是获取到一个 Socket 就结束了
    • 获取输入流得到客户端发送的 User 对象进行验证
    • 再根据 Socket 创建输出流,用来根据验证结果发送 Message 对象给客户端进行回复
    • 登录成功就将 socket 存入线程,线程启动并存入线程集合,关于线程与集合的具体如下
  • ServerConnectClientThread 似过程一的 ClientConnectServerThread 持有 socket 的线程,用于始终和对应用户保持连接
  • ManageClientThreads 管理线程类,似过程一的 ManageClientConnectServerThread
  • 若是没链接数据库想要临时测试,可以在 QQServer 中使用 HashMap / ConcurrentHashMap 集合于静态代码块中存储用户信息

拉取在线用户列表

  • 不管是客户端还是服务端都是有一个线程在不停执行 run 方法,在此方法中,不断接收对方的 Message 对象,根据传来的 Message 对象的类型来执行进一步的操作

  • 在客户端的 UserClientService 中编写向服务端请求在线用户列表的方法,在需要时 QQView 在合适的位置调用即可

  • 在 ClientConnectServerThread 线程中判断服务端发送回来的信息类型,若接收到的是服务端发来的用户列表,就在线程中直接控制台打印出用户列表即可,在需要时直接在 QQView 页面调用即可

    • split 分割为数组,循环输出
  • 服务端获取在线用户列表:所有在线的用户 id 都存放在 socket 中,socket 都包在一个线程中,而每个线程都在一个线程集合中,所以想要获取所有的在线用户,就需要通过管理线程的集合来获取,即在 ManageClientThreads 里编写获取列表的方法

    • HashMap 的遍历,可以用迭代器,
  • 服务端的线程中判断客户传来的 Message 类型,若是,就通过线程集合的方法获取所有的用户信息,拿到后将所需的类型、发送者、内容 ( 即用户信息 ) 等打包,输出流返回给客户端即可

标签:Java,socket,登录,30,用户,线程,Day,服务端,客户端
From: https://www.cnblogs.com/zhu-ya-zhu/p/17542464.html

相关文章

  • Java-Day-31( 多用户即时通信系统 —— 无异常退出 + 私聊 + 群发 )
    Java-Day-31多用户即时通信系统无异常退出问题指出:客户端输入9退出的是输出在控制台的主线程,退出的是主菜单,并没有真正的退出因为客户端启动后,相当于是开启了一个进程,在这个进程中启动了一个主线程(main线程),在main主线程中又启动了一个客户端的线程(ClientConn......
  • Java-第一天(初始java)
    在正式学习Java之前,我们可以简单了解下Java进程......也可忽略喔一、Java发展历史Java是世界上使用最广泛的编程语言之一。Java最初由SunMicrosystems在1990年代开发,用于开发从Web应用程序到移动应用程序到批处理应用程序的所有内容。Java最初是一种纯粹的面向对象的语言,但现在......
  • 闲话 Day16
    这几天天气真好啊。HE这地方居然可以热成这样,属实长见识了。那么,南方那边是不是年年夏天都这么热呢。由于学OI之后体质变化比较大,所以现在主要是怕冷不怕热。然而这并不代表我可以承受比体温还高的气温。如果南方的天气一直都像这样的话,那我大学去哪里上可能还有待商榷了......
  • ssm框架使springmvc放行资源(java配置类)
    在springmvc中,如果配置了拦截所有请求交给springmvc处理,会出现一些静态web资源加载不出来的情况,或者想放行指定web资源可以通过修改通过修改配置达到相应目的,这里使用覆写WebMvcConfigurationSupport中的方法作介绍。@ConfigurationpublicclassSpringMvcSupportextendsWeb......
  • 20230710-20230711 数论
    数论被薄纱了/kk授课老师:南京大学-朱富海教授20230710裴蜀定理对于给定不全为零的整数的\(a,b\)一定存在一对整数\(x,y\)满足\(ax+by=gcd(a,b)\)。证明:\(a==0\)\(or\)\(b==0\)显然成立;设\(gcd(a,b)=d\),即求证存在\(x,y\)满足\(ax+by=d\),等式两边同时除......
  • 算法细节系列(1):Java swap
    算法细节系列(1):Javaswap问题在C++中,swap算法可以用指针来实现,因此在Java中,如果采用如下代码来对两个数字进行交换时,也不会影响两个对象的值。publicclassTestSwap{publicstaticvoidmain(String[]args){inta=2;intb=3;System.out.prin......
  • Java图片加水印
    分为文字水印和透明图片水印packagecom.qms.report.util;importjavax.imageio.ImageIO;importjava.awt.*;importjava.awt.image.BufferedImage;importjava.io.File;importjava.io.IOException;publicclassImageWatermark{/***@paramwaterMarkType......
  • Atcoder ABC308H Make Q
    考虑枚举唯一一个度数为\(3\)的点\(u\),即既在环上又与非环上一点相连的那个点。接下来考虑先处理环,那可以先把\(u\)从图上删掉,环的最短距离便是与\(u\)有连边的\(2\)个点在图上最短路长度加上\(2\)个点与\(u\)连边的长度,即\(\min\{w_{u,i}+w_{u,j}+\operator......
  • 每日汇报 第三周第二天 JAVA中的异常处理
    今日所学:掌握什么是异常;区分运行时异常和非运行时异常;掌握try、catch、finally后面代码块发挥的作用;掌握运用try-catch-finally捕获异常;掌握如何运用throws关键字在方法上抛出异常;掌握使用throw关键字为异常创建对象,进而主动印发某种异常明日计划:JAVA中的枚举与泛型......
  • 20230710巴蜀暑期集训测试总结
    T1打个不太暴的暴力但是爆了。只对了subtask1,不清楚发生了什么。先建出Kruscal重构树,对每个询问二分答案,判断就用暴力启发式合并T2打了一个\(20pts\)dp。第一步没有想到,每怎么见过这种题。将问题转化为满足\(\foralli,x_i\leA_i,x_i\leB_i\)的序列\(x\)个数。枚......