UDP threaded listener function

I'm new to Python, so I apologize if my problem is amateurish.

I am trying to make a simple program that allows the user to see the UDP messages that are being broadcast. In order for the program not to be locked, I, of course, need to create a separate stream to listen to the broadcast.

Before I tried executing threads, the program worked great. It just waited for UDP messages and displayed them in TextView

when it received it. Of course, this blocked the main stream.

Here is my code: (Yes, I know there are a few irrelevant problems with my code, but please ignore them, for example, I never close socket

. I'll cover those issues later.)

import socket
import select
import sys
import threading

try:
    import pygtk
    pygtk.require("2.0")
except:
    pass
try:
    import gtk
except:
    print("GTK not available!")
    sys.exit(1)


class GUI:
    def __init__(self):
        self.builder = gtk.Builder()
        self.builder.add_from_file("UDPListener.ui")
        dic = {"on_mainWindow_destroy" : self.quit,
             "on_listenButton_clicked" : self.startThread,
         "on_stopListenButton_clicked" : self.stopListening}
        self.builder.connect_signals(dic)

        self.listenerThread = threading.Thread(target = self.listen)

    def startThread(self, widget):
        self.listenerThread.start()

    def listen(self):
        bufferSize = 1024                                                          
        IPAddress = "0.0.0.0"
        IPAddress: 0.0.0.0
        portNumber = 50000
        udpClient = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

        textView = self.builder.get_object("messagesReceivedEntry").get_buffer()
        textView.text = textView.get_text(textView.get_start_iter(),textView.get_end_iter())

        textView.set_text("Listening...")

        try:
            udpClient.bind((IPAddress, portNumber))
            udpClient.setblocking(0)
        except:
            print "Cannot connect."

        try:
            while True:
                result = select.select([udpClient],[],[])
                message = result[0][0].recv(bufferSize)
                print message
        except:
            print "Cannot receive message"

    def quit(self, widget):
        sys.exit(0)

    def stopListening(self, widget):
        pass

gui = GUI()
gtk.main() 

      

The code will run and everything will work fine, but it never prints any messages (I pass them myself).


UPDATE:

Thanks to JF Sebastian's answer, I modified my code to include the following:

import socket
import select
import sys
import threading
import gobject

try:
    import pygtk
    pygtk.require("2.0")
except:
    pass
try:
    import gtk
except:
    print("GTK not available!")
    sys.exit(1)

gobject.threads_init()

class GUI:
    def __init__(self, UDPClient):
        self.udpClient = UDPClient

        self.builder = gtk.Builder()
        self.builder.add_from_file("TestUDPListenerREORG.ui")
        dic = {"on_mainWindow_destroy" : self.quit,
             "on_listenButton_clicked" : self.startThread,
         "on_stopListenButton_clicked" : self.stopListening}
        self.builder.connect_signals(dic)

        self.textView = self.builder.get_object("messagesReceivedEntry").get_buffer()
        self.textViewText = self.textView.get_text(self.textView.get_start_iter(),self.textView.get_end_iter())

        self.listening = False
        self.listenerThread = threading.Thread(target = self.listen)

    def startThread(self, widget):
        self.listenerThread.start()
        pass

    def listen(self):
        try:
            self.udpClient.connect()
        except:
            print "Cannot connect."
        try:
            while True:
                result = select.select([self.udpClient.client],[],[])
                message = result[0][0].recv(1024)
                print message
                gobject.idle_add(self.updateGUI, message)
        except:
            print "Cannot receive message"

    def updateGUI(self, message):
        print "updating..."
        self.textView.set_text(self.textViewText + "\n" + message)
        print message

    def quit(self, widget):
        self.udpClient.close()
        sys.exit(0)

    def stopListening(self, widget):
        pass



class UDPClient:
    def __init__(self, IPAddress, portNumber):
        self.IPAddress = IPAddress
        self.portNumber = portNumber
        self.bufferSize = 1024

        self.client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

    def connect(self):
        try:
            self.client.bind((self.IPAddress, self.portNumber))
            self.client.setblocking(0)
        except: print "Cannot connect."

    def close(self):
        try:
            self.client.close()
        except:
            pass

udpClient = UDPClient("0.0.0.0", 50000)
gui = GUI(udpClient)
gtk.main() 

      

Everything works fine so far.

+3


source to share


1 answer


The model I find works well for multi-threaded gtk applications is to run the entire GUI on the main thread. The only method from gtk that runs on a background thread is gobject.idle_add()

to schedule gui calls to be executed on the main thread.

Place gobject.threads_init()

somewhere at the top of the module before running any other gtk code.



Here's an example for Gtk 3 , but the principle is the same for Gtk 2. Another example .

An alternative is to use something like gobject.io_add_watch()

and avoid using multiple threads.

+1


source







All Articles