09/04/2008

asyncore, asynchat and pickle

A little demo I did for spike using asycore and asynchat that sends pickles around.

(yes the delimiter sucks, and i could really not of used asynchat at all... :)

easymsg.py ------------------------------------------------------------------
import asyncore, asynchat
import os, socket, string
import pickle

PORT = 8000

class EasyMsgRequest(asyncore.dispatcher):

    def __init__(self, host, obj, port=PORT):
        asyncore.dispatcher.__init__(self)
        self.obj = obj
        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
        self.connect((host, port))

    def handle_connect(self):
        self.send(pickle.dumps(self.obj)+'\r\n')
        self.close()

    def handle_expt(self):
        self.close()

    def handle_close(self):
        self.close()


class EasyMsgChannel(asynchat.async_chat):

    def __init__(self, server, sock, addr):
        asynchat.async_chat.__init__(self, sock)
        self.set_terminator("\r\n")
        self.data = ""
        self.server = server

    def collect_incoming_data(self, data):
        self.data = self.data + data

    def found_terminator(self):
        obj = pickle.loads(self.data)
        self.route(obj)

    def route(self, obj):
        print "dont know how to route %s" % str(obj)


class EasyMsgServer(asyncore.dispatcher):

    channel_class = EasyMsgChannel

    def __init__(self, port=PORT):
        asyncore.dispatcher.__init__(self)
        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
        self.bind(("", port))
        self.listen(5)

    def handle_accept(self):
        con, addr = self.accept()
        self.create_channel(con, addr)
    
    def create_channel(self, con, addr):
        self.channel_class(self, con, addr)


client.py ------------------------------------------------------------------
import asyncore
from easymsg import EasyMsgRequest, PORT
from code import InteractiveConsole

def sender(host, port=PORT):
    def send(obj):
        req = EasyMsgRequest(host, obj, port=port)
        asyncore.loop()
    return send

if __name__ == '__main__':
    import sys
    import readline

    if len(sys.argv) < 2:
        print "usage: client.py  []"
        sys.exit(1)

    try:
        port = int(sys.argv[2])
    except (IndexError, ValueError):
        port = PORT

    v = globals().copy()
    v['s'] = v['send'] = sender(sys.argv[1], port)
    console = InteractiveConsole(v)
    console.interact()

server.py ------------------------------------------------------------------
import asyncore
from easymsg import EasyMsgServer, PORT

if __name__ == '__main__':
    import sys
    try:
        port = int(sys.argv[1])
    except (IndexError, ValueError):
        port = PORT
    s = EasyMsgServer(port)
    print "serving..."
    asyncore.loop()

forwarder.py ------------------------------------------------------------------
from easymsg import EasyMsgServer, EasyMsgChannel, EasyMsgRequest, PORT

class ForwarderChannel(EasyMsgChannel):
    def route(self, obj):
        server = self.server
        print "forwarding %s" % str(obj)
        EasyMsgRequest(server.dest_host, obj, port=server.dest_port)


class ForwarderServer(EasyMsgServer):
    
    channel_class = ForwarderChannel

    def __init__(self, dest_host, dest_port=PORT, port=PORT):
        self.dest_host = dest_host
        self.dest_port = dest_port
        EasyMsgServer.__init__(self, port)


if __name__ == '__main__':
    import sys
    import asyncore

    try:
        dest_host = sys.argv[1]
        dest_port = int(sys.argv[2])
    except (IndexError, ValueError):
        print "usage: forwarder.py   []"
        sys.exit(1)
    try:
        port = int(sys.argv[3])
    except (IndexError, ValueError):
        port = PORT
    s = ForwarderServer(dest_host, dest_port, port)
    print "serving..."
    asyncore.loop()

No comments: