Unless you're in total control over both the client and server software, you should hesitate to use pickle to transmit data back and forth. Pickle is great if you're sure the data you're unpickling is trustworthy, but if it might have been tampered with, it is insecure. See Why Python Pickle is Insecure, or the security cautionary suggestions in the pickle module documentation.
JSON is a good choice for formatting of data to send back and forth; XML is okay, YAML is pretty good. A simple messaging format might be to send the size of the message data, a delimiter (CRLF
or \r\n
is common) and then the message data.
If you use JSON, you'll have to either stick with the objects the json
module knows how to encode/decode, or write JSONEncoder
and JSONDecoder
subclasses to deal with the types you're interested in.
Below is a little JSON proof of concept you can run (not sure if it would work on Windows or not). Just run it in each of two terminals, type in one and it should show up in the other.
import socket
import select
import sys
import json
CRLF = '\r\n'
class MalformedMessage(Exception): pass
class ConnectionClosed(Exception): pass
def read_exactly(sock, buflen):
data = ''
while len(data) != buflen:
data += sock.recv(buflen - len(data))
return data
def peek(sock, buflen):
data = sock.recv(buflen, socket.MSG_PEEK)
return data
def socket_send(sock, obj):
data = json.dumps(obj)
size = len(data)
sock.sendall('%i%s%s' % (size, CRLF, data))
def socket_recv(sock):
peekdata = peek(sock, 1024)
if peekdata == '':
raise ConnectionClosed
sizepos = peekdata.find(CRLF)
if sizepos == -1:
raise MalformedMessage('Did not find CRLF in message %r' % peekdata)
sizedata = read_exactly(sock, sizepos)
read_exactly(sock, len(CRLF))
try:
size = int(sizedata)
except ValueError:
raise MalformedMessage(
'size data %r could not be converted to an int' % sizedata)
data = read_exactly(sock, size)
return json.loads(data)
if __name__ == '__main__':
netloc = ('', 7777)
try:
servsock = socket.socket()
servsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
servsock.bind(netloc)
servsock.listen(5)
sock, _ = servsock.accept()
except socket.error:
sock = socket.socket()
sock.connect(netloc)
try:
while True:
r_ok, _, _ = select.select([sys.stdin, sock], [], [])
for fd in r_ok:
if fd == sys.stdin:
obj = eval(fd.readline().strip())
socket_send(sock, obj)
elif fd == sock:
obj = socket_recv(sock)
print repr(obj)
except (KeyboardInterrupt, ConnectionClosed):
pass
finally:
print '\nexiting...'