Как получить и собрать байтовые массивы переменной длины в сокетах Python? - PullRequest
1 голос
/ 19 марта 2019

Я пытаюсь отправить большие байтовые массивы класса Protobuf с клиента Java на сервер Python.Однако они имеют переменную длины, потому что иногда я посылаю байты объекта из ClassA, а иногда из ClassB.

У меня есть сервер сокетов Python со следующим кодомвнутри функции, которая слушает сокет:

byte_array = bytearray()

# receive the data in small chunks and print it
while True:
    data = connection.recv(64)
    if data:
        # output received data
        logger.debug("Data: %s" % data)
        byte_array.extend(data)

    else:
        # no more data -- quit the loop
        logger.debug("no more data.")
        break

logger.info("Generating response...")
connection.send(generate_response(byte_array))
logger.info("Sent response.")

Я собираю большой массив байтов, который я получаю, собирая 64 байта по мере их получения.

Однако, когда байтМассив полностью передан, и отправлять нечего, сервер зависает на линии connection.recv.

Я читал, что это потому, что recv блокируется, пока либо не получит что-либо, либо соединение не будет закрыто.Однако я не хочу закрывать соединение, потому что я хочу отправить свой ответ клиенту после обработки всего массива байтов.

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

Я могу придумать три варианта:

  • Установить предопределенный «конечный» байт, ограничивающий конец байтамассив.
  • Заранее отправьте размер байтового массива, а затем вместо while True у меня будет цикл while bytes_read < expected_bytes.
  • Установите время ожидания для соединения, и я предполагаю, что когда время ожидания истеклопроисходит это означает, что все уже отправлено.

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

Есть предложения?

Спасибо.

Ответы [ 2 ]

3 голосов
/ 19 марта 2019

Я бы лично выбрал второй вариант (в сочетании с разумным тайм-аутом для обслуживания злых клиентов, которые отправляют только половину файла и остаются там навсегда). Символ разделения - это хорошо, если вы можете абсолютно гарантировать, что он уникален в вашем потоке (но вам все еще нужно время ожидания).

Если вы не можете гарантировать, что ваш разделитель будет уникальным, отправка размера, ожидаемого клиентом, решит проблему. Если ваши метаданные имеют фиксированную длину, вам не нужно беспокоиться о разделителях и их обнаружении.

1 голос
/ 19 марта 2019

Опция 1:

Таким образом, для первого варианта вы можете установить конечный байт, который не будет нигде в вашем фактическом сообщении.Вы можете создать строку, например, для "END", преобразовать ее в байтовый массив и отправить через вашу Java-программу.После получения вы можете использовать decode (), чтобы преобразовать его в строку и сравнить.:

Примечание. Конечный байт, который вы отправите, должен быть меньше или равен размеру фрагмента для декодирования и получения точного конечного байта.

byte_array = bytearray()

# receive the data in small chunks and print it
while True:
    data = connection.recv(64)
    command = data.decode()
    if command != "END":
        # output received data
        logger.debug("Data: %s" % data)
        byte_array.extend(data)

    else:
        # no more data -- quit the loop
        logger.debug("no more data.")
        break

logger.info("Generating response...")
connection.send(generate_response(byte_array))
logger.info("Sent response.")

Вариант 2:

Для второго варианта вам потребуется изменить цикл while для выполнения в соответствии с метаданными.Я считал, что метаданные будут состоять из первого чанка, который будет количеством чанков, которые будут отправлены. Это может быть что-то вроде:

byte_array = bytearray ()

# receive the data in small chunks and print it
loop_count = 0
count = 1
meta = 1
while loop_count >= count:
    data = connection.recv(64)
    if(meta):
        count = int(data.decode()) # first chunk is the number of chunks that will be sent 
        meta = 0
    logger.debug("Data: %s" % data)
    byte_array.extend(data)
    loop_count = loop_count + 1
else:
    # no more data
    logger.debug("no more data.")
logger.info("Generating response...")
connection.send(generate_response(byte_array))
logger.info("Sent response.")

Вариант 3:

Он также будет работать нормально, если вы уверены, что не будет никакой задержки в сети, и единственной проблемой будет то, что вашей java-программе придется ждать ответа от сервера python до истечения времени ожиданияпроисходит

Вариант 4:

Вы можете использовать неблокирующую розетку, которая будет работать до тех пор, пока она не будет получена в течение предварительно определенного периода времени.Хотя я не рекомендую это для вашей ситуации, вы можете прочитать об этом и посмотреть, соответствует ли это вашим потребностям.

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