Drop Incoming 'packets' for Datagram Socket

时间:2015-11-12 11:04:07

标签: python sockets udp datagram

this is question is really focused on my problem and not relative to any of the other question I could find on this topic.

PSA: When I say "packet" I mean a full string received in a single socket.recv(maxsize)

I developed similar code for the same result on Java (my pref language) and it is ok, now I have to do in python.

I have two processes that run in parallel: 1-Normal client socket connected to a specific IP 2-A "client" Datagram socket binded to "ALL" IPs.

The normal socket is working correctly as I expect, while the datagram not.

I continuosly receive packets from a server (not mine and not opensource) at a rate of more than 5 per second, but I want to process only one of them every 3 seconds. In java I did just a "sleep" and it was ok, I was getting only the last live packet, while in Python with a "time.sleep(3)" the packets are queued (I don't know how and where) and not dropped.

I HAVE to drop them because those are not need and I have to do an HTTP call between one and the other so I can't fire an HTTP post for every set of data received at that rate!

here it is my "code" for the listening socket, some comments are for private code:

def listenPositions():
    lsSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    lsSocket.bind(("0.0.0.0", 8787))
    lsSocket.setblocking(0)
    try:
        while True:
            ready = select.select([lsSocket], [], [], 1)
            if ready[0]:
                lsSocket.settimeout(1)
                recvData = lsSocket.recv(16384)
                if len(recvData) != 0:
                    recv = recvData[0:len(recvData)].decode("utf-8")
                    #print("LS: Received: " + recv)
                    strings = filter(None, str(recv).split('\n'))
                    print("Strings count=" + str(len(strings))+ ": " + str(strings))
                    for item in strings:
                       #parse the received strings as json and get the items
                        jsonPosition = json.loads(item)
                        strId = jsonPosition["id"]
                        coordinates = jsonPosition.get("coordinates")
                        if coordinates is None:
                            continue
                        print("coordinates not null:" + str(coordinates))
#DO THE HTTP POST REQUEST


                    time.sleep(3) #Pause the system for X seconds, but other packets are queued!
                else:
                    print("LS: Received empty")
            else:
                print("LS: No data, timeout")
    except Exception as e:
        print(e)
        #handle exceptions...
        print("Exception, close everything")

1 个答案:

答案 0 :(得分:1)

When you have an open socket, all correctly addressed packets should be delivered to the application. We want to have our network connections as realiable as possible, don't we? Dropping a packet is an action of last resort.

If you want to get a packet only from time to time, you could create a listening socket, get a packet and close the socket.

However there is nothing easier than ignoring a packet. Just skip its processing and move on. The code below is incomplete, but hopefully expresses what I mean.

TIMEOUT = 1.0
INT = 3.0        # interval in seconds

# create udp_socket
last = time.time() - INT
udp_socket.settimeout(TIMEOUT)
while True:
    try:
        packet = udp_socket.recv(MAXSIZE)
    except socket.timeout:
        # handle recv timeout
        continue    # or break, or return
    except OSError:
        # handle recv error (Python 3.3+)
        break       # or continue, or return
    now = time.time()
    if now - last >= INT:
        # process the packet
        last = now

Please note that the select is not needed if you read only from one source.