套接字线程与PyGTK

3 投票
1 回答
1103 浏览
提问于 2025-04-16 08:35

我正在尝试写一个即时通讯程序,基本的界面已经差不多完成了,现在我在研究接收消息的部分。我有一个UI类和一个线程接收的Receive_Socket类。每当Receive_Socket类的socket接收到一条消息时,它会调用gobject.idle_add()来执行一个UI方法,以便把消息显示在聊天窗口里。在gobject.idle_add()这一行之后,我有一个while循环,这个循环会一直运行,直到消息确实显示在聊天窗口里(我希望消息在接收另一条消息之前就能显示出来,因为我了解到gobject.idle_add()并不能保证执行顺序,当然我希望消息是按顺序显示的 :))

我试着总结一下我的代码:

UI 类:

Class UI:
##### somewhere in the init #####
    self.message_status = 0
def chat_window(self, contact, message=0):
    Check if a chat window is opened for the contact, if not it opens one.
    => In reality this check if a gtk.Window containing a gtk.Notebook is opened, 
    => if not it opens one
    => Then it creates a page for the contact in the notebook, containing a 
    => gtk.Textview which displays messages
    if message:
        self.message_display(contact, message)
def message_display(self,a,b):
    => Display the message in the message in the contact's textview
    self.message_status = 1

线程接收的Receive_Socket类:

Class Receive_Socket(threading.thread):
    message = sock.recv(1024)
    => the sender name is written in the message 
    if message:
        gobject.idle_add(myui.chat_window,sender, message)
        while not myui.message_status:
            time.sleep(0.1)
        myui.message_status = 0

主代码:

if __name__ == "__main__":
    myui = UI()
    reception = Receive_Socket()
    reception.start()
    gtk.main()

我的问题:

1) 这种代码看起来高效吗?将一个线程接收类和我的UI类结合在一起是最好的做法吗?

2) 当消息显示出来时,socket可能已经接收到了两条或更多的消息,所以当它再次执行message = sock.recv(1024)时,多个消息会被合并到message变量里。我考虑在每条消息中包含消息长度,这样如果在1024字节中有超过一条消息,它会取出这条消息,把剩下的放到一个message_buffer变量中,然后在再次执行sock.recv(1024)之前,会检查message_buffer变量是否有内容,如果有,就把message_buffer的内容放到message变量中,而不是直接用sock.recv(1024)。有没有更简单或更好的解决方案呢?

提前谢谢你,

Nolhian

1 个回答

3
  1. 不,别用线程。相反,使用glib.io_add_watch,这样当套接字准备好读取时,gtk/glib会自动调用你的函数。这样你就不会让你的界面卡住,也不需要使用线程。同时,你也不需要用到idle_add

  2. 如果你按照1的做法,就不会遇到这个问题,因为消息会按顺序到达,而且不会有多个线程同时运行导致数据混乱。

撰写回答