mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4
1761 字
7 分钟
Linux 网络编程(12):IM 聊天系统——项目分析和架构搭建

IM 聊天系统——项目分析和架构搭建#

本节开始搭建 IM 聊天系统项目,首先分析注册、登录、聊天、添加好友和上下线等基本功能,并划分客户端、服务端、数据库及网络通信模块的职责。

随后通过中介者模式降低 kernel 与具体网络实现之间的耦合,对比单例、工厂和中介者模式各自解决的问题,并使用抽象父类 INet 统一 TCP 与 UDP 网络层接口。

一、IM 聊天系统的基本功能#

主要功能包括:

  • 注册;
  • 登录;
  • 聊天;
  • 添加好友;
  • 上线与下线。

登录成功可以看作用户上线,退出或断开连接则对应下线。

项目整体采用 C/S(Client/Server,客户端/服务端)架构

  • 客户端负责界面展示、收集用户输入、组织请求;
  • 服务端负责接收请求、处理业务、访问数据库并返回结果。

二、客户端与服务端的类职责#

1. 服务端#

模块/类主要职责
数据库类连接数据库、查询、更新、断开连接
kernel处理收到的数据,组织需要发送的数据
中介者类发送数据、转发数据、打开网络、关闭网络
网络类初始化网络、发送数据、接收数据、关闭网络

2. 客户端#

模块/类主要职责
UI 界面类显示界面,采集用户输入的数据
kernel处理收到的数据,组织需要发送的数据
中介者类发送数据、转发数据、打开网络、关闭网络
网络类初始化网络、发送数据、接收数据、关闭网络

客户端与服务端都需要网络类和中介者类,二者的整体结构相近,具体网络行为有所不同。

3. 数据流向#

flowchart LR UI["UI 界面"] -->|"用户输入"| CK["客户端 Kernel"] CK -->|"待发送的数据"| CM["客户端中介者"] CM --> CN["客户端网络类"] CN <-->|"TCP / UDP"| SN["服务端网络类"] SN --> SM["服务端中介者"] SM -->|"转发收到的数据"| SK["服务端 Kernel"] SK <-->|"查询、更新"| DB["数据库类"]

中介者本身通常不负责真正的业务处理和底层网络通信,它负责在 kernel 与网络类之间传递消息:

  • 发送方向:kernel → 中介者 → 网络类
  • 接收方向:网络类 → 中介者 → kernel

三、中介者模式#

1. 为什么引入中介者#

如果 kernel 直接依赖 UDP、TCP 客户端、TCP 服务端等具体网络类,那么网络实现一变化,kernel 也需要跟着修改,类之间会形成较强的耦合。

加入中介者后:

  • kernel 面向中介者接口发送数据;
  • 网络类收到数据后交给中介者;
  • 中介者再把数据转发给 kernel
  • kernel 与具体网络实现不再直接交互。

用租房中介作类比:租客和房东不直接反复沟通,而是让中介在双方之间传递信息。软件中的中介者同样用于集中协调对象之间的交互。

2. 中介者模式解决的问题#

  • 减少对象之间的直接引用;
  • 把复杂的交互关系集中到中介者中;
  • 降低模块耦合;
  • 便于替换底层网络实现;
  • 使客户端与服务端能够复用相似的框架。

四、单例模式、工厂模式、中介者模式比较#

对比项单例模式工厂模式中介者模式
类型创建型模式创建型模式行为型模式
核心问题一个类怎样只保留一个实例对象应由谁、按什么条件创建多个对象之间怎样协作
核心做法隐藏构造,提供唯一访问入口new 和类型选择封装起来让对象通过中介者交互
主要收益避免重复实例,便于共享统一状态调用方不依赖具体创建过程减少对象之间的网状依赖
主要风险容易形成全局状态,测试困难类型过多时工厂层次会膨胀中介者可能承担过多逻辑

1. 三者不是互相替代关系#

  • 单例模式解决“对象有几个”;
  • 工厂模式解决“对象怎么创建”;
  • 中介者模式解决“对象怎么交互”。

2. 选择原则#

  • 只是需要唯一对象:考虑单例;
  • 需要隐藏复杂创建过程或切换实现:考虑工厂;
  • 多个模块彼此直接依赖、交互混乱:考虑中介者;
  • 不要为了“使用设计模式”而使用设计模式,应先判断项目中真正存在的问题。

五、网络层的抽象设计#

程序需要支持 TCP 和 UDP,因此不能把所有网络代码都堆在一个类中。这里设计了一个抽象父类 INet,再由具体网络类继承并实现它。

1. 类层次#

INet(抽象父类)
├── TcpClient
├── TcpServer
└── Udp

父类规定所有网络类共同具有的行为:

  • 初始化网络;
  • 关闭网络;
  • 发送数据;
  • 开始接收数据。

具体子类根据协议和角色实现这些函数。

这种设计利用了多态:上层统一保存 INet*,指针实际指向哪个子类对象,就执行哪个子类实现。以后换协议时,上层调用形式不必跟着改变。

网络层和中介者层还可以单独封装成库,在其他需要网络通信的项目中复用。

2. 为什么 UDP 只有一个类,TCP 却分为两个类#

  • UDP 客户端和服务端的流程基本相同,主要差异是是否绑定本地 IP 和端口;UDP 客户端也可以主动绑定,因此二者可以共用一个 Udp 类。
  • TCP 客户端要主动 connect 服务端;TCP 服务端则要 bindlistenaccept
  • 一个 TCP 服务端可以连接多个客户端:除了监听套接字,还要保存每个已连接客户端对应的套接字,管理方式明显不同。

因此这里把 TCP 拆成 TcpClientTcpServer,而 UDP 只设计一个 Udp 类。

3. 不同网络角色的大致流程#

网络角色主要流程
UDP 客户端加载库、创建套接字、绑定 IP 和端口、发送、接收、关闭套接字、卸载库
UDP 服务端加载库、创建套接字、绑定 IP 和端口、接收、发送、关闭套接字、卸载库
TCP 客户端加载库、创建套接字、连接服务端、发送、接收、关闭套接字、卸载库
TCP 服务端加载库、创建套接字、绑定 IP 和端口、监听、接受连接、接收、发送、关闭套接字、卸载库
分享

如果这篇文章对你有帮助,欢迎分享给更多人!

Linux 网络编程(12):IM 聊天系统——项目分析和架构搭建
https://joyanblog.com/posts/linux-network-programming-12-im-chat-system-analysis-architecture/
作者
Joyan
发布于
2026-07-31
许可协议
CC BY-NC-SA 4.0
相关文章 智能推荐
1
Linux 网络编程(16):IM 聊天系统——中介者类实现与 Qt、VS 通信
Linux 网络编程 Linux 网络编程系列第 16 篇,整理 IM 聊天系统中介者类的实现,以及 Qt 客户端、VS 服务端、网络层与 Kernel 之间的数据传递。
2
Linux 网络编程(15):IM 聊天系统——网络功能实现:TCP 协议服务端
Linux 网络编程 Linux 网络编程系列第 15 篇,整理 IM 聊天系统 TCP 服务端的多客户端接收、线程与套接字映射、资源回收,以及网络层向中介者移交数据的实现。
3
Linux 网络编程(20):IM 聊天系统——添加好友与项目总结
Linux 网络编程 Linux 网络编程系列第 20 篇,整理 IM 聊天系统的添加好友完整通信流程、请求与回复协议分发规律、现有架构问题,以及文件传输、群聊和音视频等扩展方向。
4
Linux 网络编程(19):IM 聊天系统——转码、下线与聊天功能实现
Linux 网络编程 Linux 网络编程系列第 19 篇,整理 IM 聊天系统的用户下线、在线与离线聊天、添加好友请求持久化,以及 Qt 客户端和 VS 服务端之间的中文转码。
5
Linux 网络编程(17):IM 聊天系统——数据库设计和创建、注册功能实现、登录功能实现
Linux 网络编程 Linux 网络编程系列第 17 篇,整理 IM 聊天系统的协议分发、用户与好友数据库设计、MySQL 连接以及注册功能,并为登录请求处理预留入口。

目录