套接字线程和PyGTK

3
我将尝试编写一个即时通讯程序,基本的UI已经完成,现在我正在研究消息接收部分。我有一个UI类和一个线程化的Receive_Socket类。每当Received_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

线程化的接收套接字类:

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)当消息被显示时,套接字可能已经接收到2个或更多消息,因此当它再次执行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在套接字准备好读取时调用您的函数。这样,您就不会冻结您的GUI,也不需要线程。同时,您也不需要idle_add

  2. 如果您采用1,则不会出现此问题,因为消息将按顺序到达,且没有并发线程来混淆数据。


谢谢,它运行得非常好!只有一个关于2)的问题,glib.io_add_watch是如何工作的?例如,当我向套接字发送3条消息时,当它接收到第一条消息时,它会调用在glib.io_add_watch中编写的回调函数,但是在处理回调函数时,其他两条消息将被套接字接收,因此,当回调完成(返回True)时,它将看到套接字有数据并再次启动回调,但这次fd.recv(1024)将包含连接的2条消息,对吗? - Nolhian
@Nolhian:当然,你的协议肯定有一些消息之间的分隔符。因此,你需要自己拆分消息,并使用缓冲区来保留部分消息,直到其余消息到达为止。另一个选择是使用 twisted http://twistedmatrix.com/ 这是一个网络框架。它的主循环与 gtk 主循环兼容。 - nosklo
@nosklo: 可以使用glib.io_add_watch来监听一个已经绑定到套接字的已准备好侦听吗? - Hibou57
@hibou57 是的,你可以使用它。 - nosklo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接