0

I am trying to send multiple strings using the socket.send() and socket.recv() function.

I am building a client/server, and "in a perfect world" would like my server to call the socket.send() function a maximum of 3 times (for a certain server command) while having my client call the socket.recv() call 3 times. This doesn't seem to work the client gets hung up waiting for another response.

server:

        clientsocket.send(dir)
        clientsocket.send(dirS)
        clientsocket.send(fileS)

client

response1 = s.recv(1024)
if response1:
    print "\nRecieved response: \n" , response1
response2 = s.recv(1024)
if response2:
    print "\nRecieved response: \n" , response2
response3 = s.recv(1024)
if response3:
    print "\nRecieved response: \n" , response3

I was going through the tedious task of joining all my strings together then reparsing them in the client, and was wondering if there was a more efficient way of doing it?

edit: My output of response1 gives me unusual results. The first time I print response1, it prints all 3 of the responses in 1 string (all mashed together). The second time I call it, it gives me the first string by itself. The following calls to recv are now glitched/bugged and display the 2nd string, then the third string. It then starts to display the other commands but as if it was behind and in a queue.

Very unusual, but I will likely stick to joining the strings together in the server then parsing them in the client

Greg
  • 103
  • 2
  • 9

3 Answers3

2

You wouldn't send bytes/strings over a socket like that in a real-world app.

You would create a messaging protocol on-top of the socket, then you would put your bytes/strings in messages and send messages over the socket.

You probably wouldn't create the messaging protocol from scratch either. You'd use a library like nanomsg or zeromq.

server

from nanomsg import Socket, PAIR
sock = Socket(PAIR)
sock.bind('inproc://bob')
sock.send(dir)
sock.send(dirS)
sock.send(fileS)

client

from nanomsg import Socket, PAIR
sock = Socket(PAIR)
sock.bind('inproc://bob')
response1 = sock.recv()
response2 = sock.recv()
response3 = sock.recv()

In nanomsg, recv() will return exactly what was sent by send() so there is a one-to-one mapping between send() and recv(). This is not the case when using lower-level Python sockets where you may need to call recv() multiple times to get everything that was sent with send().

Jay
  • 9,314
  • 7
  • 33
  • 40
1

TCP is a streaming protocol and there are no message boundaries. Whether a blob of data was sent with one or a hundred send calls is unknown to the receiver. You certainly can't assume that 3 sends can be matched with 3 recvs. So, you are left with the tedious job of reassembling fragments at the receiver.

One option is to layer a messaging protocol on top of the pure TCP stream. This is what zeromq does, and it may be an option for reducing the tedium.

tdelaney
  • 73,364
  • 6
  • 83
  • 116
1

The answer to this has been covered elsewhere.

There are two solutions to your problem.

Solution 1: Mark the end of your strings. send(escape(dir) + MARKER) Your client then keeps calling recv() until it gets the end-of-message marker. If recv() returns multiple strings, you can use the marker to know where they start and end. You need to escape the marker if your strings contain it. Remember to escape on the client too.

Solution 2: Send the length of your strings before you send the actual string. Your client then keeps calling recv() until its read all the bytes. If recv() returns multiple strings. You know where they start and end since you know how long they are. When sending the length of your string, make you you use a fixed number of bytes so you can distinguish the string lenght from the string in the byte stream. You will find struct module useful.

Community
  • 1
  • 1
Jay
  • 9,314
  • 7
  • 33
  • 40