2010-07-06 1 views
4

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

Я попытался напечатать длину данных, отправленных клиентом на стороне клиента, и длину данных, полученных на сервере, и показывает, что клиент отправляет ровно 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

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

сторона сервера: (количество моего размер файл/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

+1

Было бы проще выяснить, что не так, если вы разместили код вокруг своего вызова recv(). Предполагая, что вы вызываете recv() один раз за передачу, вы должны знать, что вы не можете ожидать получить все 1024 байта ваших отправленных данных за один вызов recv(); вам нужно зациклиться на вызове recv() и конкатенации в буфер до тех пор, пока вы не получите 1024 байта, которые вы ожидали. – Faisal

ответ

8

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

buff='' 
while len(buff) < 1024: 
    buff += s.recv(1024 - len(buff)) 
+1

Извините, но я не попал в это (возможно, потому, что я прочитал много кода и книгу сетевого программирования Стивена, прежде чем писать свой первый сокет, используя код). Может быть, вам нужно изменить _everyone_ на _almost every_. ;-P – ninjalj

+0

Большое спасибо за объяснение! Более того, я внедрил свои строки в свою программу и теперь отлично работает;) – Nolhian

3

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

1

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

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

+0

Спасибо, что очень помогло с ответом Ракиса. Я попытался установить ваш ответ в качестве принятого рядом с Ракисом, но, похоже, я могу просто установить только один, это слишком плохо :( – Nolhian

2

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

0

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

+0

Ваш ответ верен, но не очень полезен в его нынешнем кратком формате, если вы развернете пример , Я буду выше, и так будут другие (возможно). – tzot

+0

Учитывая, что 'asynchat' - довольно неудачный пример программирования стандартной библиотеки конца 1990-х годов, который никто никогда не использует, он может не получить никаких повышений, даже если объясняется!:) –

1

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

0

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

TCP является протоколом поток

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

Sender

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())