2. TCP聊天室
任务目标
实现一个基于TCP的多客户端聊天室:服务器维护多个客户端连接,任一客户端发送的消息由服务器广播给所有其他在线客户端,并处理客户端并发接入与断开。
环境与依赖
Python 3.8+,仅使用标准库 socket、threading,无需第三方包。
核心实现
import socket
import threading
HOST = '127.0.0.1'
PORT = 9000
clients = []
lock = threading.Lock()
def broadcast(message, sender_sock=None):
with lock:
for sock in clients[:]:
if sock is not sender_sock:
try:
sock.sendall(message)
except:
if sock in clients:
clients.remove(sock)
sock.close()
def handle_client(conn, addr):
print(f"[连接] {addr} 已加入")
try:
while True:
data = conn.recv(1024)
if not data:
break
broadcast(data, conn)
except:
pass
finally:
with lock:
if conn in clients:
clients.remove(conn)
conn.close()
print(f"[断开] {addr} 已离开")
def start_server():
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.bind((HOST, PORT))
server.listen(5)
print(f"[启动] 聊天室服务器监听 {HOST}:{PORT}")
while True:
conn, addr = server.accept()
with lock:
clients.append(conn)
threading.Thread(target=handle_client, args=(conn, addr), daemon=True).start()
if __name__ == '__main__':
start_server()
运行与验证
启动服务器:
python chat_server.py
启动两个或多个客户端:另开终端,使用 nc 或 Python 交互式连接:
nc 127.0.0.1 9000
每个终端输入一行文字并回车。
通过条件:
- 任一客户端发送的消息,其他所有客户端都能收到,发送者自己不会收到回显;
- 服务器终端显示每个客户端的加入与断开日志;
- 一个客户端断开(Ctrl+C 或关闭终端)不影响其他客户端继续收发消息;
- 多个客户端同时发送消息时,消息不丢失、不串线。
关键说明
- 广播时使用
sender_sock参数排除消息来源,避免回显给发送者自身; - 所有对
clients列表的读写均通过lock保护,防止多线程并发修改导致异常; - 发送失败(客户端异常断开)时自动从列表移除并关闭连接,保证后续广播不会向失效socket发送数据。