简体   繁体   中英

Listening from multiple UDP sockets in Python script

I'm currently trying to have a Python script receiving data from two different ports using two different UDP sockets (one socket, one port), initialized as follows:

# socket 1 
source1_UDPSock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
source1_UDPSock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
source1_port = 6008
source1_listen_addr = ("",source1_port)
source1_UDPSock.bind(source1_listen_addr)

# socket 2 
source2_DPSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
source2_UDPSock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
source2_port = 6009 
source2_listen_addr = ("", source2_port)
source2_UDPSock.bind(source2_listen_addr)

The problem comes when I need to retrieve the data received using the following lines:

soc1_data, addr = source1_UDPSock.recvfrom(source1_port)
soc2_data, addr = source2_UDPSock.recvfrom(source2_port) 

The code runs normally, but if I don't get any data from the first recvfrom it will block the execution until it gets something. I tried setting both sockets to non-blocking using source1_UDPSock.setblocking(False) in both of them, but it showed to be a bad solution since I had to wait one or two seconds for preventing a BlockingIOError: [WinError 10035] to appear, losing the data that may be being received from the other port.

I tried to use select in the following code after setting both ports to non-blocking:

ready_read, ready_write, exceptional = select.select([source1_UDPSock, source2_UDPSock], [],[], None)
for ready in ready_read: 
    data_1, addr = source1_UDPSock.recvfrom(source1_port)
    data_2, addr = source2_UDPSock.recvfrom(source2_port)

but I had no succeed, as it keep throwing the BlockingIOError 10035.

May the use of multithreading (one thread, one open socket) be the solution for this issue?

Thank you in advance.

Problem solved!

Finally I applied the solution found in this question performing some adaptations. I divided the port listeners into two files and created this script:

import multiprocessing 
import subprocess

def worker(file):
    subprocess.Popen(['python', file])

if __name__ == "__main__": 
    files = ['listener1.py', 'listener2.py']
    for i in files: 
        p = multiprocessing.Process(target = worker(i))
        p.start()

Each listener needs to perform some specific treatment on the data received (which is different in the two cases), so having both of them separated is OK for me.

Again thank you all!

You can use the select-Module to wait for data on multiple non-blocking sockets at once.

Another possibility is to use separate threads per socket and continue to use blocking sockets, but then you will have to synchronize your threads.

It depends on the general structure of your code which way is easier or better.

Edit:

BlockingIOError 10035 is thrown when you receive from a nonblocking socket that currently has no data, it means "this operation would have blocked if this wasn't a nonblocking socket".

In your changed code you should probably not read from all the sockets in your for-loop, but only from those that are returned as ready. You might want to read up the basics of blocking/non-blocking sockets, for example in Beej's Guide .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM