diff options
author | Mike Buland <eichlan@xagasoft.com> | 2012-01-16 16:42:17 +0000 |
---|---|---|
committer | Mike Buland <eichlan@xagasoft.com> | 2012-01-16 16:42:17 +0000 |
commit | 4843dede4add1764ced095ecf3e41ecc3a53240e (patch) | |
tree | cea32f881e5760dd417e3e8a0eaf2b3b15ecd32e /python | |
parent | dfeb2636eb83098ebd621ce2add83ef9e256318f (diff) | |
download | libgats-4843dede4add1764ced095ecf3e41ecc3a53240e.tar.gz libgats-4843dede4add1764ced095ecf3e41ecc3a53240e.tar.bz2 libgats-4843dede4add1764ced095ecf3e41ecc3a53240e.tar.xz libgats-4843dede4add1764ced095ecf3e41ecc3a53240e.zip |
Added networking compatible send/recv functions as helpers, plus a bunch of
docs.
Diffstat (limited to 'python')
-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() | ||