Передача файлов через сокет TCP - PullRequest
4 голосов
/ 07 июля 2010

Я пытаюсь написать безопасную программу для передачи файлов с использованием Python и AES, и у меня возникла проблема, которую я до конца не понимаю.Я отправляю свой файл, анализируя его с помощью фрагментов размером 1024 байта и отправляя их поверх, но серверная сторона, получающая данные, вылетает (я использую AES CBC, поэтому моя длина данных должна быть кратна 16 байтам), и полученная ошибка говорит, что этоnot.

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

Я попытался поставить time.sleep (0.5)между каждым сокетом отправляю на стороне клиента и вроде бы работает.Возможно ли, что это какая-то ошибка буфера сокета на стороне сервера?То, что слишком много данных отправляется слишком быстро клиентом и что он каким-то образом разрушает буферный сокет на стороне сервера, так что данные повреждены или исчезают, а recv (1024) получает только поврежденный фрагмент?Это единственное, о чем я мог подумать, но это также может быть полностью ложным, если у кого-то есть представление о том, почему это не работает должным образом, было бы замечательно;)

Следуя своей идее, я попробовал:

    self.s.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 32768000)
    print socket.SO_RCVBUF

Я пытался разместить 32-мегабайтный буфер на стороне сервера, но в Windows XP он показывает 4098 на принтере, а в Linux - только 8. Я не знаю, как я должен это интерпретировать, единственное, что ямы знаем, что похоже, что у него нет 32-мегабайтного буфера, поэтому код не работает.

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

Благодаря Faisal мой код здесь:

Сторона сервера: (count - это мой размер файла / 1024)

while 1:
    txt=self.s.recv(1024)
    if txt == " ":
        break       
    txt = self.cipher.decrypt(txt)
    if countbis == count:
        txt = txt.rstrip()
    tfile.write(txt)
    countbis+=1

Клиентская сторона:

while 1:
    txt= tfile.read(1024)
    if not txt:
        self.s.send(" ")
        break
    txt += ' ' * (-len(txt) % 16)
    txt = self.cipher.encrypt(txt)
    self.s.send(txt)

Заранее спасибо,

Nolhian

Ответы [ 8 ]

8 голосов
/ 07 июля 2010

Добро пожаловать в сетевое программирование! Вы только что впали в то же ошибочное предположение, что каждый делает первый раз, предполагая, что отправка клиента и получение сервером должны быть симметричными. К сожалению, это не случай. ОС позволяет осуществлять прием в кусках произвольного размера. Обойти это довольно легко, просто поместите в буфер свои данные, пока сумма, которую вы прочитали, не будет равна сумме, которую вы хотите получить. Что-то в этом роде поможет:

buff=''
while len(buff) < 1024:
    buff += s.recv( 1024 - len(buff) )
3 голосов
/ 07 июля 2010

TCP - это потоковый протокол, он не сохраняет границы сообщений, как вы только что обнаружили.

2 голосов
/ 07 июля 2010

Как уже отмечали другие, вы, вероятно, обрабатываете неполное сообщение.Вам нужно либо иметь сообщения фиксированного размера, либо иметь разделитель (не забудьте убрать свои данные!), Чтобы вы знали, когда было получено полное сообщение.

1 голос
/ 08 ноября 2011

Не относится к TCP (как уже было сказано), но повторное добавление в строку будет довольно неэффективным, если вы ожидаете много.Может быть лучше добавить список и затем превратить список в строку, когда вы закончите получать, используя ''.join(list).

1 голос
/ 07 июля 2010

Что может гарантировать TCP, так это то, что все ваши данные поступают в правильном порядке в определенный момент . (Если не произойдет что-то неожиданное, к которому оно не придет). Но вполне возможно, что отправляемые вами данные будут по-прежнему поступать кусками. Во многом это из-за ограниченных буферов отправки и получения. Что вы должны сделать, это продолжать делать ваши recv звонки, пока у вас не будет достаточно данных для их обработки. Возможно, вам придется звонить send несколько раз; используйте возвращаемое значение, чтобы отслеживать, сколько данных было отправлено / буферизовано до сих пор.

Когда вы делаете print socket.SO_RCVBUF, вы фактически печатаете символическую SO_RCVBUF contant (за исключением того, что в Python на самом деле нет констант); тот, который говорил setsockopt, что вы хотите изменить. Чтобы получить текущее значение, вы должны вместо этого позвонить getsockopt.

0 голосов
/ 18 декабря 2015

Как уже упоминалось выше

TCP - это потоковый протокол

Вы можете попробовать этот код, где данные ваши исходные данные, вы можете прочитать его из файла или пользовательского ввода

Отправитель

import socket as s
sock = s.socket(s.AF_INET, s.SOCK_STREAM)
sock.connect((addr,5000))
sock.sendall(data)
finish = t.time()

Приемник

import socket as s
sock = s.socket(s.AF_INET, s.SOCK_STREAM)
sock.setsockopt(s.SOL_SOCKET, s.SO_REUSEADDR, 1)
sock.bind(("", 5000))
sock.listen(1)
conn, _ = sock.accept()
pack = []
while True:
    piece = conn.recv(8192)
    if not piece:
        break
    pack.append(piece.decode())
0 голосов
/ 01 ноября 2011

Вот хороший фрагмент кода, который я написал некоторое время назад, возможно, не самый лучший, но это может быть хорошим примером передачи больших файлов по локальной сети.http://setahost.com/sending-files-in-local-network-with-python/

0 голосов
/ 07 июля 2010

Для многих приложений сложности TCP аккуратно абстрагированы модулем Python asynchat .

...