3

私は Python にかなり慣れていないので、私の問題がアマチュア的である場合は申し訳ありません。

ユーザーがブロードキャストされているUDPメッセージを表示できるようにする簡単なプログラムを作成しようとしています。プログラムがロックアップしないようにするには、ブロードキャストをリッスンする別のスレッドを作成する必要があります。

スレッド化を実装しようとする前は、プログラムはうまく機能していました。UDP メッセージを待って、メッセージをTextView受信したときにそれらを表示しました。もちろん、これによりメインスレッドがロックされました。

これが私のコードです: (はい、私のコードには無関係な問題がいくつかあることは承知していますが、無視してください。たとえば、socket.

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() 

コードは実行され、すべて正常に実行されますが、メッセージはまったく出力されません (私は自分でブロードキャストします)。


アップデート:

JF Sebastian の回答のおかげで、コードを次のように変更しました。

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() 

これまでのところ、すべてが完璧に動作しています。

4

1 に答える 1

1

マルチスレッド gtk アプリケーションでうまく機能するモデルは、すべての GUI コードをメイン スレッドで実行することです。バックグラウンド スレッドで実行される gtk からの唯一の方法は、gobject.idle_add()GUI コールバックがメイン スレッドで実行されるようにスケジュールすることです。

他のgtkgobject.threads_init()コードを実行する前に、モジュールの先頭に配置します。

これは Gtk 3 の例ですが、原則は Gtk 2 でも同じです

別の方法は、次のようなものを使用gobject.io_add_watch()して、複数のスレッドを使用しないようにすることです。

于 2013-01-22T16:02:57.087 に答える