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.
source to share
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.
source to share