клиент не получает все сообщения, если сервер отправляет сообщения слишком быстро с Pickle Python - PullRequest
0 голосов
/ 10 ноября 2018

Моя клиентская сторона не может получить два сообщения, если отправитель отправил слишком быстро.

sender.py

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)


sock.bind(('', int(port)))
sock.listen(1)

conn, addr = sock.accept()
#conn.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)

# sends message 1 and message 2
conn.send(pickle.dumps(message1))
#time.sleep(1)
conn.send(pickle.dumps(message2))

, где и сообщение 1, и сообщение 2 являются протравленными объектами.

client.py

sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sock.connect((ip,int(port)))

message1 = pickle.loads(sock.recv(1024))

print(message1)

message2 = pickle.loads(sock.recv(1024)) 

Когда я запускаю этот код как есть, я могу распечатать сообщение1, но не могу получить сообщение2 от отправителя. Сокет блокируется на message2.

Кроме того, если я раскомментирую time.sleep (1) в своем коде на стороне отправителя, я смогу получить оба сообщения очень хорошо. Не уверен, в чем проблема. Я пытался каждый раз очищать свой буфер TCP, устанавливая TCP_NODELAY, но это не сработало. Не уверен, что на самом деле происходит? Как я могу гарантировать, что я получу два сообщения

1 Ответ

0 голосов
/ 10 ноября 2018

Ваш код предполагает, что каждый send на стороне сервера будет соответствовать recv на стороне клиента. Но TCP - это поток байтов, а не протокол, основанный на сообщениях. Это означает, что вполне вероятно, что ваш первый recv уже будет содержать данные со второго send, которые могут быть просто отброшены pickle.loads как ненужные после выбранных данных. Второй recv будет принимать только оставшиеся данные (или просто блокировать, так как все данные там, где они уже получены), поэтому pickle.loads завершится ошибкой.

Распространенный способ справиться с этой ситуацией - создать протокол сообщений поверх потока байтов TCP. Это может быть сделано, например, при добавлении к каждому сообщению префикса с размером фиксированной длины (например, как 4-байтовый код с использованием struct.pack('L',...)) при отправке и для чтения сначала прочитайте значение размера фиксированной длины, а затем прочитайте сообщение с заданным размером .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...