zoukankan      html  css  js  c++  java
  • 21 网络编程--文件传输

    1、通过socket收发文件(基于TCP协议)

    1.1、上传文件(在同一ip下进行)

    settings:

    import os,sys
    BASE_DIR = os.path.dirname(os.path.abspath(__file__))
    sys.path.append(BASE_DIR)
    
    path_db = os.path.dirname(os.path.abspath(__file__))
    path_server = os.path.join(path_db,'server')
    path_client = os.path.join(path_db,'client')

    客户端:

    import socket
    import struct
    import json
    import os,sys
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    sys.path.append(BASE_DIR)
    from db import settings
    
    def run():
        phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        phone.connect(('127.0.0.1',9900))
        while True:
            # 1、发命令
            cmd = input('>>: ').strip()  # get 3.jpeg
            if not cmd: continue
            cmds = cmd.split()
            filename = cmds[1]
            try:
                header_dic = {
                    'filename': filename,
                    'md5': 'xxdxxx',
                    'file_size': os.path.getsize(os.path.join(settings.path_client, filename))
                }
    
                header_json = json.dumps(header_dic)
                header_bytes = header_json.encode('utf-8')
                phone.send(struct.pack('i', len(header_bytes)))  # len(header_bytes)发送信息给客户端的字节长度
                phone.send(header_bytes)  # 客户端发两次
                with open(os.path.join(settings.path_client, filename), 'rb') as f:
                    for line in f:
                        phone.send(line)
            except ConnectionResetError:  # 适用于windows操作系统
                break
        phone.close()
    
    
    if __name__ == '__main__':
        run()

    服务端:

    import socket
    import subprocess
    import struct
    import json
    # ------------------------上传功能和下载功能的逻辑对换一下就可以------------------------------------------------------
    import os,sys
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    sys.path.append(BASE_DIR)
    from db import settings
    
    phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    # phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
    phone.bind(('127.0.0.1',9900)) #0-65535:0-1024给操作系统使用
    phone.listen(5)
    
    print('starting...')
    while True: # 链接循环
        conn,client_addr=phone.accept()
        print(client_addr)
        while True:
            try:
                obj = conn.recv(4)  # 接收服务端传来的  struct.pack('i',len(header_bytes))
    
                header_size = struct.unpack('i', obj)[0]  # 解包--得到服务端传给客户端   header_dic字典字节的长度
    
                # 第二步:再收报头
                header_bytes = conn.recv(header_size)  # header_size为上一步已经算好的字典字节长度
                # header_bytes 为 接收客户端第二次发过来的header_dic字典转化的成的字节数据
    
                # 第三步:从报头中解析出对真实数据的描述信息
                header_json = header_bytes.decode('utf-8')  # class---> str类型
                header_dic = json.loads(header_json)  # 反序列化 服务端原先的 字典
                print(header_dic)
                total_size = header_dic['file_size']  # 服务端的执行后返回给客户端的字节流长度
    
                # 第四步:接收真实的数据
                filename = header_dic['filename']
                with open(os.path.join(settings.path_server, filename), 'wb') as f:
                    recv_size = 0
                    while recv_size < total_size:
                        line = conn.recv(1024)  # 1024是一个坑
                        f.write(line)
                        recv_size += len(line)
                        print(f'总大小{total_size},已下载{recv_size}')
            except ConnectionResetError:
                break
        conn.close()
    
    phone.close()

    1.2、下载文件

     客户端:

    import socket
    import struct
    import json
    import os,sys
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    sys.path.append(BASE_DIR)
    from db import settings
    
    
    phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    phone.connect(('127.0.0.1',9909))
    
    while True:
        #1、发命令
        cmd=input('>>: ').strip() # get 3.jpeg
        if not cmd:continue
        phone.send(cmd.encode('utf-8'))
    
        #2、以写的方式打开一个新文件,接收服务端发来的文件内容写入客户端的新文件
    
        #第一步:先收报头的长度
        obj=phone.recv(4)  #接收服务端传来的  struct.pack('i',len(header_bytes))
    
        header_size=struct.unpack('i',obj)[0] # 解包--得到服务端传给客户端   header_dic字典字节的长度
    
        #第二步:再收报头
        header_bytes=phone.recv(header_size) #   header_size为上一步已经算好的字典字节长度
        # header_bytes 为 接收客户端第二次发过来的header_dic字典转化的成的字节数据
    
        #第三步:从报头中解析出对真实数据的描述信息
        header_json=header_bytes.decode('utf-8') # class---> str类型
        header_dic=json.loads(header_json)   # 反序列化 服务端原先的 字典
        print(header_dic)
        total_size=header_dic['file_size'] # 服务端的执行后返回给客户端的字节流长度
    
        #第四步:接收真实的数据
        filename = header_dic['filename']
        with open(os.path.join(settings.path_client,filename),'wb') as f:
            recv_size=0
            while recv_size < total_size:
                line=phone.recv(1024) #1024是一个坑
                f.write(line)
                recv_size+=len(line)
                print(f'总大小{total_size},已下载{recv_size}')
    
    
        # print(recv_data.decode('gbk'))
    
    phone.close()

    服务端:

    import socket
    import subprocess
    import struct
    import json
    
    import os,sys
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    sys.path.append(BASE_DIR)
    from db import settings
    
    
    phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    # phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
    phone.bind(('127.0.0.1',9909)) #0-65535:0-1024给操作系统使用
    phone.listen(5)
    
    print('starting...')
    while True: # 链接循环
        conn,client_addr=phone.accept()
        print(client_addr)
    
        while True: #通信循环
            try:
                #1、收命令
                res=conn.recv(8096) # b'get 3.jpeg'
                if not res:break #适用于linux操作系统
    
                #2、解析命令,提取相应的命令参数
                cmds = res.decode('utf-8').split()
                filename = cmds[1]
    
                #3、以读取方式打开文件,读取文件内容 发给客户端
    
                #第一步:制作固定长度的报头
                header_dic={
                    'filename':filename,
                    'md5':'xxdxxx',
                    'file_size': os.path.getsize(os.path.join(settings.path_server,filename))
                }
    
                header_json=json.dumps(header_dic)
    
                header_bytes=header_json.encode('utf-8')
    
                #第二步:先发送报头的长度
                conn.send(struct.pack('i',len(header_bytes))) # len(header_bytes)发送信息给客户端的字节长度
    
                #第三步:再发报头
                conn.send(header_bytes)  # 客户端发两次
                with open(os.path.join(settings.path_server,filename),'rb') as f:
                    for line in f:
                        conn.send(line)
    
    
                #第四步:再发送真实的数据
    
            except ConnectionResetError: #适用于windows操作系统
                break
        conn.close()
    
    phone.close()

    2、上传、下载代码优化(函数版本)

     客户端:

    import socket
    import struct
    import json
    import os,sys
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    sys.path.append(BASE_DIR)
    from db import settings
    
    def get(phone):
        obj = phone.recv(4)  # 接收服务端传来的  struct.pack('i',len(header_bytes))
        header_size = struct.unpack('i', obj)[0]  # 解包--得到服务端传给客户端   header_dic字典字节的长度
        header_bytes = phone.recv(header_size)  # header_size为上一步已经算好的字典字节长度
        # header_bytes 为 接收客户端第二次发过来的header_dic字典转化的成的字节数据
        # 第三步:从报头中解析出对真实数据的描述信息
        header_json = header_bytes.decode('utf-8')  # class---> str类型
        header_dic = json.loads(header_json)  # 反序列化 服务端原先的 字典
        print(header_dic)
        total_size = header_dic['file_size']  # 服务端的执行后返回给客户端的字节流长度
    
        # 第四步:接收真实的数据
        filename = header_dic['filename']
        with open(os.path.join(settings.path_client, filename), 'wb') as f:
            recv_size = 0
            while recv_size < total_size:
                line = phone.recv(1024)  # 1024是一个坑
                f.write(line)
                recv_size += len(line)
                print(f'总大小{total_size},已下载{recv_size}')
    
    def put(phone,cmds):
        filename = cmds[1]
        # try:
        header_dic = {
            'filename': filename,
            'md5': 'xxdxxx',
            'file_size': os.path.getsize(os.path.join(settings.path_client, filename))
        }
    
        header_json = json.dumps(header_dic)
        header_bytes = header_json.encode('utf-8')
        phone.send(struct.pack('i', len(header_bytes)))  # len(header_bytes)发送信息给客户端的字节长度
        phone.send(header_bytes)  # 客户端发两次
        with open(os.path.join(settings.path_client, filename), 'rb') as f:
            for line in f:
                phone.send(line)
    
    def run():
        phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        phone.connect(('127.0.0.1',9909))
        while True:
            #1、发命令
            cmd=input('>>: ').strip() # get 3.jpeg
            if not cmd:continue
            phone.send(cmd.encode('utf-8'))
            cmds = cmd.split()
            if cmds[0] == 'get':
                get(phone)
            if cmds[0] == 'put':
                try:
                    put(phone,cmds)
                except ConnectionResetError:  # 适用于windows操作系统
                    break
        phone.close()
    
    if __name__ == '__main__':
        run()

    服务端:

    import socket
    import subprocess
    import struct
    import json
    
    import os,sys
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    sys.path.append(BASE_DIR)
    from db import settings
    
    def get(conn,cmds):
        filename = cmds[1]
        header_dic = {
            'filename': filename,
            'md5': 'xxdxxx',
            'file_size': os.path.getsize(os.path.join(settings.path_server, filename))
        }
        header_json = json.dumps(header_dic)
        header_bytes = header_json.encode('utf-8')
        # 第二步:先发送报头的长度
        conn.send(struct.pack('i', len(header_bytes)))  # len(header_bytes)发送信息给客户端的字节长度
        # 第三步:再发报头
        conn.send(header_bytes)  # 客户端发两次
        with open(os.path.join(settings.path_server, filename), 'rb') as f:
            for line in f:
                conn.send(line)
    
    def put(conn):
        obj = conn.recv(4)  # 接收服务端传来的  struct.pack('i',len(header_bytes))
    
        header_size = struct.unpack('i', obj)[0]  # 解包--得到服务端传给客户端   header_dic字典字节的长度
    
        # 第二步:再收报头
        header_bytes = conn.recv(header_size)  # header_size为上一步已经算好的字典字节长度
        # header_bytes 为 接收客户端第二次发过来的header_dic字典转化的成的字节数据
    
        # 第三步:从报头中解析出对真实数据的描述信息
        header_json = header_bytes.decode('utf-8')  # class---> str类型
        header_dic = json.loads(header_json)  # 反序列化 服务端原先的 字典
        print(header_dic)
        total_size = header_dic['file_size']  # 服务端的执行后返回给客户端的字节流长度
    
        # 第四步:接收真实的数据
        filename = header_dic['filename']
        with open(os.path.join(settings.path_server, filename), 'wb') as f:
            recv_size = 0
            while recv_size < total_size:
                line = conn.recv(1024)  # 1024是一个坑
                f.write(line)
                recv_size += len(line)
                print(f'总大小{total_size},已下载{recv_size}')
    
    def run():
        phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        # phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
        phone.bind(('127.0.0.1',9909)) #0-65535:0-1024给操作系统使用
        phone.listen(5)
    
        print('starting...')
        while True: # 链接循环
            conn,client_addr=phone.accept()
            print(client_addr)
            while True: #通信循环
                try:
                    #1、收命令
                    res=conn.recv(8096) # b'get 3.jpeg'
                    if not res:break
                    #2、解析命令,提取相应的命令参数
                    cmds = res.decode('utf-8').split()
                    if cmds[0] == 'get':
                        get(conn,cmds)
                    if cmds[0] == 'put':
                        put(conn)
                except ConnectionResetError: #适用于windows操作系统
                    break
            conn.close()
        phone.close()
    
    if __name__ == '__main__':
        run()

    3、面向对象编写上传、下载文件

  • 相关阅读:
    c++之输出文件和输入文件的处理
    C++之输入输出流
    c++之虚析构函数
    c++之虚函数和基类指针
    接口自动化测试框架Karate入门
    uiautomator+cucumber实现移动app自动化测试
    calabash-android Win10 入门笔记
    Page Object 模式编写UiAutomator脚本
    ruby脚本打印日志到rspec的报告文件中
    Ruby跳出多层循环 catch...throw
  • 原文地址:https://www.cnblogs.com/foremostxl/p/9664763.html
Copyright © 2011-2022 走看看