Отправить метаданные перед файлом с сокетами в python - PullRequest
0 голосов
/ 09 января 2019

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

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

В настоящее время мой код выглядит так для приемника :

 while True:
    c, addr = self.s.accept()
    l = c.recv(1024)
    while (l):
        if stage < 2:
            self.__recvHeader(l)
            stage += 1
        else:
            self.f.write(l)
        l = c.recv(1024)

Будучи функцией __recvHeader:

def __recvHeader(self, data):
    line = data.decode("utf-8").split(":")
    if line[0] == "Name":
        self.filename = line[1]
        self.f = open("/tmp/" + self.filename, 'wb')
    elif line[0] == "Size":
        self.size = int(line[1])
    else:
        print("ERROR: " + "".join(line))

А Tx любит:

# Here I send some headers first, then
l = f.read(1024)
while (l):
    self.s.send(l)
    l = f.read(1024)

При использовании функции sendHeader :

def __sendHeader(self, name, value):
    self.s.send((name + ":" + value).encode('utf-8'))

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

Есть идеи о том, как решить эту проблему, или как я могу превратить эти данные во что-то фиксированного размера, чтобы избежать этой проблемы? Этот последний вариант также потребовал бы другого "разбора" IMO, не так ли?

Ответы [ 2 ]

0 голосов
/ 09 января 2019

Убедитесь, что вы используете сокет с: socket.SOCK_STREAM! Это означает, что сокеты используют TCP, который гарантирует, что ваши данные поступают и поступают в порядке (в разумных пределах «гарантированности»). Если проблемы сохраняются, читайте дальше ...

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

while ('$'.encode('utf-8') not in l):
    l = c.recv(1024)
    # append l to a bytearray or similar

И вы просто отправляете "$<base64filecontent>$".

0 голосов
/ 09 января 2019

Я полагаю, вы используете сокеты TCP / IP. TCP / IP является потоковым протоколом и ничего не знает о ваших структурах данных. Если вы отправляете «сообщение» за одну send() операцию, нет гарантии, что оно придет за одну recv() операцию. Или что операция recv() получит только одно «сообщение». В вашем случае заголовок - это сообщение.

Таким образом, вы должны каким-то образом разделять свои сообщения, чтобы получатель мог правильно получать и анализировать их. У вас есть два основных варианта:

  1. Сначала отправьте длину (количество байтов) заголовка, а затем данные заголовка. Получатель сначала читает длину, а затем читает столько байтов.
  2. Отправлять разделитель после каждого заголовка. Получатель считывает данные заголовка до получения разделителя.

В первом варианте вы должны подумать о том, как отправить длину. Если вы используете многобайтовое значение, такое как 32-разрядное значение, вы можете преобразовать его в сетевой порядок байтов перед отправкой. См Хтонл .

Во втором варианте вы можете recv() побайтно, но это будет очень медленно. Возможно, вы захотите использовать какую-то буферизацию.

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