ZeenaZeek ZeenaZeek - 7 months ago 14
Python Question

Threading udp datas with Python

I'm trying to implement UDP socket's threading.

I want to be able to wait for clients to send me some data in a thread and wait for first datas in an other.

import threading
import socket

class Broker():

def __init__(self):
self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.sock.bind(('127.0.0.1', 4242))
self.clients_list = []

def talkToClient(self, ip):
self.sock.sendto("ok", ip)

def listen_clients(self):
while True:
msg, client = self.sock.recvfrom(1024)
t = threading.Thread(None, self.talkToClient, None, (client,), None)

b = Broker()
b.listen_clients()


and my client

import socket

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)

sock.sendto("connection", ('127.0.0.1', 4242))

while True:
msg, b = sock.recvfrom(1024)
print msg


Problem is that my client is never receiving "ok"

Answer

Your main problem is that you are not starting the thread that you have created.

t.start()

Should do it. Please make sure you are using four spaces for indentation as well.

I didn't see the error first myself, but once I added some logging statements it was pretty obvious. The code ended up looking like this:

import threading
import socket
import logging

class Broker():

    def __init__(self):
        logging.info('Initializing Broker')
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.sock.bind(('127.0.0.1', 4242))
        self.clients_list = []

    def talkToClient(self, ip):
        logging.info("Sending 'ok' to %s", ip)
        self.sock.sendto("ok", ip)

    def listen_clients(self):
        while True:
            msg, client = self.sock.recvfrom(1024)
            logging.info('Received data from client %s: %s', client, msg)
            t = threading.Thread(target=self.talkToClient, args=(client,))
            t.start()

if __name__ == '__main__':
    # Make sure all log messages show up
    logging.getLogger().setLevel(logging.DEBUG)

    b = Broker()
    b.listen_clients()

I'm afraid you will run into other problems however, because of your threaded solution. Most python modules are not thread-safe by default, unfortunately this is true for the socket module as well. I'm pretty sure that eventually your socket's internal state will be corrupted since you are reading in one thread and writing in another, or potentially in many others since you spawn a new process for each client.

If you look at multi-threaded socket code examples in Python, a socket is usually owned and used by only one thread. The key is to not reuse the listening socket for clients, but to use socket.accept to create a new socket for each client once it has connected.

Comments