Length-Type-Based Protocol Client/Server

May 31st, 2009

What: Adds a Twisted-based client and server for protocols which begin with a length and type field.

Where: http://pypi.python.org/pypi/ltprotocol

Contribute Ideas / Make Suggestions: Send a comment here

Source Code Repository: http://github.com/dound/ltprotocol

Sign up to receive emails about updates.

Installation:

  1. Install easy_install if you don’t already have it
  2. sudo easy_install ltprotocol
  • Alternatively, you can download the source (from here).
  • Alternatively, if you checkout the repository then install with sudo ./setup.py install

Description: Provides a Twisted-based client and server implementation for protocols which begin with a legnth and type field. Create your protocol by constructing an LTProtocol with a list of LTMessage objects which specify your protocol. Use LTTwistedServer and LTTwistedClient to create a server or client.

Example: This example was written for v0.2.0. A complete example can be downloaded here. To try it out, run:

python test_ltprotocol.py server
python test_ltprotocol.py client

To use it, you first define the messages in your protocol:

class NumMsg(LTMessage):
    @staticmethod
    def get_type():
        return 1
 
    def __init__(self, n):
        LTMessage.__init__(self)
        self.num = n
 
    def pack(self):
        return struct.pack("> I", self.num)
 
    @staticmethod
    def unpack(body):
        return NumMsg(struct.unpack("> I", body)[0])
 
    def __str__(self):
        return str(self.num)
 
class StrMsg(LTMessage):
    @staticmethod
    def get_type():
        return 2
 
    def __init__(self, s):
        LTMessage.__init__(self)
        self.str = s
 
    def pack(self):
        return struct.pack("> %us" % len(self.str), self.str)
 
    @staticmethod
    def unpack(body):
        return StrMsg(struct.unpack("> %us" % len(body), body)[0])
 
    def __str__(self):
        return self.str
 
TEST_PROTOCOL = LTProtocol([NumMsg, StrMsg], 'H', 'B')

When your client or server receives data, it posts a callback to a method you specify. For this example, I am going to use this helper function to simply print out the messages we receive:

def print_ltm(prefix, proto, ltm):
    print '%s got: %s' % (prefix, str(ltm))

You can also define callbacks for when a client or server gets connected or disconnected. In this example, the new connection callback is used to initiate the periodic sending of messages and a disconnect callback to print a simple message:

def periodic_send(proto):
    if c.connected:
        print 'sending ...'
        proto.send(NumMsg(200))
        proto.send(StrMsg("hello world!"))
        proto.send(NumMsg(7))
        reactor.callLater(1, lambda : periodic_send(proto))
 
def print_disconnect(proto):
    print 'disconnected!'

To create a client, I would do something like this (the second argument is the function to call when a complete message has arrived):

client = LTTwistedClient(TEST_PROTOCOL,
                         lambda p, m : print_ltm('client', p, m))
client.connect('127.0.0.1', 9999)

Likewise, to create a server I would do something like this (note that I specify the new connection and disconnection callback functions here; they could have been defined for the client instead in this case):

server = LTTwistedServer(TEST_PROTOCOL,
                         lambda p, m : print_ltm('server', p, m),
                         periodic_send,
                         print_disconnect)
server.listen(9999)