Как избежать потери данных при отправке через сокеты Python, если принимающая сторона во время отправки была занята?
Есть клиент и есть сервер. Клиент отправляет серверу данные с периодичностью в условную 0.1 секунды, с помощью метода socket.send(). Сервер получает данные от клиента через метод socket.recv(1024) и производит операции над этими данными, которые занимают условную 1 секунду. После выполнения всех операций, сервер возвращается к прослушиванию клиента через метод recv ... Проблема в том, что во время выполнения операции, клиент успевает отправить еще 10 пакетов данных, которые сервер, когда возвращается к прослушиванию клиента - уже не видит. Т.е выполнив пакет №1, возвращаясь к приему пакетов, сервер уже получит пакет №10. Вопрос, как избежать эту потерю? Вывести условные операции в паралелльный поток? Не костыль ли это?
Прилагаю сервер и клиент для демонстрации:
Server:
import socket
from time import sleep
serv = socket.socket()
serv.bind(('localhost', 1337))
serv.listen(10)
conn, addr = serv.accept()
while True:
data = conn.recv(1024)
sleep(1) # Имитируем выполнение операций
print(data.decode())
Client:
from socket import socket
from time import sleep
sock = socket()
sock.connect(('localhost', 1337))
count = 0
while True:
sock.send(bytes(count))
sleep(0.1)
count += 1
UPD. Проблема возникает, когда передаются данные в формате pickle. Принимаются эти данные на стороне сервера с помощью следующей функции ...
def unpickle_data(self, sock, data_size):
"""Собирает большие файлы в цикле"""
data = []
while True:
packet = sock.recv(data_size)
if not packet:
break
data.append(packet)
try:
data_arr = pickle.loads(b"".join(data))
return data_arr
except pickle.UnpicklingError:
print(format_exc())
except:
print(format_exc())
Ответы (1 шт):
Этот код в принципе не может работать. send принимает массив байт, а вы передаете int.
Нужно передавать именно массив байт, например так:
while True:
sock.send(str(count).encode('utf-8'))
print(count, end='', flush=True)
count += 1
sleep(0.1)
Далее, все что посылается через TCP сокет доходит до сервера. Если сервер не успевает обрабатывать, то данные буферизируются и следующая операция чтения прочитает все что накопилось и пришло от клиента:
Так же может быть и обратная ситуация: клиент послал большой массив, а транспорт его разбил на несколько мелких пакетов, и сервер прочитает только часть (или вообще может прочитать пустой массив, если еще ничего не дошло). Из этого следует, что клиент и сервер должны договориться и использовать протокол, который позволит серверу знать, сколько данных ожидается. И сервер должен собирать полученный кусочки данных перед тем как сможет их интерпретировать.
Например, клиент перед посылкой массива может послать его длину. Сервер сначала читает длину, потом читает в цикле данные пока не получит их все, и только после этого пробует их обрабатывать. Т.е. в вашем случае десериализировать pickle-ом.
