Context:
It is common that a binary protocol defines frames of a given size. The struct
module is good at parsing that, provided everything has been received in a single buffer.
Problem:
TCP sockets are streams. A read from a socket cannot give more bytes than requested but can return less. So this code is not reliable:
def readnbytes(sock, n):
return sock.recv(n) # can return less than n bytes
The naive workaround:
def readnbytes(sock, n):
buff = b''
while n > 0:
b = sock.recv(n)
buff += b
if len(b) == 0:
raise EOFError # peer socket has received a SH_WR shutdown
n -= len(b)
return buff
may not be efficient, because if we ask a large number of bytes, and the data if very fragmented, we will repeatedly re-allocate a new byte buffer.
Question:
How is it possible to reliably receive exactly n bytes from a stream socket with no risk of re-allocation?
References:
Those other questions are related, and do give hints, but none give a simple and clear answer:
as you can see write socket the maximum buffer size is 1048576 bytes.
Transmission Control Protocol/Internet Protocol provides a set of 16-bit port numbers within each host.
It simply takes the data, encapsulates it into a TCP packet, and sends it to the remote peer. The TCP socket then keeps sent packets in memory and waits for an acknowledge from the remote peer. If the packet is not acknowledged when the timeout expires, the same packet is resent.
you can use bin(ord('b')). replace('b', '') bin() it gives you the binary representation with a 'b' after the last bit, you have to remove it. Also ord() gives you the ASCII number to the char or 8-bit/1 Byte coded character.
You can use socket.makefile() to wrap the socket in a file-like object. Then reads will return exactly the amount requested, unless the socket is closed where it can return the remainder. Here's an example:
server.py
from socket import *
sock = socket()
sock.bind(('',5000))
sock.listen(1)
with sock:
client,addr = sock.accept()
with client, client.makefile() as clientfile:
while True:
data = clientfile.read(5)
if not data: break
print(data)
client.py
from socket import *
import time
sock = socket()
sock.connect(('localhost',5000))
with sock:
sock.sendall(b'123')
time.sleep(.5)
sock.sendall(b'451234')
time.sleep(.5)
sock.sendall(b'51234')
Server Output
12345 12345 1234
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With