Вы должны принять меры, чтобы убедиться, что у вас есть весь объект, прежде чем вы расстегните. Вы делаете conn.recv(XXX)
, но это не означает, что вы фактически получили все XXX байтов. В случае успеха это означает, что вы получили где-то от 1 до XXX байт (включительно). Если это небольшой буфер, вы часто получаете все это в одном куске, но вы никогда не должны рассчитывать на это.
Как правило, вы хотите отправить количество байтов в двоичном формате фиксированного размера (обычно с использованиеммодуль struct
), затем после получения количества байтов продолжайте получать до тех пор, пока не получите все ожидаемые байты или не получите ошибку (т. е. ваш одноранговый узел отключен).
Что-то похожее на отправляющей стороне:
import struct
pickled_bytes = pickle.dumps(thing_youre_sending)
p_size = len(pickled_bytes) # Size of pickled buffer
p_size_buf = struct.pack("!I", p_size) # Packed binary size (4 byte field)
conn.sendall(p_size_buf) # Send length (Note sendall!)
conn.sendall(pickled_bytes) # Send actual pickled object
На принимающей стороне вы будете делать что-то вроде этого:
import struct
...
def recv_all(conn, rlen):
""" Function to receive all bytes """
recvd = 0
buf = b''
while recvd < rlen:
rbuf = conn.recv(rlen - recvd)
if not rbuf:
# Client disconnected. Handle error in whatever way makes sense
raise ClientDisconnected()
recvd += len(rbuf)
buf += rbuf
...
p_size_buf = recv_all(conn, 4) # Receive entire binary length field
p_size = struct.unpack("!I", p_size_buf)[0] # (Unpack returns an array)
pickled_bytes = recv_all(conn, p_size) # Receive actual pickled object
thing_you_sent = pickle.loads(pickled_bytes)