Как я могу предотвратить потерю данных через Wi-Fi с python сокетами? - PullRequest
1 голос
/ 27 марта 2020

Я пытаюсь отправить данные с одного raspberry pi (4) на другой pi (0 w) (я включаю устройства, потому что w 0 не самое мощное устройство, оно немного медленное при запуске рабочий стол, но я не уверен, что это проблема). Передача обычно работает, но время от времени я теряю сообщение. Я полагаю, что могу добавить дополнительный шаг, чтобы убедиться, что сообщение прошло, и запросить его снова, если нет (например, вставлять каждое сообщение некоторое время l oop, чтобы сравнить числа счетчиков), но я не был уверен, было ли лучший путь. Ниже показан некоторый фиктивный код для иллюстрации проблемы.

Клиент (raspberry pi 4)

#client
import socket
import time
import pickle
import random

HOST = '192.168.1.37'
PORT = 2031
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
counter = 0
while True:
    counter += 1
    message = ['note_off', 21, counter, time.time()]
    message_2 = pickle.dumps(message)
    print(message)
    s.send(message_2)
    time.sleep(random.random() / 10)

Сервер (raspberry pi 0 w)

# server
import socket
import pickle
import time
import threading

HOST = '192.168.1.37'
PORT = 2031
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen(1)
global stop
stop = False

def testa():
    counter = 0
    conn, addr = s.accept()
    s.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
    print('Connected by', addr)
    try:
        while True and not stop:
            message_2 = conn.recv(1024)
            message = pickle.loads(message_2)
            if message:
                counter += 1
                print('counter = {}, message = {}'.format(counter, message))
        s.close()
    except:
        print('closing')
        s.close()


try:
    print('creating thread')
    test_thread = threading.Thread(target=testa)
    print('starting thread')
    test_thread.start()
    print('thread started')
except:
    s.close()
    stop = True

Итак, в клиентский код, я запускаю счетчик и включаю его в часть сообщения, а также запускаю дублирующий счетчик в другой программе, чтобы мы могли сравнить. Я печатаю вывод для проверки.

counter = 1, message = ['note_off', 21, 1, 1585259341.171993]
counter = 2, message = ['note_off', 21, 2, 1585259341.2157793]
...
counter = 27, message = ['note_off', 21, 27, 1585259342.608451]
counter = 28, message = ['note_off', 21, 28, 1585259342.6267097]
counter = 29, message = ['note_off', 21, 31, 1585259342.739835]
counter = 30, message = ['note_off', 21, 32, 1585259342.813044]
counter = 31, message = ['note_off', 21, 33, 1585259342.8884292]
...
counter = 230, message = ['note_off', 21, 267, 1585259354.8655927]
counter = 231, message = ['note_off', 21, 268, 1585259354.9502656]
counter = 232, message = ['note_off', 21, 269, 1585259354.999945]

Счетчик, а затем третий элемент message должен совпадать, и они некоторое время это делают, но затем сообщения начинают сбрасываться.

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

РЕШЕНИЕ Как указано в комментариях, это было результатом Мое недопонимание, как именно работает поток (я думал об этом как о потоке сообщений, когда это действительно поток байтов). В моем случае, поскольку я точно знаю, насколько большими будут объекты, которые будут отправлены, я могу установить параметр для recv, чтобы он точно определял количество отправляемых байтов (есть более элегантные решения, но этот работает для моего случая).

...