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 并 sendrecv_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 字节):

  1. 200 字节 name:发言者昵称;系统消息时固定为 "#NULL"
  2. 4 字节 intcolor_code(发送者 ID,客户端用 id % 6 取色)
  3. 200 字节 str:消息正文(如 Alice: hello 中的 hello,或 Alice has joined

接收端必须用 recv_all 读满 200 + 4 + 200,再解析下一则消息。

5.4 系统消息约定

name"#NULL" 时,客户端不打印 name: 前缀,只显示彩色正文,用于「xxx has joined / has left」类提示。


posted @ 2026-05-21 09:59  fighting_88412  阅读(31)  评论(0)    收藏  举报