Python networking client, trying to respond to server responses
Question: The application is a WxPython client/server setup that has multiple clients
connect to the server and engaging in duplex networking protocol.

I've had Twisted hooked up with AMP in the past, but it did not fully cut it
for the architecture in the application without overly complicating things in
the end.

So for the server I have got SocketServer with the ThreadingMixIn set up. At
the moment I am working on the buffer/command queue for the server, but that's
not the issue.

On the client side I can do all the normal sending of data, triggered by
events in the UI, without too much problems. I am currently stuck trying to
get the client to listen for responses without blocking the entire
application. So I want to put this in a thread, but should it start at the
part that's now commented out or should it be handled completely different and
I am just not seeing it?

In short: I want the client to send commands to the server and listen for any
responses without blocking/stalling the entire application.

The code below is prototyping code, please excuse any typical mistakes such as
magical values and other hardcoded data, it will be different in the final
code.

    
    
    import socket
    import threading
    import time
    
    
    class CommandProxy(object):
        def __init__(self, host, port):
            self.host = host
            self.port = port
    
        def close(self):
            if self.connection:
                self.connection.close()
    
        def connect(self):
            try:
                self.connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                self.connection.connect((self.host, self.port))
            except socket.error as e:
                print "Socket error: {0}".format(e)
    
        def send_command(self, command, *kw):
            datalist = ' '.join(kw)
            data = command + ' ' + datalist + '\x00'
    
            print 'DATA: {0}'.format(data)
    
            self._write(data)
    
    #        while True:
    #            data = self._read()
    #            if data == 0:
    #                break
    #
    #        print "DATA RECEIVED: {0}".format(data)
    
        def _read(self):
            data = self.connection.recv(1024)
            return data
    
        def _write(self, bytes):
            self.connection.sendall(bytes)
    
    
    if __name__ == '__main__':
        HOST, PORT = 'localhost', 1060
    
        proxy = CommandProxy(HOST, PORT)
        proxy.connect()
        try:
            while True:
                proxy.send_command('ID', '1')
                time.sleep(2)
    
        except KeyboardInterrupt:
            print "Interrupted by user"
        except socket.error as e:
            print "Socket error: {0}".format(e)
        except Exception as e:
            print "something went wrong: {0}".format(e)
        finally:
            proxy.close()
    


Answer: I think you're mistaken about whether a single-threaded or multi-threaded
approach will complicate your application more or less. The problem you're
wrestling with now is one of the many that (for example) Twisted solves for
you out of the box.

The most common complaint people have about Twisted is that it makes them
structure their code strangely, in a way they're not used to. However, when
you're using a GUI library like wxPython, you have already accepted this
constraint. Twisted's event-driven architecture is exactly like the event-
driven architecture of all the popular GUI toolkits. As long as you keep using
wxPython, also using Twisted isn't going to force you to do anything **else**
you don't want to do.

On the other hand, switching to threads will mean you need to be very careful
about access to shared data structures, you won't be able to unit test
effectively, and many problems that arise will only do so when someone else is
running your application - because they have a different number of cores than
you, or their network has different latency characteristics, or any of a
number of other things which cause your threaded code to run in ways you never
experienced. With extreme care you can still write something that works, but
it will be much more difficult.

Since you haven't posted any of your Twisted-based code here, I can't really
give any specific advice on how to keep things as simple as possible. However,
I recommend that you take another look at a non-threaded solution. Join the
twisted-python@twistedmatrix.com mailing list, hop on #twisted on freenode, or
post more stackoverflow questions about it. Lots of people will be eager to
help. :)

