C++实现简易聊天室
用 C++ 从零实现一个命令行 TCP 聊天室
基于 POSIX 套接字与 C++11 多线程的命令行聊天室。服务端负责连接管理与消息广播,客户端将发送与接收拆成独立线程,在终端里实现「边打字边收消息」的体验。
项目源码: https://github.com/xcj-fighting/chatroom-cpp
一、效果演示
上图:先启动 server,再开两个 client 分别登录并发消息,可见彩色昵称、进出提示与实时广播。

二、为什么要做这个项目
网络编程入门时,我们常会写「客户端发一句、服务端回一句」的 echo 程序。但真正贴近日常体验的,是多人同时在线、消息实时可见的聊天场景。
chatroom-cpp 刻意保持精简:不引入 Boost.Asio、不碰 WebSocket,只用 Linux 自带的 socket / bind / listen / accept / send / recv,配合 <thread> 和 <mutex>,把「一个服务端 + 多个客户端 + 广播」这条链路走通。适合用来巩固:
- TCP 面向字节流时的粘包 / 半包问题
- 多线程共享客户端列表时的互斥
- 终端 ANSI 颜色与多线程
cout的协调
项目地址:https://github.com/xcj-fighting/chatroom-cpp
三、功能一览
| 能力 | 说明 |
|---|---|
| 多人在线 | 多个客户端同时连接同一服务端 |
| 实时广播 | 任一用户发言,其他人立即收到 |
| 彩色昵称 | 按用户 ID 分配 6 种 ANSI 终端色 |
| 进出提示 | 加入 / 离开聊天室时有系统消息 |
| 双线程客户端 | 发送与接收分离,输入时仍可收消息 |
| 优雅退出 | 输入 #exit 后通知全员并断开 |
四、整体架构
┌─────────────────┐
│ server │
│ accept 主循环 │
│ 每连接一线程 │
│ broadcast 广播 │
└────────┬────────┘
│ TCP :10000
┌─────────────────┼─────────────────┐
│ │ │
┌──────▼──────┐ ┌──────▼──────┐ ┌──────▼──────┐
│ client │ │ client │ │ client │
│ t_send 发送 │ │ │ │ │
│ t_recv 接收 │ │ │ │ │
└─────────────┘ └─────────────┘ └─────────────┘
- 服务端:主线程
accept新连接;为每个连接detach一个handle_client线程;收到消息后向除发送者外的所有存活客户端转发。 - 客户端:连接成功后发送定长昵称;
send_message线程读 stdin 并send;recv_message线程循环recv并打印。
五、应用层协议设计
TCP 是字节流,一次 send 的数据可能被拆成多次 recv 到达,因此项目采用定长字段 + recv_all 循环读满的方式,避免解析错位。
5.1 常量
- 单字段最大长度:
MAX_LEN = 200字节(用户名、消息体各占一块 200 字节缓冲区) - 默认端口:
10000 - 客户端默认连接:
127.0.0.1(可在client.cpp中改为局域网 IP)
5.2 客户端 → 服务端
| 时机 | 载荷 |
|---|---|
| 连接后 | 200 字节昵称(不足部分由 memset / 缓冲区约定处理) |
| 聊天中 | 200 字节消息体;内容为 #exit 时表示退出 |
5.3 服务端 → 其他客户端(每条聊天 / 系统通知分三帧)
每次广播依次发送(共 404 字节):
- 200 字节
name:发言者昵称;系统消息时固定为"#NULL" - 4 字节
int:color_code(发送者 ID,客户端用id % 6取色) - 200 字节
str:消息正文(如Alice: hello中的hello,或Alice has joined)
接收端必须用 recv_all 读满 200 + 4 + 200,再解析下一则消息。
5.4 系统消息约定
当 name 为 "#NULL" 时,客户端不打印 name: 前缀,只显示彩色正文,用于「xxx has joined / has left」类提示。

浙公网安备 33010602011771号