4

Using sockets in python3.x I want to send the content of a dictionary over a socket, which for some reasons is NOT answered by the link just above this line...

client.py:

a = {'test':1, 'dict':{1:2, 3:4}, 'list': [42, 16]}
bytes = foo(a)
sock.sendall(bytes)

server.py:

bytes = sock.recv()
a = bar(bytes)
print(a)

How to convert any dictionary to a sequence of bytes (to be able to be sent through a socket) and how to be converted back? I prefer a clean and simple way to do this.

What I have tried so far:

sock.sendall(json.dumps(data))
TypeError: 'str' does not support the buffer interface

sock.sendall(bytes(data, 'UTF-8'))
TypeError: encoding or errors without a string argument

data = sock.recv(100)
a= data.decode('UTF-8')
AttributeError: 'str' object has no attribute 'decode'
Alex
  • 41,580
  • 88
  • 260
  • 469
  • 3
    What about serializing it to JSON? https://docs.python.org/2/library/json.html Would it be sufficient for your needs or do you need to transfer more than just lists, dicts, strings, True/False/None and ints/floats? – Messa May 26 '14 at 19:35
  • Looks like a dupe of http://stackoverflow.com/questions/15190362/sending-a-dictionary-using-sockets-in-python – dano May 26 '14 at 19:41
  • This does not seem to work. I tried `sock.sendall(json.dumps(data))` with data being a `dict` and got an error `TypeError: 'str' does not support the buffer interface`. – Alex May 26 '14 at 19:42
  • For that `TypeError`, see http://stackoverflow.com/questions/5471158/typeerror-str-does-not-support-the-buffer-interface – dano May 26 '14 at 19:43
  • @dano: Well, because of that error I posted my question in the first place. The solution in the link you posted also does not work, because of an error `AttributeError: 'str' object has no attribute 'decode'`. – Alex May 26 '14 at 19:44

1 Answers1

12

This is primarily summarizing the comments, but you need to convert the dict to a json str object, convert that str object to a bytes object by encoding it, and then send that over the socket. On the server-side, you need to decode the bytes object sent over the socket back to a str, and then use json.loads to turn it back into a dict.

Client:

b = json.dumps(a).encode('utf-8')
s.sendall(b)

Server:

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('localhost', 1234))
s.listen(1)
conn, addr = s.accept()
b = b''
while 1:
    tmp = conn.recv(1024)
    b += tmp
d = json.loads(b.decode('utf-8'))
print(d)
dano
  • 91,354
  • 19
  • 222
  • 219
  • Well, I cannot test your suggestion as I now (after simplifying my scipt) get an error `OSError: [Errno 107] Transport endpoint is not connected`. – Alex May 26 '14 at 20:07
  • 1
    @Alex, that's a separate problem. I'll expand my server-side example code which will probably reveal your error. My guess is you're using the original `socket` object to call `recv` instead of the one returned by `sock.accept`. – dano May 26 '14 at 20:08
  • Ok, I rewrote my whole proof-of-concept example AGAIN, and your suggestion works! But what do I do if the object to receive is larger than 1024 bytes? I can read the byte bits in a while loop which gets added to an empty string? I might need create an empty byte variable or something. Or just increase the number of bytes to receive in `recv` to something really big? – Alex May 26 '14 at 20:15
  • 1
    @Alex, You can make the buffer larger if you know there's going to be some limit on the size of the dict you send. Otherwise you do the recv in a while loop, like you said. the Python documentation for `socket` shows that in action: https://docs.python.org/2/library/socket.html#example – dano May 26 '14 at 20:18
  • 1
    The link you posted does no show an example of reading data from `recv` and 'adding' them together. If the data rom `recv` ist just text (like in python 2.x) this is very easy, as you initialize an empty string. But for python 3.x you need to initialize an empty byte object or something... – Alex May 26 '14 at 20:21
  • 1
    @Alex, right. Luckily, making an empty `byte` is easy. See my edit. – dano May 26 '14 at 20:23