2013-05-17 2 views
1

Как получить следующий код, чтобы разбить большие файлы на более мелкие части и отправить эти части вместо отправки всего файла? Он не может передавать большие файлы (протестировано с Ubuntu изо вокруг 600MB)Как разбить файл на более мелкие куски перед отправкой

...some code 
# file transfer 
    with open(sendFile, "rb") as f: 
     while 1: 
      fileData = f.read() 
      if fileData == "": break 
      # send file 
      s.sendall(EncodeAES(cipher, fileData)) 
    f.close() 
...more code 

Я пытался с f.read (1024), но это не сработало.

Наконец, при разделении файлов мне нужно будет снова объединить детали.

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

Надеюсь, что вышеуказанного кода достаточно. Если нет, я обновляю больше кода.

+0

вам нужно сделать это в python? вы можете использовать стандартный gnu 'split' в cli и передать полученные части. –

+1

Мне кажется, что он должен работать с f.read (1024). Как это точно, вы можете дать более подробную информацию? BTW, не нужно закрывать файл в конце: ключевое слово «с» делает это для вас – deubeuliou

+0

Я бы предпочел сделать это на Python. Использование f.read (1024) дает мне много тарабарщины (что, вероятно, около 1024 бит зашифрованного файла) – MadsRC

ответ

5

Возможно, я ошибаюсь, но я уверен, что ваша фактическая проблема - это не то, что вы думаете о ней, и по той же причине ваша попытка исправить ее, прочитав 1K за раз, не помогла. Извиняюсь, если я ошибаюсь, и вы уже знаете это основное.

Вы пытаетесь отправить зашифрованный текст, как это:

s.sendall(EncodeAES(cipher, fileData)) 

Там, конечно, нет информации о длине, без разделителей и т.д. в этом коде. И вы не можете отправлять данные длины вне этой функции, потому что вы не знаете, как долго будет зашифрованный текст перед тем, как перейти к этому коду.

Итак, я предполагаю, что другая сторона делает что-то вроде этого:

data = s.recv(10*1024*1024) 
with open(recvFile, "wb") as f: 
    f.write(DecodeAES(cipher, data)) 

Поскольку приемник не имеет возможности узнать, где зашифрованные концы файлов и следующий зашифрованный файл (или другое сообщение) начинается , все, что он может сделать, это попытаться получить «все», а затем расшифровать его. Но это может быть половина файла или файл плюс 6-1/2 других сообщения или оставшаяся часть какого-либо предыдущего сообщения плюс половина файла и т. Д. Сокеты TCP - это просто потоки байтов, а не последовательности отдельных сообщений. Если вы хотите отправлять сообщения, вам нужно построить протокол поверх TCP.

Я угадываю причину, по которой вы считаете, что это не удается с большими файлами, это то, что вы тестируете на локальном хосте или в простой локальной сети. В этом случае, для smallish send s, есть вероятность 99%, что вы получите recv столько же, сколько вы отправили. Но как только вы становитесь слишком большим для одного из буферов на этом пути, он работает от 99% времени до 0% времени, поэтому вы предполагаете, что проблема заключается в том, что вы просто не можете отправлять большие файлы.

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


Всякий раз, когда вы пытаетесь для отправки любых сообщений (файлов, команд и т. д.) по сети, вам нужен протокол на основе сообщений. Но TCP/IP - это протокол на основе байтов. Итак, как вы справляетесь с этим? Вы создаете протокол сообщений поверх протокола потока.

Самый простой способ сделать это - принять протокол, который уже был разработан для вашей цели, и что у него уже есть библиотеки Python для клиента, а также библиотеки Python или демона запаса, которые вы можете просто использовать как есть для сервер. Некоторыми очевидными примерами для отправки файла являются FTP, TFTP, SCP или HTTP. Или вы можете использовать протокол общего назначения, такой как netstring, JSON-RPC или HTTP.

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

Во-первых, вы можете начать с Twisted, monocle, Tulip, или какой-либо другой структуры, которая была разработана, чтобы сделать все утомительно и труднодоступный правом вещи, так что вы должны написать только часть, которую вы заботитесь о: поворот байтов в сообщения и сообщения в байты.

Или вы можете пойти снизу вверх и построить обработчик протокола из основных вызовов сокетов (или asyncore или что-то еще подобное низкоуровневое). Вот простой пример:

def send_message(sock, msg): 
    length = len(msg) 
    if length >= (1 << 32): 
     raise ValueError('Sorry, {} is too big to fit in a 4GB message'.format(length)) 
    sock.sendall(struct.pack('!I', length)) 
    sock.sendall(msg) 

def recv_bytes(sock, length): 
    buf = '' 
    while len(buf) < length: 
     received = sock.recv(4-len(buf)) 
     if not received: 
      if not buf: 
       return buf 
      raise RuntimeError('Socket seems to have closed in mid-message') 
     buf += received 
    return buf 

def recv_message(sock): 
    length_buf = recv_bytes(sock, 4) 
    length = struct.unpack('!I', buf) 
    msg_buf = recv_bytes(sock, length) 
    return msg_buf 

Конечно, в реальной жизни, вы не хотите, чтобы сделать крошечную 4-байтовый читает, а это означает, что вам нужно, чтобы накопить буфер между несколькими вызовами recv_bytes. Что еще более важно, вы обычно хотите переключить поток управления с помощью объекта Protocol или Decoder или обратного вызова или сопрограммы. Вы кормите его байтами, и он передает что-то еще сообщениями. (И аналогично для отправляющей стороны, но это всегда проще). Отвлекая протокол от сокета, вы можете заменить его совершенно другим транспортом - тестовым драйвером (почти необходимым для отладки обработчиков протоколов), протоколом туннелирования, гнездо, привязанное к статическому реактору select (для одновременного управления несколькими соединениями) и т. д.

+0

Спасибо. Исключительное объяснение, которое на самом деле имеет смысл. Я думаю, что найду подходящий способ отправить эти файлы :) – MadsRC

+0

@MadsRC: Позвольте мне отредактировать ответ, чтобы дать несколько разных отправных точек. – abarnert

Смежные вопросы