2. TCP聊天室
任务目标
实现一个基于TCP协议的多客户端聊天室服务端与客户端程序。服务端能够同时接受多个客户端连接,并将任一客户端发送的消息广播给所有在线客户端,从而掌握多线程处理并发连接的核心方法。
环境与依赖
- Python 3.6+(标准库,无需第三方依赖)
- 操作系统:Windows / Linux / macOS 均可
核心实现
服务端采用socketserver.ThreadingTCPServer,每个客户端连接由独立线程处理,实现并发广播。客户端使用标准socket库,通过两个线程分别处理消息发送与接收。
# server.py - TCP聊天室服务端
import socketserver
class ChatHandler(socketserver.StreamRequestHandler):
clients = set() # 所有在线客户端的socket集合
def setup(self):
super().setup()
self.__class__.clients.add(self.request)
self.broadcast(f"[系统] 新用户加入,当前在线 {len(self.clients)} 人")
def handle(self):
while True:
try:
data = self.rfile.readline().strip()
if not data:
break
msg = data.decode('utf-8')
self.broadcast(f"[用户] {msg}")
except (ConnectionResetError, BrokenPipeError):
break
def finish(self):
super().finish()
self.__class__.clients.discard(self.request)
self.broadcast(f"[系统] 用户离开,当前在线 {len(self.clients)} 人")
def broadcast(self, message):
for client in list(self.clients):
try:
client.sendall((message + '\n').encode('utf-8'))
except (ConnectionResetError, BrokenPipeError):
self.clients.discard(client)
if __name__ == '__main__':
HOST, PORT = '127.0.0.1', 8888
with socketserver.ThreadingTCPServer((HOST, PORT), ChatHandler) as server:
print(f"聊天室已启动: {HOST}:{PORT}")
server.serve_forever()
# client.py - TCP聊天室客户端
import socket
import threading
def receive(sock):
while True:
try:
data = sock.recv(1024).decode('utf-8')
if data:
print(data, end='')
except (ConnectionResetError, OSError):
print("连接已断开")
break
def send(sock):
while True:
msg = input()
if msg.lower() == '/quit':
sock.close()
break
sock.sendall((msg + '\n').encode('utf-8'))
if __name__ == '__main__':
HOST, PORT = '127.0.0.1', 8888
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((HOST, PORT))
threading.Thread(target=receive, args=(sock,), daemon=True).start()
send(sock)
运行与验证
- 启动服务端:终端执行
python server.py,看到“聊天室已启动”即成功。 - 启动多个客户端:另开两个以上终端,分别执行
python client.py。 - 验证广播:在任一客户端输入消息并回车,其他所有客户端(包括发送者自己)都应看到
[用户] 消息内容。 - 验证上下线通知:新客户端连接时,所有在线客户端收到“新用户加入”提示;关闭一个客户端(输入
/quit或直接关闭窗口),其余客户端收到“用户离开”提示。 - 通过条件:所有客户端能实时收到彼此的广播消息,且上下线通知准确显示在线人数变化,即判定实现成功。
常见问题
- 端口被占用:若启动服务端报
Address already in use,更换PORT或等待系统释放端口。 - 中文乱码:确保所有终端编码为 UTF-8(Windows 可执行
chcp 65001后重启终端)。 - 客户端无法连接:确认服务端已先启动,且
HOST与PORT在两端代码中一致。