Python UDP socketserver returning empty message

Question:

I have a UDP socketserver program that I use to demonstrate how UDP works (code for the server and client are below). I run this on a server, then have the client.py program send a message and receive a reply. I am unfortunately running into an issue that seems to only occur on campus Wifi. On campus wifi, the client does not receive a response.

Troubleshooting with Wireshark shows the issue. For some reason the UDP server is responding with two UDP messages – one empty, and one containing the response message. These messages are recorded in Wireshark as coming in approximately 0.000002 seconds apart. On a wired network, the one with the response consistently comes first, and on Wifi, the empty message consistently comes first. Since the client is waiting for a single messages response, when the empty message returns, the client prints and exits, and the actual response is never seen.

I know I could write the client to listen for both messages and print out whichever one has the data, but I would rather try to figure out what’s going on. Why is the socketserver responding with two messages in the first place, and how can I get it to only send one? OR at least to send the data first.

server.py:

import socketserver


class MyUDPRequestHandler(socketserver.DatagramRequestHandler):
    def handle(self):

        data = self.request[0].strip()
        socket = self.request[1]
        # just send back the same data, but lower-cased
        socket.sendto(data.lower(), self.client_address)


if __name__ == "__main__":
    with socketserver.UDPServer(("0.0.0.0", 9091), MyUDPRequestHandler) as server:
        server.serve_forever()

client.py:

import socket

HOST, PORT = "localhost", 9091
message = "NOW I AM SHOUTING"  # The UDP server will lowercase the message

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

sock.sendto(bytes(message + "n", "utf-8"), (HOST, PORT))
received = str(sock.recv(1024), "utf-8")

print("Sent:     {}".format(message))
print("Received: {}".format(received))
Asked By: Ryan

||

Answers:

I’ve repeated the problem and it’s socketserver. Notice the definition of DatagramRequestHandler below:

class DatagramRequestHandler(BaseRequestHandler):

    """Define self.rfile and self.wfile for datagram sockets."""

    def setup(self):
        from io import BytesIO
        self.packet, self.socket = self.request
        self.rfile = BytesIO(self.packet)
        self.wfile = BytesIO()

    def finish(self):
        self.socket.sendto(self.wfile.getvalue(), self.client_address)

The packet is put into a buffer as rfile and should be read from there, then written back to the wfile buffer. finish sends the packet. The handler shouldn’t call sendto itself:

import socketserver

class MyUDPRequestHandler(socketserver.DatagramRequestHandler):
    def handle(self):
        data = self.rfile.read()
        self.wfile.write(data.strip().lower())

if __name__ == "__main__":
    with socketserver.UDPServer(("0.0.0.0", 9091), MyUDPRequestHandler) as server:
        server.serve_forever()

But just using a simple socket as the server works fine too:

import socket

s = socket.socket(type=socket.SOCK_DGRAM)
s.bind(('', 9091))
while True:
    data, client = s.recvfrom(2048)
    s.sendto(data.strip().lower(), client)

Note that UDP packets are not guaranteed to be delivered or delivered in the same order, so the original code’s issue with the two packets changing order isn’t surprising.

Answered By: Mark Tolonen
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.