Python下P2P聊天应用UDP Socket无法接收对等端数据求助
问题分析与解决方案
你的问题核心在于服务器地址交换逻辑错误,导致客户端拿到了错误的端口信息,后续绑定和发送目标端口全部出错,从而无法接收消息。以下是具体问题点和修正方案:
关键问题点
- 服务器向客户端发送的地址格式错误:当前发送的是「对方IP、对方端口、自己的端口」,完全没必要传递客户端自己的端口,且后续客户端解析时把对方端口当成了自己的通信端口,导致绑定错误。
- 客户端存在未定义变量:
print语句中的sport是未定义的,应该替换为dport。 - 客户端重复创建socket并绑定错误端口:监听和发送的socket都绑定到了错误的端口(对方的端口),而非自己实际用于P2P通信的端口。
修正后的代码
1. 服务器代码(修正地址交换逻辑)
import socket sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.bind(('', 44444)) while True: clients = [] # 等待两个客户端连接 while len(clients) < 2: data, address = sock.recvfrom(128) clients.append(address) sock.sendto(b'ready', address) c1_addr, c2_addr = clients # 向c1发送c2的完整地址,向c2发送c1的完整地址 try: sock.sendto(f"{c2_addr[0]} {c2_addr[1]}".encode(), c1_addr) sock.sendto(f"{c1_addr[0]} {c1_addr[1]}".encode(), c2_addr) except Exception as e: print(str(e))
2. 客户端代码(修正地址解析与通信逻辑)
import socket import threading # 第一步:与服务器交互获取对等端地址 my_port = 40270 server_addr = ('X.X.X.X', 44444) with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as sock: sock.bind(('', my_port)) sock.sendto(b'0', server_addr) # 等待服务器的ready响应 while True: data = sock.recv(1024).decode() if data.strip() == 'ready': break # 接收对等端的IP和端口 peer_info = sock.recv(1024).decode().split(' ') peer_ip = peer_info[0] peer_port = int(peer_info[1]) print(f"\n对等端地址: {peer_ip}:{peer_port},本地通信端口: {my_port}") # 第二步:启动监听线程接收对等端消息 def listen(): with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s: s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.bind(('', my_port)) while True: data, _ = s.recvfrom(1024) print(f"\rpeer: {data.decode()}\n> ", end='') listener = threading.Thread(target=listen, daemon=True) listener.start() # 第三步:发送消息给对等端 with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s: s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.bind(('', my_port)) while True: msg = input('> ') s.sendto(msg.encode(), (peer_ip, peer_port))
修正说明
- 服务器现在直接传递对等端的完整IP和端口,不再发送客户端自身的端口,简化逻辑避免混淆。
- 客户端明确自己的通信端口(
my_port),监听和发送socket都绑定到这个端口,确保能接收到对等端发送到该端口的消息。 - 修复了未定义变量
sport的问题,打印信息更清晰。 - 监听线程中使用
recvfrom获取发送方地址(虽然这里用不到,但更符合UDP的使用习惯)。
内容的提问来源于stack exchange,提问作者mimskydo
相关产品推荐
相关产品推荐

