Skip to content

多用户通信系统,练习项目框架设计、多线程、网络编程、IO流;offline分支为服务端,offline_client分支为客户端。

Notifications You must be signed in to change notification settings

zhangyuian/Multi-user-Communication

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

多用户即时通信系统

为什么选择这个项目

  1. 有趣
  2. 涉及到java各个方面的技术
  • 项目框架设计
  • java面向对象
  • 网络编程
  • 多线程
  • IO流
  • Mysql / 使用集合充当内存数据库
  1. 巩固旧知识,学习新知识

弱化界面,因为界面会耗费很多时间,只需要掌握核心知识点即可

项目开发流程

  1. 需求分析: 1)需求分析师:懂技术+行业 2)出一个需求分析报告(白皮书),该项目功能,客户具体要求
  2. 设计阶段 1)架构师/项目经理 2)设计工作(UML类图,流程图,模块设计,数据库,架构) 3)原型开发 4)组建团队
  3. 实现阶段 1)程序员/码农 2)完成架构师的模块功能 3)测试自己模块
  4. 测试阶段 1)测试工程师 2)单元测试,测试用例,白盒测试、黑盒测试、集成测试
  5. 实施阶段 1)实施工程师(开发能力/环境配置部署能力) 2)项目正确的部署到客户的平台,并保证运行正常 3)身体要好(经常出差)
  6. 维护阶段: 1)发现bug解决/项目升级

国内开发一般实现阶段会比较长,因为国内喜欢一边设计,一边开发

需求分析

  1. 用户登录
  2. 拉取在线用户列表
  3. 无异常退出(客户端、服务端)
  4. 私聊
  5. 群聊
  6. 发文件
  7. 服务器推送新闻

功能实现-用户登录

1. 功能说明:

因为还没有学习数据库,我们人为规定用户名/id = 100,密码123456就可以登录,其它用户不能登录
后面使用HashMap模拟数据库,可以多个用户登录

2. 思路分析+程序框架图

image.png 分析:

  • 服务器端:
  1. 当有客户端连接到服务器后,会得到一个socket
  2. 启动一个线程,该线程持有该socket对象,也就是说socket是该线程的属性
  3. 为了更好的管理线程,需要使用集合hm来管理
  • 客户端
  1. 和服务器端通信时,使用对象方式,可以使用对象流来读写
  2. 当客户端连接到服务端后,也会得到socket
  3. 启动一个线程,该线程持有socket
  4. 为了更好管理线程,也将该线程放入到集合

使用 Message 对象流的方式来进行通信,方便后面的拓展

3. 代码实现

功能实现-拉取在线用户列表、无异常退出

拉取在线用户列表

思路分析:

  1. 客户端通过Message消息向服务端请求在线用户列表
  2. 服务端通过Message返回在线用户列表

无异常退出

思路分析:

  • 客户端
  1. 客户端因为启动了接受消息的线程,因此在main线程退出之后,进程并不会结束
  2. 需要在退出系统选项处添加 System.exit(0)
  3. 另外在退出之前,需要向服务端发送一个断开连接的 Message
  • 服务端
  1. 服务端在接受到客户端的 Message 关闭该线程

功能实现-私聊

思路分析:

  • 客户端:
  1. 接收用户希望给某个其它在线用户聊天的内容
  2. 将消息构建成 Message 对象,通过对应的 socket 发送给服务器
  3. 在他的线程(通信线程中),读取到发送的Message 消息,并显示即可
  • 服务端:
  1. 可以读取到客户端发送给某个客户的消息
  2. 从管理线程的集合中,根据 message 对象的 getterid 获取到对应线程的 socket
  3. 然后将 message 对象转发给指定客户

功能实现-群聊

和私聊差不多,只不过将Message 转给所有的线程而不是一个线程

功能说明-发文件

功能说明:

  1. 发送给哪个用户
  2. 指定发送文件的路径
  3. 指定对方接受文件的路径

思路分析:

  • 客户端:
  1. 先把文件 a.jpg 读取到客户端,字节数组
  2. 把文件对应的字节数组封装到 message 对象 [包含文件内容,sender,getter]
  3. 将 message 对象发送给服务端
  4. 在接收到包含有文件的消息后,就将该文件保存到磁盘
  • 服务端
  1. 接收到 message 对象
  2. 拆解 message 对象的 getterid,获取该用户的通信线程
  3. 把 message 对象转发给指定用户
  • 课后作业:让接收的用户指定保存的路径 思路1:
  1. 客户端接收到文件流之后指定保存位置。 这种思路有问题,因为会导致两个线程抢占控制台输入资源,导致不能从控制台输入文件存储路径

只是将普通的 Message 进行了拓展

功能实现-服务器推送新闻

功能说明 服务器可以推送消息给所有人

思路说明:

  • 服务端
  1. 推送消息/新闻,本质其实就是群发消息
  2. 在服务器启动一条独立线程,专门负责发送推送新闻

拓展功能-离线留言和离线发文件

在实际工作中,独立解决问题的能力非常重要,必须有意识培养

  1. 实现离线留言,如果某个用户没有在线,
  2. 实现离线发文件,如果某个用户没有在线,当登录后,可以接受离线的文件

思路:

  • 服务端:离线发消息
  1. 当有客户发送消息/文件,如果用户不在线
  2. 把message存放到服务的 db [ConcurrentHashMap]
  3. key -> getterid value -> ArrayList, ArrayList 存放 message
  4. 当用户登录后,到服务端 db 去查找,如果有 getter = userid,就取出 ArrayList 的 Message 对象,发送给对应客户端即可

重写该项目的感悟

  1. 整体的框架是最难想的

  2. 处理流 ObjectOutputStream 不能随意关闭,因为关闭了处理流会导致内部的节点流也关闭,socket 也会被关闭,会和客户端断开连接

  3. 客户端和服务端的包名不一样,会导致使用对象流的时候出现classNotFoundException

  4. 在线用户列表是使用string来传输,中间用空格隔开,传输到客户端后再用split分离

  5. 客户端和服务端的联调比较困难,产生的bug比较难找

各需求分析

image.png

1. 登录

  • 客户端:
  1. QQView 作为主线程接受用户的输入
  2. 在登录成功后启动一个线程接收服务端传递的消息
  3. 客户端这里是由两个线程在运行,一个接受用户的操作指令,执行命令,另外一个是接收消息
  • 服务端
  1. 服务端线程 QQService 监听端口
  2. 如果有客户端连接,则建立一个线程保持通信,该线程接收来自客户端的请求,并处理该请求

2. 拉取在线用户列表

  • 客户端:
  1. QQView 向服务端发送请求,要求返回在线用户列表
  2. 另一个线程接收服务端返回的信息
  • 服务端
  1. 服务端接收到客户端的请求
  2. 返回在线用户列表 1)创建管理线程的类,每次与客户端建立连接,则将连接线程放入该类的一个 ConcurrentHashMap 成员中,作为在线用户集合 2)用户发送请求的时候,取出在线用户集合的userId,通过空格连接成 String 类型,发送给客户端(客户端通过split空格解析)

3. 无异常退出(退出登录)

  • 客户端:
  1. 客户端在退出时发送消息告知服务端,需要退出登录
  2. 客户端调用 System.exit(0) 关闭程序
  • 服务端:
  1. 服务端接受到客户端的退出登录请求后,将该用户从在线用户集合 ConcurrentHashMap 成员中移除
  2. 并调用 socket.close() 关闭连接,然后结束该线程

4. 私聊

  • 客户端
  1. 客户端发送消息给服务端,消息中带上 getter
  • 服务端
  1. 服务端接受到消息,通过消息中的 getter 找到对应的连接线程,将消息转发

5. 群聊

  • 客户端
  1. 客户端发送消息给服务端
  • 服务端
  1. 服务端接受到消息,遍历所有在线用户,转发消息

6. 发文件

  • 客户端
  1. 客户端将文件读入到内存中,在消息中设置byte[]数组,将文件流放入byte[]数组中
  2. 将消息发送给服务端
  • 服务端
  1. 服务端接收到来自客户端的消息,将消息转发

About

多用户通信系统,练习项目框架设计、多线程、网络编程、IO流;offline分支为服务端,offline_client分支为客户端。

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages