Python游戏服务器中socket.sendto()调用无限挂起问题排查求助
sendto() hangs indefinitely in game server-to-client communication Problem Description
I'm setting up a server for my game, but the server is behaving abnormally at the final stage of sending data to the client. The issue seems to stem from this line of code:
sock.sendto(json.dumps({player_identifier: message}), self.udp_addr)
The call hangs indefinitely—my console prints "sending" but never "sent", and the client never prints "data received".
Additional context:
- The client's socket is bound to
0.0.0.0:1235, and the server is sending to the client's IP (127.0.0.1) on port 1235. - I've verified the message is intact when entering the
send_udpfunction, and the client'srunfunction executes normally. - This feature was working previously, and I can't find clear troubleshooting info.
Server code snippet:
def send_udp(self, player_identifier, message): """ Send udp packet to player (game logic interaction) """ sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) print("sending", flush = True) sock.sendto(json.dumps({player_identifier: message}), self.udp_addr) print("sent", flush = True)
Client code snippet:
class Client: def __init__(self, server_host, server_port_tcp=1234, server_port_udp=1234, client_port_udp=1235): """ Create a game server client """ self.client_udp = ("0.0.0.0", client_port_udp) self.lock = threading.Lock() self.server_listener = SocketThread(self.client_udp, self, self.lock) self.server_listener.start() self.server_udp = (server_host, server_port_udp) self.server_tcp = (server_host, server_port_tcp) self.register() class SocketThread(threading.Thread): def __init__(self, addr, client, lock): """ Client udp connection """ threading.Thread.__init__(self) self.client = client self.lock = lock self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.sock.bind(addr) def run(self): """ Get responses from server """ while True: data, addr = self.sock.recvfrom(1024) print("data received") self.lock.acquire() try: self.client.server_message.append(data) finally: self.lock.release()
Solution & Troubleshooting Steps
Let's break down the most likely causes and fixes for your hanging sendto() call:
1. You’re passing a string instead of bytes to sendto() (Python 3 critical issue)
In Python 3, UDP sockets require bytes-like objects for sending data, but json.dumps() returns a string. If you’re running Python 3, this should throw a TypeError, but if the code is wrapped in an uncaught exception handler (or running in a thread where exceptions aren’t printed), it might appear as a hang instead.
Fix this by encoding the JSON string to bytes:
sock.sendto(json.dumps({player_identifier: message}).encode('utf-8'), self.udp_addr)
2. No timeout set on the server socket
UDP is typically connectionless and non-blocking, but if the OS send buffer fills up (unlikely in testing, but possible), sendto() will block indefinitely. Adding a timeout will force the call to fail fast and give you debug info:
def send_udp(self, player_identifier, message): """ Send udp packet to player (game logic interaction) """ sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.settimeout(5) # Add 5-second timeout print("sending", flush=True) try: sock.sendto(json.dumps({player_identifier: message}).encode('utf-8'), self.udp_addr) print("sent", flush=True) except socket.timeout: print(f"Send timed out to {self.udp_addr}", flush=True) except Exception as e: print(f"Send failed: {str(e)}", flush=True) finally: sock.close() # Clean up the socket
3. Verify self.udp_addr is correctly set
Double-check that self.udp_addr is indeed ("127.0.0.1", 1235) (matching your client’s bound port). Add a print statement before sendto() to confirm:
print(f"Sending to {self.udp_addr}", flush=True)
It’s easy to accidentally use the server’s UDP port (1234) here instead of the client’s 1235.
4. Confirm the client’s listener is running correctly
Even if you think the client’s run function is working, add a debug print at the start of the SocketThread.run() method to confirm the listener is active and bound to the right port:
def run(self): """ Get responses from server """ print(f"UDP listener active on {self.sock.getsockname()}", flush=True) while True: data, addr = self.sock.recvfrom(1024) print("data received") # ... rest of your code
5. Check for player_identifier serialization issues
JSON requires object keys to be strings. If player_identifier is a custom object or non-serializable type, json.dumps() could hang or throw an exception. Test serialization in isolation to rule this out:
test_data = {player_identifier: message} print(f"Test serialization: {json.dumps(test_data)}", flush=True)
If this line fails, you’ll need to convert player_identifier to a string (or another JSON-supported type) before serialization.
内容的提问来源于stack exchange,提问作者Koekenhapper

