【网络编程与 Socket】Python 网络编程:socket + threading 实现简易聊天
·
Python 网络编程:socket + threading 实现简易聊天系统(含完整源码与实战讲解)
在网络编程的世界里,Socket 是沟通的“电话线”,Threading 是让你可以同时和很多人通话的“线程分机”。将它们组合起来,你就能从零构建一个多人并发的简易聊天服务。
一、Socket + Threading 到底在做什么?
用一句话概括:
一个 socket 就是一条“通信线路”,一个线程就负责“盯着”某个客户端。
所以,一个多人聊天程序就是:
- 一个主线程:负责接受新连接
- 多个子线程:各自负责收发对应客户端数据
- 一个共享消息广播函数
二、Python Socket 基础知识(附实例)
1. 创建一个最基础的 TCP 服务器
import socket
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(("0.0.0.0", 9999))
server.listen(5)
print("服务器已启动,等待连接...")
conn, addr = server.accept()
print("新客户端:", addr)
data = conn.recv(1024)
print("收到:", data.decode())
conn.send("你好,我是服务器".encode())
优点(正面示例)
- 简单
- 清晰
缺点(错误示例)
- 只能同时服务一个客户端
- conn.recv() 是阻塞的,客户端不发消息就会卡住
这迫使我们引入 threading。
三、Threading:让服务器能服务多个客户端
多线程模型基本结构
import threading
def handle_client(conn, addr):
while True:
data = conn.recv(1024)
if not data:
break
print(f"{addr}:{data.decode()}")
conn.close()
每来一个客户端:
threading.Thread(target=handle_client, args=(conn, addr)).start()
这样服务器就能同时处理多个连接。
四、完整项目:实现一个多人聊天室(含源码)
下面是完整可运行的聊天系统:
服务器 server.py
import socket
import threading
clients = [] # 保存所有客户端 socket
def broadcast(msg, source):
for c in clients:
if c != source:
try:
c.send(msg)
except:
pass
def handle_client(conn, addr):
print("客户端加入:", addr)
while True:
try:
data = conn.recv(1024)
if not data:
break
print(f"{addr} 说:{data.decode()}")
broadcast(data, conn)
except:
break
print("客户端退出:", addr)
clients.remove(conn)
conn.close()
def main():
server = socket.socket()
server.bind(("0.0.0.0", 9999))
server.listen(5)
print("聊天室服务器已启动,端口 9999")
while True:
conn, addr = server.accept()
clients.append(conn)
threading.Thread(target=handle_client, args=(conn, addr)).start()
if __name__ == "__main__":
main()
功能说明
- 每个客户端由一个线程负责
- broadcast() 用于把消息发送给其他用户
- 客户端退出时自动移除
客户端 client.py
import socket
import threading
def listen(sock):
while True:
try:
msg = sock.recv(1024)
print(msg.decode())
except:
break
def main():
sock = socket.socket()
sock.connect(("127.0.0.1", 9999))
threading.Thread(target=listen, args=(sock,), daemon=True).start()
while True:
msg = input("")
sock.send(msg.encode())
if __name__ == "__main__":
main()
五、常见错误示例与调试技巧
错误 1:主线程阻塞导致无人能连
错误代码:
conn, addr = server.accept()
data = conn.recv(1024)
当第一个客户端连进来,服务器会一直等待它发数据,后续客户端连不上。
解决:
- 使用线程处理每个客户端
- 主线程只负责 accept
错误 2:客户端关闭导致服务器崩溃
某些同学写的 recv 逻辑:
data = conn.recv(1024).decode()
print(data)
当客户端断开,recv 返回空数据或抛异常,程序会崩。
正确写法:
data = conn.recv(1024)
if not data:
break
错误 3:broadcast 里修改列表导致错误
错误:
for c in clients:
clients.remove(c)
会触发:
RuntimeError: list changed size during iteration
解决方法:
- 不在遍历时修改 clients
- 用 try/except 忽略发送失败
调试技巧
- 用
print查看线程是否启动 - 用
netstat -ano查看端口是否被占用 - 用
telnet 127.0.0.1 9999测试 server 是否正常
六、实际工作技巧:让你的聊天系统更“像样”
技巧 1:给每个用户增加昵称
可以在客户端连接时先发送名字:
name = sock.recv(1024).decode()
技巧 2:支持系统消息
如用户加入、用户退出通知。
技巧 3:心跳检测防止假死
每隔 30 秒发送一次心跳包。
技巧 4:使用队列代替直接 send
生产环境中可避免阻塞。
例如用 queue.Queue:
msg_queue.put(msg)
线程从队列取数据发送。
七、拓展:为什么不用多进程?为什么聊天系统常用 select/epoll?
多线程虽然简单,但在高并发情况下会产生:
- 线程过多
- 切换开销大
- Python GIL 限制性能
所以高并发聊天系统(如 WebSocket)更常用:
- select(基础)
- poll(增强)
- epoll(高并发专用)
本篇教程属于“教学友好、结构清晰”的版本。
如果你想进一步升级,我可以写:
《select + epoll 实现高并发聊天室》
或
《Python + asyncio 实现万人聊天室》
八、总结
通过本文你掌握的是一个非常典型的网络编程结构:
- 用 socket 建立 TCP 通信
- 用 threading 支持多个客户端并发
- 用广播机制构建聊天模型
- 避免常见错误(阻塞、断连、列表操作等)
- 学到实际工作中的优化技巧
- 理解背后的原理(I/O 模型 + 并发模型)
你完全可以在这个基础上继续拓展,做出自己的多人聊天工具、在线协作系统甚至小游戏服务器。
AI 创作声明
本文部分内容由 AI 辅助生成,并经人工整理与验证,仅供参考学习,欢迎指出错误与不足之处。
更多推荐

所有评论(0)