python - 如何在发送前将文件拆分成更小的部分

标签 python python-2.7

如何获取以下代码以将大文件分解为较小的部分并发送这些部分,而不是发送整个文件?它无法发送大文件(使用 600mb 左右的 ubuntu iso 测试)

...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 加密文件,如果这对我正在尝试做的事情有任何影响的话。猜猜加密单独的部分是最聪明的,而不是加密整个文件然后将其分成几部分。

希望上面的代码就足够了。如果没有,我将使用更多代码进行更新。

最佳答案

我可能是错的,但我敢打赌,您的实际问题不是您认为的那样,这与您尝试通过一次读取 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 之上构建协议(protocol)。

我猜你认为它只因大文件而失败的原因是你正在本地主机或简单的局域网上进行测试。在这种情况下,对于较小的 send s,你有 99% 的机会会 recv和你发送的一样多。但是一旦你的缓冲区变得太大,它就会从 99% 的时间工作到 0% 的时间,所以你假设问题是你不能发送大文件。

您认为将其分成 1024 字节的 block 会给您带来胡言乱语的原因是,这意味着您正在快速连续地处理一大堆消息,从而使 send 和 recv 调用一对一匹配的可能性大大降低-一。 (或者这个可能更简单——例如,您没有匹配两侧的更改,因此您解密的方式与加密的方式不同。)

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

最简单的方法是采用已经为您的目的设计的协议(protocol),并且该协议(protocol)已经具有用于客户端的 Python 库和 Python 库或库存守护程序,您可以按原样将其用于服务器。发送文件的一些明显示例是 FTP、TFTP、SCP 或 HTTP。或者,您可以使用通用协议(protocol),如 netstring、JSON-RPC 或 HTTP。

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

首先,您可以从 Twisted 开始, monocle , Tulip ,或其他一些旨在完成所有繁琐且难以正确处理的框架的框架,因此您只需编写您关心的部分:将字节转换为消息,将消息转换为字节。

或者您可以自下而上,从基本的套接字调用(或 asyncore 或其他类似的低级)构建您的协议(protocol)处理程序。这是一个简单的例子:
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对象或回调或协程。你用字节喂它,它用消息喂它别的东西。 (对于发送方也是如此,但这总是更简单。)通过将协议(protocol)从套接字中抽象出来,您可以用一个完全不同的传输来替换它——一个测试驱动程序(对于调试协议(protocol)处理程序几乎是必不可少的)、一个隧道协议(protocol)、一个连接到 select 的套接字-style reactor(同时处理多个连接)等。

关于python - 如何在发送前将文件拆分成更小的部分,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16618391/

相关文章:

python - 如何使用 Scapy 确定无线加密类型?

python - 查找列表中第一个正元素的索引 - python

python - python代码中明显非法的字符序列

python - 多重继承: only 1 parent init'd

python - 在 Python 中通过正则表达式分解 CSV

python - 如何使用 Azure 认知服务同时听和说

python - 如何在python目录中获取文件名列表(不带扩展名)?

python - roc_auc_score() 和 auc() 的结果不同

Python:使用 Tkinter 时脚本不退出

python - pip 损坏,重新安装不起作用。 EC2