当前位置: 首页 > news >正文

Python 实现基于 TCP 的聊天程序(Socket + threading + Tkinter + 4 节点并行)

Python 实现基于 TCP 的聊天程序(Socket + threading + Tkinter + 4 节点并行)

本文配套实验:TCP/IP 协议基础、Python 网络编程、Socket 编程、threading 多线程、Tkinter 图形界面。在华为云 FlexusX 4 节点上完成分布式聊天实测。
完整源码与运行产物见文末仓库地址(Gitee)。


一、实验目标

  1. 理解TCP/IP的面向连接、可靠字节流传输模型。
  2. 掌握Python Socket服务端listen/accept与客户端connect编程。
  3. 掌握threading多线程:服务器为每个客户端连接单独开一个线程,实现并发。
  4. 掌握Tkinter图形界面:聊天室 GUI,并在后台线程中接收网络消息,避免界面卡死。
  5. 4 台服务器上并行运行、互通测试,验证真实网络环境下的聊天功能。

二、TCP/IP 与 Socket 核心概念

1. TCP 三次握手与可靠传输

TCP 是面向连接的协议。客户端与服务端通信前要先完成"三次握手",建立一条可靠字节流通道。连接建立后,发送的数据会按顺序、无差错地到达对端(除非网络断开)。

2. Python Socket 编程模型

服务端:

importsocket srv=socket.socket(socket.AF_INET,socket.SOCK_STREAM)# TCPsrv.bind(("0.0.0.0",9000))# 绑定本机所有网卡的 9000 端口srv.listen(64)# 监听,最大挂起连接数 64conn,addr=srv.accept()# 阻塞等待客户端连接

客户端:

client=socket.socket(socket.AF_INET,socket.SOCK_STREAM)client.connect(("服务器IP",9000))# 主动发起连接client.sendall(b"hello\n")

3. 为什么需要多线程

服务端如果只用一个线程,会陷入"处理 A 客户端 → B 客户端发消息也读不到"的困境。正确做法是:每 accept 一个连接就创建一个threading.Thread,每个线程独立和它的客户端收发,主线程继续 accept 下一个连接。


三、聊天室协议设计(教学版)

为了简单、可读,本实验采用文本行协议(每条消息以\n结尾):

  • 客户端连接后,第一条消息作为昵称
  • 后续每行都是聊天内容
  • 服务器把任意客户端消息以 JSON 广播给所有人:
    {"type":"chat","from":"昵称","msg":"内容"}
  • 上下线由服务器自动广播系统消息:
    {"type":"system","from":"系统","msg":"XXX 加入了聊天室"}

工业上通常会用二进制长度头/Protocol Buffers,但教学演示用文本行最清晰。


四、聊天服务器:多线程广播(chat_server.py

核心逻辑:

  1. 监听0.0.0.0:9000
  2. 维护在线客户端列表clients(用锁clients_lock保护线程安全)。
  3. accept到新连接后,创建Thread(target=handle_client)
  4. handle_client:先读取昵称,然后循环接收每行消息,调用broadcast把 JSON 发给所有在线客户端。
importsocket,threading,json clients=[]clients_lock=threading.Lock()defbroadcast(obj):data=(json.dumps(obj,ensure_ascii=False)+"\n").encode("utf-8")withclients_lock:forconn,addr,nameinclients:try:conn.sendall(data)exceptException:passdefhandle_client(conn,addr):name=conn.recv(1024).decode("utf-8").strip()# 首条为昵称withclients_lock:clients.append((conn,addr,name))broadcast({"type":"system","from":"系统","msg":f"{name}加入了聊天室"})whileTrue:data=conn.recv(4096)ifnotdata:break# 按行解析、广播...

五、控制台客户端:脚本化并行测试(chat_client.py

控制台客户端用于在headless服务器上批量验证

用法:

python3 chat_client.py<服务器IP><端口><昵称>"消息1|消息2"<消息间隔>

关键实现:

  • 主线程连接 + 发送消息。
  • 接收线程recv_loop持续读取广播,避免阻塞发送。
importsocket,threading,timedefrecv_loop(sock):whileTrue:data=sock.recv(4096)ifnotdata:break# 解析 JSON 并打印sock=socket.socket(AF_INET,SOCK_STREAM)sock.connect((SERVER,PORT))threading.Thread(target=recv_loop,args=(sock,),daemon=True).start()

六、Tkinter GUI 客户端(chat_gui.py

GUI 客户端体现"用 Tkinter 库编写聊天程序 GUI 模块"。界面组成:

  • 顶部:服务器 IP / 端口 / 昵称输入框 + 连接/断开按钮。
  • 中部ScrolledText消息显示区(只读)。
  • 底部:消息输入框 + 发送按钮,支持回车发送。

关键点:GUI 的接收必须放到独立线程!

# 连接成功后启动接收线程threading.Thread(target=self.recv_loop,daemon=True).start()

如果直接在主线程recv(),界面会冻结,按钮点不动。recv_loop收到消息后用self.root.after(0, lambda: ...)self.append_text线程安全地更新界面。

真实运行截图

在华为云ecs-a16b-0002上通过xvfb虚拟显示运行 GUI 客户端,连接服务器114.116.249.146:9000,自动发送消息后截屏:

可以看到:

  • 已连接到服务器114.116.249.146:9000
  • 系统提示 “GUI节点 加入了聊天室”
  • GUI 端发消息你好,我是 Tkinter GUI 客户端 ✅,并被服务器广播回显

这证明 GUI 客户端不仅界面正常,而且能真实收发 TCP 消息


七、4 节点并行实战(华为云 FlexusX)

部署架构

节点角色连接目标
ecs-a16b-0001 (114.116.249.146)聊天服务器 + 1 个本机客户端127.0.0.1:9000
ecs-a16b-0002 (124.70.93.143)客户端114.116.249.146:9000
ecs-a16b-0003 (1.92.74.240)客户端114.116.249.146:9000
ecs-a16b-0004 (116.205.116.6)客户端114.116.249.146:9000

编排脚本(run_chat.py

本地用paramiko多线程执行:

  1. 在 0001 启动服务端,用setsid脱离会话,确保 SSH 断开后服务器仍常驻。
  2. 4 个客户端并发连接到 0001。
  3. 拉取服务器日志与各客户端日志,合并成transcript.txt

服务器侧日志(线程分配证明)

[MainThread] 聊天服务器已启动,监听 0.0.0.0:9000 [Thread-2 (handle_client)] node0001 加入聊天室 (addr=('127.0.0.1', 57000)),当前在线 1 [Thread-3 (handle_client)] node0002 加入聊天室 (addr=('124.70.93.143', 34584)),当前在线 2 [Thread-4 (handle_client)] node0004 加入聊天室 (addr=('116.205.116.6', 53938)),当前在线 3 [Thread-5 (handle_client)] node0003 加入聊天室 (addr=('1.92.74.240', 48298)),当前在线 4 [Thread-2] node0001: 【0001】TCP 三次握手完成,连接已建立 [Thread-3] node0002: 【0002】收到服务器广播,在线节点已可见 [Thread-4] node0004: 【0004】聊天室消息被广播给所有人 [Thread-5] node0003: 【0003】GUI 客户端也能接入同一服务器 ... [Thread-2] node0001 断开,剩余在线 3 [Thread-3] node0002 断开,剩余在线 2 [Thread-4] node0004 断开,剩余在线 1 [Thread-5] node0003 断开,剩余在线 0

每个客户端由独立的 Thread-2~5处理,threading并发效果一目了然。

客户端侧日志(广播效果证明)

node0002为例,它收到了其他 3 个节点的消息:

[node0002] 已连接服务器 114.116.249.146:9000 [系统] node0002 加入了聊天室 [来自 node0001] 【0001】TCP 三次握手完成,连接已建立 [来自 node0004] 【0004】聊天室消息被广播给所有人 [来自 node0003] 【0003】GUI 客户端也能接入同一服务器 [来自 node0001] 【0001】服务器用 threading 为每客户端开线程 [来自 node0002] 【0002】多客户端互不阻塞 ✅ [来自 node0004] 【0004】4 节点并行测试完成 [来自 node0003] 【0003】Socket 编程真有趣 [系统] node0001 离开了聊天室 [node0002] 测试完成,退出

4 节点全部成功,每个客户端都完整收到了其他节点的消息,TCP + threading + 广播验证通过 ✅。

踩坑记录

  1. pkill -f chat_server.py自匹配自杀-f按整条命令行匹配,"启动 chat_server 的 shell 命令行"里就含有chat_server.py,结果把启动自己的 shell 杀了,服务器根本起不来。改按端口杀进程解决。
  2. nohup进程被 SSH 会话关闭:paramiko 执行nohup ... &并关闭通道后,进程可能仍被信号终止。改用setsid创建新会话,彻底脱离原会话。
  3. 服务器就绪探测从本机做:本地沙箱到云服务器 9000 端口可能受安全组影响,但节点间 9000 实际互通;从服务器本机127.0.0.1:9000探测最可靠。

八、完整运行示例

本地快速体验

# 终端1:启动服务器python3 chat_server.py9000# 终端2:启动客户端 Apython3 chat_client.py127.0.0.19000Alice"你好|大家好"# 终端3:启动客户端 Bpython3 chat_client.py127.0.0.19000Bob"收到|Socket 真有趣"# 终端4:启动图形客户端python3 chat_gui.py

4 节点并行部署

python3 run_chat.py

九、总结

  • TCP 是面向连接的可靠传输,三次握手后客户端与服务端建立字节流通道。
  • Python Socket只需socket.socket(AF_INET, SOCK_STREAM)即可实现服务端/客户端。
  • threading 多线程让服务器能同时处理多个客户端,每个连接一个线程,互不阻塞。
  • Tkinter GUI的接收必须放在后台线程,否则界面会卡死。
  • 4 台华为云服务器并行验证证明了:跨节点 TCP 连接、多线程并发、消息广播均正常工作,且 GUI 客户端能真实接入并收发消息。

十、源码与产物

  • Gitee 仓库:https://gitee.com/LiaCin/python-tcp-chat
  • 目录结构:
    python-tcp-chat/ ├── chat_server.py # 多线程 TCP 聊天服务器 ├── chat_client.py # 控制台客户端(脚本化测试) ├── chat_gui.py # Tkinter GUI 客户端 ├── run_chat.py # 4 节点 paramiko 并行编排 ├── Python实现基于TCP聊天程序.md # 本博客 ├── README.md ├── gui.png # Xvfb 下 GUI 真实截图 └── results_chat/ ├── transcript.txt # 合并日志(4 客户端广播证明) ├── 114.116.249.146/ │ ├── server_log.txt # 服务器侧线程处理日志 │ ├── server_stdout.log │ └── client_node0001.log ├── 124.70.93.143/client_node0002.log ├── 1.92.74.240/client_node0003.log └── 116.205.116.6/client_node0004.log

如果本文对你理解 TCP/Socket/threading/Tkinter 有帮助,欢迎点赞收藏;也欢迎在评论区晒出你的 4 节点运行结果 🚀

http://www.jsqmd.com/news/1163864/

相关文章:

  • 面试问题
  • openeuler/cpds-detector高级用法:自定义监控规则与告警策略全攻略
  • 2026国内GEO服务商TOP9:AI搜索优化公司能力、定位与预算对比 - 品牌深度评测
  • Fable 4D飞溅效果格式技术解析:原理、应用与实战指南
  • 2026广州低分中考学生出路:南沙低进高出民办高中朝晖高中升学解析 - 米諾
  • Windows右键菜单清理指南:3步告别臃肿右键菜单,提升工作效率50%
  • Python 工业边缘 CLI 实战:用 Typer 做参数校验、子命令与帮助文档
  • PilotGo-plugin-ELK与PilotGo平台集成:打造一体化运维管理
  • 5分钟掌握B站缓存视频转换神器:m4s-converter完全指南
  • 2026年北七家、小汤山仓储寄存/库房出租:无中介费、配套完善/业主直租、整租长租 - 硬核推荐
  • 内核Oops分析与crash dump调试实战:从恐慌信息到根因的精确定位
  • 跳跃游戏 II:从“接力赛”到“BFS 层级覆盖”——贪心 + BFS 的经典范式
  • BetterGI:原神智能辅助工具的完整使用指南
  • 2026年7月最新哈尔滨真力时官方售后服务网点地址及客服电话一览 - 亨得利官方服务中心
  • Kubernetes 系列【11】控制器:Deployment(无状态部署控制器)
  • 寄大件哪个物流最便宜?2026最新省钱攻略+比价技巧 - 快递物流资讯
  • 匹米替比Pimitespib:HGF通路靶向难治性肉瘤新选择
  • gitstats 统计工具
  • 2026广州有一生一案教学的民办高中吗?南沙朝晖高中分层培优介绍 - 米諾
  • 制造业生产现场管理:计划、组织、协调、控制与检测的全面实践
  • 2026年7月最新成都市郫都区亨得利官方名表服务中心电话公示 - 亨得利官方博客
  • 2026手机拍摄二寸照片完整指南:尺寸规范、拍摄技巧与多类制作实操
  • 2026年济南除甲醛,哪家靠谱又省心? - 米諾
  • 终极解决方案:如何为JetBrains IDE无限重置30天试用期
  • 近期量化工具怎么选,先看规则流程能否承接
  • 第一章Netty,聚集写入 (Gathering Writes)
  • 别再 if-else 疯狂嵌套了!观察者模式让你代码优雅到离谱
  • 2026最新适合长期学习的八字排盘App推荐:为什么要看AI提示词和多盘复盘?
  • 达梦数据库-非常规场景恢复-01-REDO损坏、误删
  • GEO服务商 vs SEO公司:本质区别、实施路径与佛山企业选择指南 - 米諾