From 4843dede4add1764ced095ecf3e41ecc3a53240e Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Mon, 16 Jan 2012 16:42:17 +0000 Subject: Added networking compatible send/recv functions as helpers, plus a bunch of docs. --- python/client.py | 11 ++++++++++ python/gats.py | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++----- python/server.py | 18 ++++++++++++++++ 3 files changed, 90 insertions(+), 5 deletions(-) create mode 100755 python/client.py create mode 100755 python/server.py (limited to 'python') diff --git a/python/client.py b/python/client.py new file mode 100755 index 0000000..53e38fd --- /dev/null +++ b/python/client.py @@ -0,0 +1,11 @@ +#!/usr/bin/python + +import gats +import socket +import time + +s = socket.create_connection( ('localhost', 5051) ) +gats.send( {'type': 'hello'}, s ) +print gats.recv( s ) + +time.sleep( 10 ) diff --git a/python/gats.py b/python/gats.py index 7e66f52..760314a 100644 --- a/python/gats.py +++ b/python/gats.py @@ -1,18 +1,68 @@ + +"""Provides pickle-compatible functions for working with Gats packets. +Converts to and from normal python structures like dictionaries, lists, +tuples, booleans, strings, etc. + +This also provides a couple of helpers to make working with sockets a bit +easier, recv and send work with sockets in blocking mode.""" + import struct -from cStringIO import StringIO +from cStringIO import StringIO as _StringIO import math _scalarMagic = float.fromhex('0x1.62e42fefa39efp+2') +def recv( s ): + '''A helper that reads a single packet from the provided socket (s). The + socket should be in blocking mode for this to work correctly. This function + doesn't handle any exceptions, so if the socket closes while reading + handling the exception is up to you.''' + while True: + version = s.recv(1) + if len(version) == 0: + return None + version = ord(version[0]) + if version != 0: + break + + if version == 1: + sBuf = _StringIO() + iSize = 5 + buf = '' + while len(buf) < 4: + buf += s.recv(4-len(buf)) + iGoalSize = struct.unpack('>I', buf )[0] + while iSize < iGoalSize: + buf = s.recv( min(iGoalSize-iSize, 4096) ) + sBuf.write( buf ) + iSize += len(buf) + + sBuf.seek( 0 ) + return _readObj( sBuf ) + +def send( obj, s ): + '''A helper that sends the entire object (obj), in a Gats encoded packet to + the provided socket (s). This buffers the data first, so it should use + as few network packets as possible to send the data.''' + s.send( dumps( obj ) ) + def loads( sIn ): - return load( StringIO( sIn ) ) + '''Loads a complete Gats packet as described by the string sIn and returns + the contained object. The string can only contain one packet. Any data + after the first packet will simply be ignored.''' + return load( _StringIO( sIn ) ) def dumps( obj ): - sTmp = StringIO() + '''Returns the provided object (obj) as a complete Gats packet in a string, + since Gats encoded objects are not in plain text, it'll probably be useless + to print these strings out.''' + sTmp = _StringIO() dump( obj, sTmp ) return sTmp.getvalue() def load( sIn ): + '''Reads a single Gats packet (one object) from the provided file-like + object and returns it. If it can't read anything it returns None.''' # Scan for a valid packet header while True: version = sIn.read(1) @@ -27,7 +77,9 @@ def load( sIn ): return _readObj( sIn ) def dump( obj, sOut ): - sTmp = StringIO() + '''Writes the given object (obj) to the file-like object sOut as a complete + Gats packet.''' + sTmp = _StringIO() _writeObj( obj, sTmp ) sCore = sTmp.getvalue() sOut.write( struct.pack('>BI', 1, len(sCore)+5 ) ) @@ -152,7 +204,7 @@ def _writeObj( obj, sOut ): if iScale < 0: iScale -= 1 - sTmp = StringIO() + sTmp = _StringIO() d /= pow( 256.0, iScale ) sTmp.write( chr( int(d) ) ) @@ -175,6 +227,8 @@ def _writeObj( obj, sOut ): raise Exception('A type that is not gats-encodable was encountered: ' + str(type(obj))) def _readPackedInt( sIn ): + '''Internal helper function that reads an integer in packed format from the + provided file-like object and returns it.''' bNeg = False b = ord(sIn.read(1)[0]) @@ -191,6 +245,8 @@ def _readPackedInt( sIn ): return rOut def _writePackedInt( iIn, sOut ): + '''Internal helper function that writes an integer in packed format to the + provided file-like object.''' if iIn < 0: iIn = -iIn b = iIn&0x3F diff --git a/python/server.py b/python/server.py new file mode 100755 index 0000000..c36f073 --- /dev/null +++ b/python/server.py @@ -0,0 +1,18 @@ +#!/usr/bin/python + +import gats +import socket +import time + +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) +s.bind(('', 5051)) +s.listen(1) +conn, addr = s.accept() +print 'Connected by', addr +while 1: + print 'Reading...' + obj = gats.recv( conn ) + print 'Read',obj + gats.send( {'recvAddr': addr, 'recvTime': time.time(), 'recvObj': obj }, conn ) +conn.close() -- cgit v1.2.3