Problems with a chat program written in Python and PyGTK
Question: I am new to python and I am currently working on a chat room program in Python
(still in progress...). I have also made a GUI for my program. Initially, I
made two py files, one for the GUI and one for the chatting function. They
both worked perfectly when separated. After, I combined the two files. I faced
the following two problems:

  1. One of my threads (`target = loadMsg`) is used to wait for the host's msg and print it out on the screen. The problem is that it delays for one msg every time. For example, I sent a "1" to the host and the host should return a "1" immediately. But, the "1" I received didn't appear on my screen. Then I send a "2" to the host and the host should reply a "2" immediately. Then, my screen shows a "1" but the "2" is still missing until the host reply a "3" to me, after I send a "3" to the host. Where is the problem?

  2. This is a technical problem. I was testing the stability of the chat room and I found that about 10% of my msg disappeared during the transmission and this situation occurs randomly. How can I fix such a problem? Sorry for my poor English. I hope someone can help me with it.T_T

Here is my code for your reference: \---Client

    
    
    import pygtk,gtk
    import logging
    from threading import *
    import socket
    
    DEBUG = 1
    HOST = ''
    PORT = 8018
    TIMEOUT = 5
    BUF_SIZE = 1024
    
    class Base():
        def reload(self):
            try:
                buf = self.sock.recv(BUF_SIZE)
                print buf
                self.addMsg(buf)
            except:
                pass
        def reload_butt(self,widget):
            try:
                self.thread = Thread(target=self.reload)
                self.thread.start()
            except:
                pass
    
        def loadMsg(self):
            try:
                while True :
                        buf = self.sock.recv(BUF_SIZE)
                    print buf
                    self.addMsg(buf)
                except:
                        self.sock.close()
        def sendMsg(self,widget):
            if DEBUG : print "Send Msg"
            if self.entry.get_text() : self.sock.send(self.entry.get_text())
                self.entry.set_text("")
        def addMsg(self,string):
            if DEBUG : print "Try to add Msg"
            if self.entry.get_text() :
                iter = self.buffer1.get_iter_at_offset(-1)
                self.buffer1.insert(iter,("\n Username: "+string))
                self.entry.set_text("")
                self.adj = self.scrolled_window.get_vadjustment()
                self.adj.set_value( self.adj.upper - self.adj.page_size )
                if DEBUG : print "Add msg ok"
        def destroy(self,widget):
            if DEBUG : print "Destroy function called"
            self.sock.close() 
            gtk.main_quit()
    
        def __init__(self,sock):
            if DEBUG : print "Initializing..."
            self.sock = sock
    
            self.win=gtk.Window()
            self.win.connect("destroy",self.destroy)
    
            self.vbox=gtk.VBox()
            self.win.add(self.vbox)
    
            self.view=gtk.TextView()
            self.view.set_editable(False)
            self.buffer1=self.view.get_buffer()
    
            self.scrolled_window=gtk.ScrolledWindow()
            self.scrolled_window.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC)
            self.scrolled_window.add(self.view)
            self.vbox.add(self.scrolled_window)
    
            self.entry=gtk.Entry()
            self.entry.connect("activate",self.sendMsg)
    
            self.enter=gtk.Button("Enter")
            self.enter.connect("clicked",self.sendMsg)
    
            self.reload=gtk.Button("Reload")
            self.reload.connect("clicked",self.reload_butt)
    
            self.hbox=gtk.HBox()
            self.hbox.add(self.entry)
            self.hbox.pack_start(self.reload,False,False)
            self.hbox.pack_start(self.enter,False,False)
            self.vbox.pack_start(self.hbox,False,False)
    
            self.win.show_all()
            if DEBUG : print "Finish initializing"
        def main(self):
            try :
                gtk.main()
            except :
    
                print "Error!!!"
    def main() :
        try :
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
            sock.connect((HOST, PORT)) 
            print ('Connecting to '+ str(HOST) +' ' + str(PORT)) 
            base=Base(sock)
            thread1=Thread(target=base.loadMsg)
            thread2=Thread(target=base.main)
            thread2.start()
            thread1.start()
        except :
            print "Err0r!!!"
            sock.close()
    main()
    

\---host (an echo host)

    
    
    import socket
    
    HOST = ''
    PORT = 8018
    
    
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.bind((HOST, PORT))
    s.listen(5)
    
    
    conn, addr = s.accept() 
    print 'Connected by', addr
    try :
        print "Start!"
        while True:
            data = conn.recv(1024)
                print data
            reply = data # echo
            if not reply : break
                if reply== "!q" : 
                        conn.close()
                break   
    
            conn.send(reply)
        conn.close()
    except :
        print "Error!!!!!"
        conn.close()
    


Answer: I would seriously recommend to use the gio library (part of glib). Using that
library, you connect functions to the socket operations such as when data is
available, or when data can be written to the socket. The library will call
these function when necessary, and you don't need a wait loop. Which is more
CPU-friendly.

<http://jcoppens.com/soft/howto/gtk/chat_socket.php> contains an example of
communications between a C program and Python, using gio, which might be
useful to you.

This way, you can start monitoring the sockets after the GUI has started, and
you do not need threads to attend the communications.

