2010-12-15 86 views
3

J'essaie d'écrire un programme de messagerie instantanée, l'interface de base est presque terminée et je regarde dans la partie de réception des messages. J'ai une classe d'interface utilisateur et une classe threadée Receive_Socket. Chaque fois que le socket de la classe Received_Socket reçoit un message, il fait un gobject.idle_add() pour appeler une méthode UI afin d'afficher le message dans une fenêtre de discussion. Après la ligne gobject.idle.add(), j'ai une boucle while qui boucle jusqu'à ce que le message soit en fait affiché dans la fenêtre de chat (je veux que le message soit affiché avant de recevoir un autre message car j'ai lu gobject.idle_add() ne garantit pas l'ordre d'exécution, et bien sûr je veux des messages à afficher dans l'ordre :))Socket Thread et PyGTK

J'ai essayé de résumer mon code:

UI classe:

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 

classe hiérarchique 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 

Main Code:

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

Mes questions:

1) Est-ce que ce genre de code sembler efficace? Est-ce la meilleure façon de procéder (avoir une classe de réception threadée avec ma classe d'interface utilisateur)?

2) Au moment où le message est affiché, le socket peut avoir reçu 2 messages ou plus, alors quand il fait à nouveau message = sock.recv (1024), plusieurs messages seront concaténés dans le message variable. J'ai pensé à inclure la longueur du message dans chaque message, donc s'il y a plus d'un message dans les 1024 octets, il prendra le message et mettra le reste dans une variable message_buffer et avant de refaire un sock.recv (1024) il vérifiera si la variable message_buffer contient n'importe quoi et si c'est le cas, placez le message_buffer dans la variable de message au lieu de sock.recv (1024). Existe-t-il une solution plus simple/meilleure pour ce faire?

Merci à l'avance,

Nolhian

Répondre

3
  1. Non Ne pas utiliser les threads. Au lieu de cela, utilisez glib.io_add_watch pour que gtk/glib appelle votre fonction lorsque le socket est prêt à lire. De cette façon, vous ne ferez pas gui votre gui et n'aura pas besoin de threads. Vous n'aurez pas non plus besoin de idle_add. Si vous faites , vous n'aurez pas ce problème, car les messages arriveront dans l'ordre et il n'y aura pas de threads concurrents pour confondre les données.

+0

Merci cela fonctionne très bien! Juste une question sur 2), comment fonctionne vraiment glib.io_add_watch? Par exemple j'envoie 3 messages au socket, quand il reçoit le premier il appelle le callback écrit dans glib.io_add_watch, mais pendant le traitement du callback les 2 autres messages seront reçus par le socket et donc, quand le callback sera fini (return True), il verra que le socket a des données et relancera le callback, mais cette fois le fd.recv (1024) contiendra les 2 messages concaténés, non? – Nolhian

+0

@Nolhian: bien sûr, votre protocole a certainement une sorte de délimiteur entre les messages. Vous devez donc scinder les messages vous-même et utiliser un tampon pour conserver les messages partiels jusqu'à ce que le reste du message n'arrive pas encore. Une autre alternative est d'utiliser 'tordu' http://twistedmatrix.com/ qui est un cadre de réseautage. Son mainloop est compatible avec gtk mainloop. – nosklo

+0

@nosklo: peut-on utiliser 'glib.io_add_watch' avec un socket lié attendant d'écouter? – Hibou57