Examples

Packetized TCP Server and Client

The following example shows an example of a protocol on TCP which has a length field and a payload of length bytes. With Suitcase, we only need to declare the basic structure of the message and we get a packer and a stream protocol handler out of the library with very little effort.

Since the protocol definition is declarative, it is easy to see what the structure of packets is. The definition of the protocol is shared between the client and the server. For the server portion, we can use SocketServer from the standard library in order to accept connections. Suitcase has no special support for any networking libraries, so you are free to use it with other network libraries like twisted, gevent, etc. as you please.

import sys
import socket

from six.moves import socketserver
from suitcase.protocol import StreamProtocolHandler
from suitcase.structure import Structure
from suitcase.fields import UBInt16, LengthField, Payload, UBInt8

FRAME_TYPE_ECHO_REQUEST = 0x00
FRAME_TYPE_ECHO_RESPONSE = 0x10


class EchoProtocolFrame(Structure):
    frame_type = UBInt8()
    payload_length = LengthField(UBInt16())
    payload = Payload(payload_length)


class EchoTCPHandler(socketserver.BaseRequestHandler):
    def _frame_received(self, request_frame):
        # frame is an instance of EchoProtocolFrame
        print("Received %r" % request_frame)
        if request_frame.frame_type == FRAME_TYPE_ECHO_REQUEST:
            response = EchoProtocolFrame()
            response.frame_type = FRAME_TYPE_ECHO_RESPONSE
            response.payload = "You sent %r" % request_frame.payload
            self.request.sendall(response.pack())
        else:
            print("Unexpected frame: %r" % request_frame)

    def setup(self):
        self.handler = StreamProtocolHandler(EchoProtocolFrame, self._frame_received)

    def handle(self):
        while True:
            self.handler.feed(self.request.recv(1024))


def client():
    def message_received(frame):
        print(frame)

    s = socket.socket()
    s.connect(('127.0.0.1', 7070))
    proto_handler = StreamProtocolHandler(EchoProtocolFrame, message_received)
    while True:
        input = raw_input("Data to send: ")
        request = EchoProtocolFrame()
        request.frame_type = FRAME_TYPE_ECHO_REQUEST
        request.payload = input
        s.sendall(request.pack())

        # to handle asynchronous messages, this would be done asynchronously
        proto_handler.feed(s.recv(1024))


if __name__ == '__main__':
    if len(sys.argv) != 2:
        print("Usage Client: %s -c" % sys.argv[0])
        print("Usage Server: %s -s" % sys.argv[1])
    if sys.argv[1] == '-c':
        client()
    elif sys.argv[1] == '-s':
        server = socketserver.TCPServer(('0.0.0.0', 7070), EchoTCPHandler)
        server.serve_forever()