author | Alberto Bertogli
<albertito@gmail.com> 2007-08-17 20:09:46 UTC |
committer | Alberto Bertogli
<albertito@gmail.com> 2007-08-17 20:09:46 UTC |
parent | a7d5a88148129685acfd0c2660f4e882444a9bb9 |
tcpmp.py | +99 | -0 |
diff --git a/tcpmp.py b/tcpmp.py new file mode 100644 index 0000000..448401e --- /dev/null +++ b/tcpmp.py @@ -0,0 +1,99 @@ + +""" +tcpmp - TCP Message Passing +Alberto Bertogli (albertito@gmail.com) +------------------------------------------ + +This module implements a bidirectional channel with the Channel class, which +allows you to send and receive python objects (as long as they're pickable) +between two hosts, using TCP. + +You should instance in each host, and then call .server() or .client(), +according to your status. Then you can begin sending and receiving objects +with .send() and .recv(). + +If the connection gets broken (one of the processes closes it or dies), send() +and recv() will raise a BrokenChannel exception, defined here. + +It should work under any Unix, Windows and Mac systems. +""" + +import os +import socket +import errno +import pickle + +default_port = 1642 + +class BrokenChannel (Exception): + "Exception raised when the channel gets broken." + pass + +class SockFD (object): + """File descriptor wrapper for socket objects. Implement .write(), + .read() and .readline(), which is what pickle needs to work.""" + + def __init__(self, sock): + self.sock = sock + self.fd = os.fdopen(sock.fileno()) + + def write(self, s): + self.sock.send(s) + + def read(self, size = -1): + if size == -1: + return self.fd.read() + return self.fd.read(size) + + def readline(self, size = -1): + return self.fd.readline(size) + + def close(self): + #self.sock.close() + self.fd.close() + + def __del__(self): + self.close() + + +class Channel (object): + "TCP message passing." + + def __init__(self): + self.sock = None + self.fd = None + + def __del__(self): + if self.fd: + self.fd.close() + + def client(self, ip, port = default_port): + "Tell the object we're the client." + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.connect((ip, port)) + self.fd = SockFD(s) + + def server(self, listen_ip = '0.0.0.0', port = default_port): + "Tell the object we're the server." + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.bind((listen_ip, port)) + s.listen(1) + conn, addr = s.accept() + self.fd = SockFD(conn) + + def send(self, o): + "Send an object." + try: + pickle.dump(o, self.fd, -1) + except (socket.error, EOFError), info: + self.fd.close() + raise BrokenChannel, info + + def recv(self): + "Receive an object." + try: + return pickle.load(self.fd) + except (socket.error, EOFError), info: + self.fd.close() + raise BrokenChannel, info +