如何在发送之前将文件拆分成较小的块

时间:2013-05-17 21:46:17

标签: python python-2.7

如何获取以下代码将大文件分解为较小的部分并发送这些部分,而不是发送整个文件?它无法发送大文件(使用ubuntu iso测试大约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加密文件,如果这对我正在尝试做的事情有任何影响。猜猜加密单独的部分是最聪明的,而不是加密整个文件然后将其拆分成部分。

希望上面的代码足够了。如果没有,我会用更多代码更新。

1 个答案:

答案 0 :(得分: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之上构建协议。

我猜你认为只有大文件失败的原因是你在localhost或简单的局域网上测试。在这种情况下,对于较小的send,你有{99}的可能性recv与你发送的完全一样多。但是一旦你对其中一个缓冲区变得太大,它就会从99%的工作时间变为0%的时间,所以你认为问题在于你无法发送大文件。

你认为将其分成1024字节块的原因让你胡言乱语,这意味着你快速连续地做了一大堆消息,使得send和recv调用不太可能匹配一个对一个。 (或者这个可能更简单 - 例如,你没有匹配双方的变化,所以你不会像加密一样解密。)


每当您尝试通过网络发送任何类型的消息(文件,命令等)时,您都需要基于消息的协议。但TCP / IP是基于字节流的协议。那么,你如何处理呢?您可以在流协议之上构建消息协议。

最简单的方法是采用已经为您的目的而设计的协议,并且已经有客户端的Python库以及您可以直接用于服务器的Python库或库存守护程序。发送文件的一些明显示例是FTP,TFTP,SCP或HTTP。或者您可以使用通用协议,如netstring,JSON-RPC或HTTP。

如果您想学习自己设计和实施协议,有两种基本方法。

首先,您可以从TwistedmonocleTulip或其他一些旨在完成所有繁琐且难以获取的内容的框架开始,这样您就可以了必须编写你关心的部分:将字节转换为消息,将消息转换为字节。

或者你可以自下而上,用基本的套接字调用(或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时保存缓冲区。更重要的是,您通常希望使用ProtocolDecoder对象或回调或协同程序来控制周围的控制流。你用字节来提供它,它用消息提供其他东西。 (同样对于发送方,但这总是更简单。)通过从套接字中抽象出协议,您可以用完全不同的传输替换它 - 一个测试驱动程序(对于调试协议处理程序几乎必不可少),隧道协议,套接字绑定到select样式的反应器(同时处理多个连接)等。