Как избежать потери данных при отправке через сокеты 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 шт):

Автор решения: Roman Konoval

Этот код в принципе не может работать. send принимает массив байт, а вы передаете int.

Нужно передавать именно массив байт, например так:

while True:
   sock.send(str(count).encode('utf-8'))
   print(count, end='', flush=True)
   count += 1
   sleep(0.1)

Далее, все что посылается через TCP сокет доходит до сервера. Если сервер не успевает обрабатывать, то данные буферизируются и следующая операция чтения прочитает все что накопилось и пришло от клиента:

python клиент сервер демонстрация работы буферизации на сервере

Так же может быть и обратная ситуация: клиент послал большой массив, а транспорт его разбил на несколько мелких пакетов, и сервер прочитает только часть (или вообще может прочитать пустой массив, если еще ничего не дошло). Из этого следует, что клиент и сервер должны договориться и использовать протокол, который позволит серверу знать, сколько данных ожидается. И сервер должен собирать полученный кусочки данных перед тем как сможет их интерпретировать.

Например, клиент перед посылкой массива может послать его длину. Сервер сначала читает длину, потом читает в цикле данные пока не получит их все, и только после этого пробует их обрабатывать. Т.е. в вашем случае десериализировать pickle-ом.

→ Ссылка