HNU-计算机网络-实验2-从零构建Python3 Socket聊天室与文件传输系统 📅 2026/7/15 2:13:28 1. 实验环境准备与基础概念在开始构建聊天室之前我们需要先准备好Python3的开发环境。我推荐使用Python 3.6及以上版本因为这个版本对异步IO的支持更加完善。安装Python后可以通过以下命令检查版本python3 --version接下来需要理解几个核心概念Socket网络通信的基本单元可以理解为两个程序间通信的端点TCP协议可靠的、面向连接的传输协议适合聊天室这种需要保证消息顺序的场景IP地址和端口就像房子的门牌号和房间号用于准确定位网络中的服务我建议在开始前先创建一个干净的虚拟环境python3 -m venv chatroom_env source chatroom_env/bin/activate # Linux/Mac chatroom_env\Scripts\activate # Windows2. 基础Socket通信实现我们先从最简单的单客户端-服务器模型开始。服务端代码server.py的核心部分如下import socket def start_server(): server_socket socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_socket.bind((0.0.0.0, 8888)) # 绑定所有网卡 server_socket.listen(5) # 最大排队连接数 print(服务器已启动等待连接...) while True: client_socket, addr server_socket.accept() print(f新连接来自{addr}) try: while True: data client_socket.recv(1024) # 接收数据 if not data: break print(f收到消息{data.decode(utf-8)}) client_socket.send(bMessage received) finally: client_socket.close()对应的客户端代码client.pyimport socket def start_client(): client_socket socket.socket(socket.AF_INET, socket.SOCK_STREAM) client_socket.connect((127.0.0.1, 8888)) # 连接本地服务器 while True: message input(请输入消息(输入quit退出): ) if message quit: break client_socket.send(message.encode(utf-8)) response client_socket.recv(1024) print(f服务器回复{response.decode(utf-8)}) client_socket.close()这个基础版本有几个关键点需要注意使用TCP协议(SOCK_STREAM)保证可靠性服务端需要先bind再listen客户端connect时需要指定正确的IP和端口消息传输需要编码/解码3. 多客户端支持与线程池基础版本只能处理单个客户端连接我们需要引入多线程来处理并发。这里我推荐使用ThreadPoolExecutor它比手动创建线程更高效from concurrent.futures import ThreadPoolExecutor def handle_client(client_socket, addr): print(f处理客户端 {addr} 的连接) try: while True: data client_socket.recv(1024) if not data: break print(f{addr} 发送{data.decode(utf-8)}) client_socket.send(bACK) except Exception as e: print(f处理 {addr} 时出错{e}) finally: client_socket.close() def start_threaded_server(): server_socket socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_socket.bind((0.0.0.0, 8888)) server_socket.listen(5) with ThreadPoolExecutor(max_workers10) as executor: print(多线程服务器已启动...) while True: client_socket, addr server_socket.accept() executor.submit(handle_client, client_socket, addr)实际测试中发现线程池大小需要根据服务器性能调整。我的经验公式是CPU核心数 × 2 2。比如4核CPU可以设置max_workers10。4. 聊天室功能实现完整的聊天室需要支持用户昵称广播消息用户加入/离开通知多房间支持可选服务端核心逻辑clients {} # 存储所有客户端连接 def broadcast(message, senderNone): 广播消息给所有客户端 for username, client in clients.items(): if client ! sender: # 不发送给自己 try: client.send(message.encode(utf-8)) except: del clients[username] # 移除失效连接 def handle_chat_client(client_socket, addr): username client_socket.recv(1024).decode(utf-8) # 首先接收用户名 clients[username] client_socket broadcast(f{username} 加入了聊天室) try: while True: message client_socket.recv(1024).decode(utf-8) if not message: break if message.startswith(/): # 处理命令 pass else: broadcast(f{username}: {message}) except: pass finally: del clients[username] broadcast(f{username} 离开了聊天室) client_socket.close()客户端需要做相应调整def start_chat_client(): username input(请输入你的昵称: ) client_socket socket.socket(socket.AF_INET, socket.SOCK_STREAM) client_socket.connect((127.0.0.1, 8888)) client_socket.send(username.encode(utf-8)) # 首先发送用户名 # 启动接收线程 threading.Thread(targetreceive_messages, args(client_socket,)).start() while True: message input() if message /quit: break client_socket.send(message.encode(utf-8)) client_socket.close() def receive_messages(socket): while True: try: message socket.recv(1024).decode(utf-8) print(message) except: break5. 文件传输功能文件传输需要特殊处理因为文件可能很大不能一次性读取。我们设计一个简单的协议客户端发送FILE:[文件名]|[文件大小]服务端准备接收客户端分块发送文件内容服务端处理代码def receive_file(client_socket, file_info): filename, filesize file_info.split(|) filesize int(filesize) with open(filename, wb) as f: received 0 while received filesize: data client_socket.recv(4096) if not data: break f.write(data) received len(data) return received filesize客户端发送代码def send_file(client_socket, filepath): filename os.path.basename(filepath) filesize os.path.getsize(filepath) # 发送文件头信息 header fFILE:{filename}|{filesize} client_socket.send(header.encode(utf-8)) # 分块发送文件内容 with open(filepath, rb) as f: while True: bytes_read f.read(4096) if not bytes_read: break client_socket.send(bytes_read)实际测试时发现大文件传输需要注意设置合适的缓冲区大小我测试4096字节效果不错添加进度显示考虑网络中断的恢复机制6. 常见问题与解决方案在开发过程中我遇到了几个典型问题端口占用问题服务器关闭后立即重启可能会报错Address already in use。解决方法server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)消息粘包问题TCP是流式协议消息可能会粘在一起。解决方案添加消息分隔符如换行符使用固定长度头部使用更高级的协议如HTTP客户端异常断开需要完善异常处理try: # 正常处理逻辑 except ConnectionResetError: print(客户端异常断开) finally: # 清理资源性能优化当用户量增大时可以考虑使用select/epoll等IO多路复用技术将部分逻辑异步化考虑使用消息队列解耦7. 完整项目结构建议一个规范的聊天室项目可以这样组织chatroom/ ├── server/ │ ├── __init__.py │ ├── main.py # 主入口 │ ├── core.py # 核心逻辑 │ └── utils.py # 工具函数 ├── client/ │ ├── __init__.py │ └── main.py ├── protocol/ # 通信协议定义 │ ├── __init__.py │ └── message.py └── requirements.txt在requirements.txt中记录依赖python3.68. 扩展思路完成基础功能后可以考虑加密通信使用SSL/TLS加密传输消息持久化将聊天记录保存到数据库Web界面使用Flask/Django提供Web访问移动端支持开发Android/iOS客户端我在实际测试中发现当用户超过100时纯Python的实现开始出现性能瓶颈。这时候可以考虑使用asyncio重写引入Redis处理消息队列考虑使用Go等高性能语言重写核心组件这个项目虽然不大但涵盖了网络编程的许多核心概念。通过实践我对TCP协议、多线程编程、异常处理等有了更深入的理解。建议大家在完成基础功能后继续挑战更复杂的场景比如跨机房通信、负载均衡等。