Было бы полезно, если бы мы могли точно видеть, что вы делаете на отправляющей стороне. Однако очевидно, что у вас есть несколько проблем.
Во-первых, в начальном recv
очевидно, что вы намеревались получить только начальный объект pickle, который вы использовали для кодирования длины оставшихся байтов. Однако, что recv
может также получить начальный сегмент оставшихся байтов (или даже всех оставшихся байтов, в зависимости от их размера). Так сколько же вы должны дать начальному pickle.loads
?
Было бы лучше создать поле фиксированной длины, которое будет содержать размер оставшихся данных. Это часто делается с помощью модуля struct
. На отправляющей стороне:
import struct
# Pickle the data to be sent
data = pickle.dumps(python_obj)
data_len = len(data)
# Pack data length into 4 bytes, encoded in network byte order
data_len_to_send = struct.pack('!I', data_len)
# Send exactly 4 bytes (due to 'I'), then send data
conn.sendall(data_len_to_send)
conn.sendall(data)
На принимающей стороне, как сказано в исключении, pickle.loads
принимает строку байтов, а не список. Поэтому частью решения этой проблемы будет объединение всех элементов списка в одну байтовую строку перед вызовом loads
:
unpickled = pickle.loads(b''.join(data))
Другие проблемы на принимающей стороне: используйте len(packet)
, чтобы получить размер буфера. sys.getsizeof
предоставляет внутреннюю память, используемую объектом bytes
, которая включает в себя неопределенные накладные расходы интерпретатора и здесь не то, что вам нужно.
После recv
первое, что вы должны сделать, это проверить наличие пустого буфера, который указывает на конец потока (len(packet) == 0
или packet == ''
или not packet
даже). Это может произойти, например, если отправитель был убит до завершения отправки (или сбой сетевого соединения, или какая-то ошибка на стороне отправителя и т. Д.). В противном случае, если соединение заканчивается преждевременно, ваша программа никогда не достигнет break
и, следовательно, будет в очень узком бесконечном цикле.
Итак, вы можете сделать что-то вроде этого:
# First, obtain fixed-size content length
buf = b''
while len(buf) < 4:
tbuf = recv(4 - len(buf))
if tbuf == '':
raise RuntimeError("Lost connection with peer")
buf += tbuf
# Decode (unpack) length (note that unpack returns an array)
len_to_recv = struct.unpack('!I', buf)[0]
data = []
len_recved = 0
while len_recvd < len_to_recv:
buf = self.s.recv(min(len_to_recv - len_recvd, BUFFERSIZE))
if buf == '':
raise RuntimeError("Lost connection with peer")
data.append(buf)
len_recvd += len(buf)
unpickled_obj = pickle.loads(b''.join(data))
РЕДАКТИРОВАТЬ: перемещенные скобки