Python UDP receiver raises timeout error with high package rate while wireshark receives data

119 Views Asked by At

I'm trying to make a simple UDP receiver, using python, to read a continuous data stream from a data aquisition device. This device can be configured to send data using UDP protocol to a certain IP and port. I configured it to send two data streams on port 4000 and 4001 both to ip: 192.168.0.10 (see wireshark screenshot below). The stream to port 4001 has a higher package rate. My laptop ip for the ethernet interface used is set statically at this ip in order to receive the data. I can receive the slow stream at port 4000 which works as expected. When I use the same code and set the port to 4001 I expected to read this data stream, instead I get a timeout exception.

I expected the biggest problem with high package rate udp would be loosing data because the buffer overflows which is not a big problem since loosing some packets is acceptable for my case. However if I get a timeout exception during the socket.recv(1024) call I thought that means there is no data in the buffer? Since wireshark does receive data I don't understand what is happening.

Here is a minimal example of what I am trying to do.

import socket

for i in range(3):  # try multiple times
    try:
        socket_i = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        socket_i.settimeout(5)
        socket_i.bind(('192.168.0.10', 4001))  #4000 works, 4001 does not
        raw = socket_i.recv(1024)

        socket_i.close()
        print(raw)
    except Exception as ex:  # Exception is raised when using 4001: timed out
        socket_i.close()
        print('failed')
        print(ex)

Wireshark printscreen; only 1 packet from port 4000 is shown, since this stream is slow.

I read similar questions: Receive an high rate of UDP packets with python

Here it was concluded that python was the bottle neck. Also they received data, I don't receive anything, instead the socket.recv() times out. I don't think my package rate is that high, anyone thinks otherwise?

Receive an high rate of UDP packets with python

Here most of the data was received and only after some time the algorithm 'hangs on socket.recv()'. I tried increasing the buffer as suggested, using:

socket_i.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 1024*1024*1024)

Various values for buffer size are tried without luck. Setting large time out did not help.

Finally I tried using 'socketserver' package (the example udp server script):

import socketserver

class MyUDPHandler(socketserver.BaseRequestHandler):
    """
    This class works similar to the TCP handler class, except that
    self.request consists of a pair of data and client socket, and since
    there is no connection the client address must be given explicitly
    when sending data back via sendto().
    """

    def handle(self):
        data = self.request[0].strip()
        socket = self.request[1]
        print("{} wrote:".format(self.client_address[0]))
        print(data)
        # socket.sendto(data.upper(), self.client_address)  #don't want to send stuff back

if __name__ == "__main__":
    with socketserver.UDPServer(('192.168.0.10', 4001), MyUDPHandler) as server:
        server.serve_forever()

Using port 4000 this gives the expected behaviour, for port 4001 the code hangs without doing anything (probably large timeout by default?). I guess 'socketserver' package runs ontop of'socket' package?

I hope someone can help!

Update:

I fixed my problem by making the udp receiver using pyshark. This is a bit hacky and I'm not satisfied with the method however for now it works. I figured if wireshark receives data pyshark might work as well. Any suggestions using 'socket' package are welcome!

code for hacky udp receiver

import pyshark
ip = '192.168.0.10'
port = 4001
capture = pyshark.LiveCapture(bpf_filter=f'dst host {ip} and dst port {port}', use_json=True, include_raw=True)

for pkt in capture.sniff_continuously():
    raw = bytearray.fromhex(pkt.udp.payload_raw[0])
    print(raw)
0

There are 0 best solutions below