python中实现文件与文本传输

· Special

本质为:引入socket模块,json序列化与粘包的解决方法

1
2

概念

客户端

服务端

代码

客户端

#按需发送文字和文件
import socket
import json
import struct
import os


#定义发送文字函数
def send_data(conn,content):
    #发送文件大小
    #将字符串改字节再计算长度
    body_bytes = content.encode('utf-8')
    msg_size = struct.pack('i', len(body_bytes))
    conn.sendall(msg_size)
    conn.sendall(body_bytes)


#定义发送文件函数
def send_file(conn,file):
    #发送文件大小
    file_size = os.stat(file).st_size
    msg_size = struct.pack('i', file_size)
    conn.send(msg_size)

    #发送文件
    has_send_file_byte = 0
    file_obj = open(file, 'rb')
    while has_send_file_byte < file_size:
        chunk = file_obj.read(2048)
        conn.sendall(chunk)
        has_send_file_byte += len(chunk)
    file_obj.close()


#运行函数
def run():
    #对象化连接
    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    client.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    client.connect(('127.0.0.1', 9999))


    while True:
        #设置发送类型
        '''
        msg | word
        file | file path 
        '''

        user_input = input('>>>').strip()
        if user_input.upper() == 'Q':
            send_data(client,'close')
            break

        #判断输入类型,并匹配方法
        content = user_input.split('|',1)
        if len(content) != 2:
            print('输入不合法,请重试')
            continue
        #将输入格式分类
        msg_type,info = content

        if msg_type == 'msg':
            #发送文件类型
            send_data(client,json.dumps({'msg_type':'msg'}))
            send_data(client,info)
        else:
            #获取当前文件名称
            # file_name = info.rsplit(os.sep,1)[1]
            if os.sep in info:
                file_name = info.rsplit(os.sep, 1)[1]
            else:
                file_name = info
            #发送文件类型
            send_data(client,json.dumps({'msg_type':'file','file_name':file_name}))
            #发送文件
            send_file(client,info)

    client.close()

if __name__ == '__main__':
    run()


服务端

#按需接收文字和文件
import socket
import struct
import json
import os


#设置接收文本函数
def save_data(conn,chunk_stream = 1024):
    #接收头部信息(大小)
    #循环接收是因为需要从网卡缓冲区捞数据
    has_receive_byte = 0
    save_header_byte = []
    while has_receive_byte < 4:
        chunk = conn.recv(4-has_receive_byte)
        has_receive_byte += len(chunk)
        save_header_byte.append(chunk)

    #字节合成由列表到字节
    data = b''.join(save_header_byte)
    #获取头部字节
    data_length = struct.unpack('i', data)[0]

    #开始接收文字数据
    #开始从缓冲区捞
    has_receive_data = []
    #已保存数据大小
    has_receive_data_byte = 0
    while has_receive_data_byte < data_length:
        #判断字节是否满足标准1024字节,不满足就获取不足的字节的数据并获取
        size = chunk_stream if (data_length-has_receive_data_byte) > chunk_stream else data_length-has_receive_data_byte
        chunk = conn.recv(size)
        has_receive_data.append(chunk)
        has_receive_data_byte += len(chunk)

    #将获取的字节拼接
    word_data = b''.join(has_receive_data)
    return word_data





def save_file(conn,file_name,chunk_stream = 1024):
    #接收头部信息(大小)
    #循环接收是因为需要从网卡缓冲区捞数据
    has_receive_byte_file = 0
    save_header_byte = []
    while has_receive_byte_file < 4:
        chunk = conn.recv(4-has_receive_byte_file)
        has_receive_byte_file += len(chunk)
        save_header_byte.append(chunk)

    #字节合成由列表到字节
    data = b''.join(save_header_byte)
    #获取头部字节
    data_length = struct.unpack('i', data)[0]

    #开始接收文字数据
    #开始从缓冲区捞

    #打开文件对象
    #获取保存路径
    save_path = os.path.join('files',file_name)
    file_obj = open(save_path,'wb')

    has_receive_file_byte = 0
    while has_receive_file_byte < data_length:
        #判断字节是否满足标准1024字节,不满足就获取不足的字节的数据并获取
        size = chunk_stream if (data_length-has_receive_file_byte) > chunk_stream else data_length-has_receive_file_byte
        chunk = conn.recv(size)
        file_obj.write(chunk)
        has_receive_file_byte += len(chunk)
        file_obj.flush()
    #关闭文件对象
    file_obj.close()

#运行程序
def run():
    #对象化
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    #端口复用
    server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    server.bind(('127.0.0.1', 9999))
    server.listen(5)

    while True:
        conn, addr = server.accept()
        while True:
            #获取文件类型
            message_type = save_data(conn).decode()
            if message_type == 'close':
                print('客户端关闭链接')
                break

            #反序列化字符
            message_type_info = json.loads(message_type)

            #判断类型
            if message_type_info['msg_type'] == 'msg':
                data = save_data(conn)
                print(f'接收到消息{data.decode()}!')
            else:
                file_name = message_type_info['file_name']
                save_file(conn,file_name)
                print(f'接收到文件,已经保存到{file_name}!')
        conn.close()

if __name__ == '__main__':
    run()







python


评论

行为验证™ 安全组件加载中...