First of all, to send all the bytes you don’t need a loop because python sockets provide a simple method: socket.sendall()
.
Now to your questions:
-
Yes, even to receive just 4 bytes you should have a receive loop that calls
recv()
on the socket until 4 bytes are read. -
You can, if you can guarantee that such characters will not appear in the message itself. However, you’d still need to search every character that you read in for the magic delimiter, so it seems inferior to simply prefixing the message body with a length.
-
When you call
recv(n)
that is only guaranteed to return at most n bytes, not exactly n bytes.
Here are three different recvall()
methods to compare:
def recvall(sock, size):
received_chunks = []
buf_size = 4096
remaining = size
while remaining > 0:
received = sock.recv(min(remaining, buf_size))
if not received:
raise Exception('unexpected EOF')
received_chunks.append(received)
remaining -= len(received)
return b''.join(received_chunks)
and the much shorter
def recvall2(sock, size):
return sock.recv(size, socket.MSG_WAITALL)
and finally another version that is a little shorter than the first but lacks a couple of features:
def recvall3(sock, size):
result = b''
remaining = size
while remaining > 0:
data = sock.recv(remaining)
result += data
remaining -= len(data)
return result
The second one is nice and short, but it relies on a socket option socket.MSG_WAITALL
that I do not believe is guaranteed to exist on every platform. The first and third ones should work everywhere. I haven’t really benchmarked any to compare and contrast.