python socket传输文件(解决跨平台传输时数据丢失)

最近在做一个项目,涉及到本地机器和服务器之间的数据传输,因此也查了许多资料和博客。纵观来看,数据传输的一般步骤是先发送数据头,包括文件大小和文件名,然后开始传输数据。但是我的需求是发送端为Windows系统,而接收端为linux系统,使用之前的代码接收到的文件一直有损坏,导致后续工作失败。在查阅了无数资料后,终于找到一种解决办法,特记录在这里。

下面是部署在发送端的代码,和网上查找的代码基本相同:

import socket
import struct
import sys
import os
import time


if __name__ == '__main__':

    file_name = sys.argv[1]

    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.connect((socket.gethostname(), 12345))

    # 定义文件头信息;
    file_head = struct.pack('128sl', os.path.basename(file_name).encode(),
                        os.stat(file_name).st_size)

    sock.send(file_head)

    read_file = open(file_name, "rb")

    while True:
        # time.sleep(1)
        file_data = read_file.read(10240)

        if not file_data:
            break

        sock.send(file_data)

    read_file.close()
    sock.close()

下面是接收端的代码,这里主要对接收文件的地方进行了修改,代码如下:

import socket
import threading
import os
import struct


def sending_file(connection):
    try:
        file_info_size = struct.calcsize('128sl')

        buf = connection.recv(file_info_size)

        if buf:
            file_name, file_size = struct.unpack('128sl', buf)
            file_name = file_name.decode().strip('\00')

            file_new_dir = os.path.join('receive')
            # print(file_name, file_new_dir)
            if not os.path.exists(file_new_dir):
                os.makedirs(file_new_dir)

            file_new_name = os.path.join(file_new_dir, file_name)

            received_size = 0

            w_file = open(file_new_name, 'wb')

            print("start receiving file:", file_name)

            while not received_size == file_size:

                r_data = connection.recv(10240)
                received_size += len(r_data)
                w_file.write(r_data)

            w_file.close()

            print("接收完成!\n")

        connection.close()

    except Exception as e:
        print(e)


if __name__ == '__main__':
    host = socket.gethostname()

    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.bind((host, 12345))
    sock.listen(5)

    print("服务已启动---------------")

    while True:
        connection, address = sock.accept()
        print("接收地址:", address)
        thread = threading.Thread(target=sending_file, args=(connection,))
        thread.start()

这样修改的原因在于接收端并不是每次都能接收到buf_size大小的数据,因而在最后的一次connection.recv(file_size - received_size)不能保证一定能接收完数据,谨记。

另外,在不同的平台上可能会遇到这个问题:struct.error: unpack requires a buffer of 136 bytes。

这是由于平台的位数不同导致的,我的windows系统为32位,而linux系统为64位,因此应该将32位的机器上的128sl改为128sq,这样长度就相等了。如果想进一步拓展程序的兼容性,可以使用platform模块判断系统的位数和操作系统类别。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值