0

I have a simple server-client program:

In server.py:

import socket

server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

server_socket.bind(("127.0.0.1", 1234))
server_socket.listen()
connection_socket, address = server_socket.accept()

with connection_socket:
    data = connection_socket.recv(1000)
    connection_socket.send(bytearray([0x0]))
    print(data)


server_socket.close()

And in client.py:

import socket

client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

client_socket.connect(("127.0.0.1", 1234))
client_socket.send(bytearray([0x0, 0x1, 0x2]))
print(client_socket.recv(1))
client_socket.send(bytearray([0x3, 0x4, 0x5]))

client_socket.close()

Here's what I think is going on:

What I know of the TCP protocol is that it is "stream-based". I've read here that recv blocks IO until my request of 1000 bytes has been fulfilled. This is seemingly interrupted by the send made by the server or the recv made by the client. The following 3 bytes go unreceived.

Are these correct assumptions? If not, what is really going on here?

Thanks in advance for your help!

Scene
  • 489
  • 4
  • 16
  • As a stream protocol you can't make any assumptions about how much data is sent or received in a single call. Your recv may return with only a single byte or many. recv is really reading from a kernel buffer that is being filled by TCP in the bacground. Your send may only send some of the bytes you asked (you need to check the count it returns or use sendall) but that "send" really only sends it to the kernel where it may be buffered and sent in multiple segments later on. – tdelaney Aug 15 '21 at 05:32
  • 1
    In the question that you reference, look down the comments of the accepted answer: _Amazing that the 51 people who upvoted this aren't aware this does not work, even worse that the OP marked this answer as correct._. That answer is not correct. – tdelaney Aug 15 '21 at 05:37
  • Stream based means the data start with byte 0 and ends after the last byte with the EOF condition. You should not make any assumptions how is this stream divided into "chunks" that are stored in buffers, transferred over the network or returned by `recv`. – VPfB Aug 15 '21 at 06:52

1 Answers1

2

I've read here that recv blocks IO until my request of 1000 bytes has been fulfilled.

Which is wrong. recv blocks until at least one byte is received. The number given just specifies the maximum number of bytes which should be read, i.e. neither the exact number nor the minimum number.

The following 3 bytes go unreceived.

It is likely that in this specific case the 1000 bytes are received at once, leaving 3 bytes unread. This is different though if larger amounts of data are send, especially over links with low MTU (i.e. local network, WiFi vs. localhost traffic). Here it can be seen that only parts of the expected data are received during a single recv.

Even the assumption that send will send all given data is wrong: send will only send at most the given data. One needs to actually check the return value to see how much actually got send. Use sendall instead if you want to have everything send.

Can I say that socket.send() “flushed”/“resets” the TCP stream here?

No. send and recv work only on the socket write and read buffers. They don't actually cause a sending or receiving. This is done by the OS instead. A send just puts the data into the sockets write buffer and the OS will eventually transmit this data. This transmission is not in all cases done immediately though. If there are outstanding unacknowledged data the sending might get deferred until the data are acknowledged (details depend on the TCP window). If only few data are in the buffer the OS might wait a while for the application to call send with more data in order to keep the transmission overhead low (NAGLE algorithm).

Thus the phrase "flush" has no real meaning here. And "reset" actually means something completely different with TCP - namely forcibly breaking the connection using the RST flag. So don't use these phrases in this context.

Steffen Ullrich
  • 114,247
  • 10
  • 131
  • 172