diff options
| -rwxr-xr-x | python/client.py | 11 | ||||
| -rw-r--r-- | python/gats.py | 66 | ||||
| -rwxr-xr-x | python/server.py | 18 |
3 files changed, 90 insertions, 5 deletions
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 @@ | |||
| 1 | #!/usr/bin/python | ||
| 2 | |||
| 3 | import gats | ||
| 4 | import socket | ||
| 5 | import time | ||
| 6 | |||
| 7 | s = socket.create_connection( ('localhost', 5051) ) | ||
| 8 | gats.send( {'type': 'hello'}, s ) | ||
| 9 | print gats.recv( s ) | ||
| 10 | |||
| 11 | 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 @@ | |||
| 1 | |||
| 2 | """Provides pickle-compatible functions for working with Gats packets. | ||
| 3 | Converts to and from normal python structures like dictionaries, lists, | ||
| 4 | tuples, booleans, strings, etc. | ||
| 5 | |||
| 6 | This also provides a couple of helpers to make working with sockets a bit | ||
| 7 | easier, recv and send work with sockets in blocking mode.""" | ||
| 8 | |||
| 1 | import struct | 9 | import struct |
| 2 | from cStringIO import StringIO | 10 | from cStringIO import StringIO as _StringIO |
| 3 | import math | 11 | import math |
| 4 | 12 | ||
| 5 | _scalarMagic = float.fromhex('0x1.62e42fefa39efp+2') | 13 | _scalarMagic = float.fromhex('0x1.62e42fefa39efp+2') |
| 6 | 14 | ||
| 15 | def recv( s ): | ||
| 16 | '''A helper that reads a single packet from the provided socket (s). The | ||
| 17 | socket should be in blocking mode for this to work correctly. This function | ||
| 18 | doesn't handle any exceptions, so if the socket closes while reading | ||
| 19 | handling the exception is up to you.''' | ||
| 20 | while True: | ||
| 21 | version = s.recv(1) | ||
| 22 | if len(version) == 0: | ||
| 23 | return None | ||
| 24 | version = ord(version[0]) | ||
| 25 | if version != 0: | ||
| 26 | break | ||
| 27 | |||
| 28 | if version == 1: | ||
| 29 | sBuf = _StringIO() | ||
| 30 | iSize = 5 | ||
| 31 | buf = '' | ||
| 32 | while len(buf) < 4: | ||
| 33 | buf += s.recv(4-len(buf)) | ||
| 34 | iGoalSize = struct.unpack('>I', buf )[0] | ||
| 35 | while iSize < iGoalSize: | ||
| 36 | buf = s.recv( min(iGoalSize-iSize, 4096) ) | ||
| 37 | sBuf.write( buf ) | ||
| 38 | iSize += len(buf) | ||
| 39 | |||
| 40 | sBuf.seek( 0 ) | ||
| 41 | return _readObj( sBuf ) | ||
| 42 | |||
| 43 | def send( obj, s ): | ||
| 44 | '''A helper that sends the entire object (obj), in a Gats encoded packet to | ||
| 45 | the provided socket (s). This buffers the data first, so it should use | ||
| 46 | as few network packets as possible to send the data.''' | ||
| 47 | s.send( dumps( obj ) ) | ||
| 48 | |||
| 7 | def loads( sIn ): | 49 | def loads( sIn ): |
| 8 | return load( StringIO( sIn ) ) | 50 | '''Loads a complete Gats packet as described by the string sIn and returns |
| 51 | the contained object. The string can only contain one packet. Any data | ||
| 52 | after the first packet will simply be ignored.''' | ||
| 53 | return load( _StringIO( sIn ) ) | ||
| 9 | 54 | ||
| 10 | def dumps( obj ): | 55 | def dumps( obj ): |
| 11 | sTmp = StringIO() | 56 | '''Returns the provided object (obj) as a complete Gats packet in a string, |
| 57 | since Gats encoded objects are not in plain text, it'll probably be useless | ||
| 58 | to print these strings out.''' | ||
| 59 | sTmp = _StringIO() | ||
| 12 | dump( obj, sTmp ) | 60 | dump( obj, sTmp ) |
| 13 | return sTmp.getvalue() | 61 | return sTmp.getvalue() |
| 14 | 62 | ||
| 15 | def load( sIn ): | 63 | def load( sIn ): |
| 64 | '''Reads a single Gats packet (one object) from the provided file-like | ||
| 65 | object and returns it. If it can't read anything it returns None.''' | ||
| 16 | # Scan for a valid packet header | 66 | # Scan for a valid packet header |
| 17 | while True: | 67 | while True: |
| 18 | version = sIn.read(1) | 68 | version = sIn.read(1) |
| @@ -27,7 +77,9 @@ def load( sIn ): | |||
| 27 | return _readObj( sIn ) | 77 | return _readObj( sIn ) |
| 28 | 78 | ||
| 29 | def dump( obj, sOut ): | 79 | def dump( obj, sOut ): |
| 30 | sTmp = StringIO() | 80 | '''Writes the given object (obj) to the file-like object sOut as a complete |
| 81 | Gats packet.''' | ||
| 82 | sTmp = _StringIO() | ||
| 31 | _writeObj( obj, sTmp ) | 83 | _writeObj( obj, sTmp ) |
| 32 | sCore = sTmp.getvalue() | 84 | sCore = sTmp.getvalue() |
| 33 | sOut.write( struct.pack('>BI', 1, len(sCore)+5 ) ) | 85 | sOut.write( struct.pack('>BI', 1, len(sCore)+5 ) ) |
| @@ -152,7 +204,7 @@ def _writeObj( obj, sOut ): | |||
| 152 | if iScale < 0: | 204 | if iScale < 0: |
| 153 | iScale -= 1 | 205 | iScale -= 1 |
| 154 | 206 | ||
| 155 | sTmp = StringIO() | 207 | sTmp = _StringIO() |
| 156 | 208 | ||
| 157 | d /= pow( 256.0, iScale ) | 209 | d /= pow( 256.0, iScale ) |
| 158 | sTmp.write( chr( int(d) ) ) | 210 | sTmp.write( chr( int(d) ) ) |
| @@ -175,6 +227,8 @@ def _writeObj( obj, sOut ): | |||
| 175 | raise Exception('A type that is not gats-encodable was encountered: ' + str(type(obj))) | 227 | raise Exception('A type that is not gats-encodable was encountered: ' + str(type(obj))) |
| 176 | 228 | ||
| 177 | def _readPackedInt( sIn ): | 229 | def _readPackedInt( sIn ): |
| 230 | '''Internal helper function that reads an integer in packed format from the | ||
| 231 | provided file-like object and returns it.''' | ||
| 178 | bNeg = False | 232 | bNeg = False |
| 179 | 233 | ||
| 180 | b = ord(sIn.read(1)[0]) | 234 | b = ord(sIn.read(1)[0]) |
| @@ -191,6 +245,8 @@ def _readPackedInt( sIn ): | |||
| 191 | return rOut | 245 | return rOut |
| 192 | 246 | ||
| 193 | def _writePackedInt( iIn, sOut ): | 247 | def _writePackedInt( iIn, sOut ): |
| 248 | '''Internal helper function that writes an integer in packed format to the | ||
| 249 | provided file-like object.''' | ||
| 194 | if iIn < 0: | 250 | if iIn < 0: |
| 195 | iIn = -iIn | 251 | iIn = -iIn |
| 196 | b = iIn&0x3F | 252 | 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 @@ | |||
| 1 | #!/usr/bin/python | ||
| 2 | |||
| 3 | import gats | ||
| 4 | import socket | ||
| 5 | import time | ||
| 6 | |||
| 7 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | ||
| 8 | s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) | ||
| 9 | s.bind(('', 5051)) | ||
| 10 | s.listen(1) | ||
| 11 | conn, addr = s.accept() | ||
| 12 | print 'Connected by', addr | ||
| 13 | while 1: | ||
| 14 | print 'Reading...' | ||
| 15 | obj = gats.recv( conn ) | ||
| 16 | print 'Read',obj | ||
| 17 | gats.send( {'recvAddr': addr, 'recvTime': time.time(), 'recvObj': obj }, conn ) | ||
| 18 | conn.close() | ||
