zoukankan      html  css  js  c++  java
  • 网络编程TCP

    import os
    import struct
    import json
    import socket
    
    # 设置文件上传路径
    BASE_PATH = 'D:python10期每日笔记和视频day01视频'
    file_list = os.listdir(BASE_PATH)
    
    # 创建客户端
    client = socket.socket()
    
    # 连接服务端
    client.connect(('127.0.0.1', 8888))
    
    while True:
        # 打印文件列表
        for file in file_list:
            print(file_list.index(file), file)
    
        # 选择文件
        choice = input('>>>:').strip()
    
        # 判断输入是否正确
        if not choice.isdigit() or int(choice) < 0 or int(choice) >= len(file_list):
            print('输入有误')
            continue
        choice = int(choice)
    
        # 拼接文件路径
        file_name = file_list[choice]
        file_path = os.path.join(BASE_PATH, file_name)
    
        # 获取文件大小
        file_size = os.path.getsize(file_path)
    
        # 创建字典
        json_dic = {'file_name': file_name, 'file_size': file_size}
    
        # 用json将字典序列化
        json_dic = json.dumps(json_dic).encode('utf-8')
    
        # 用struct打包
        header = struct.pack('i', len(json_dic))
    
        # 发送报头
        client.send(header)
    
        # 发送字典
        client.send(json_dic)
    
        # 发送文件
        sented = 0
        print('开始发送文件.....')
        with open(file_path, 'rb') as f:
            for line in f:
                client.send(line)
                sented += len(line)
                # 显示进度
                print(f'
    {int((sented/file_size)*100)}%',end='')
        print('文件发送完毕.....')
    客户端
    import struct
    import os
    import json
    import socket
    
    # 创建服务端
    server = socket.socket()
    
    # 绑定IP和端口
    server.bind(('127.0.0.1', 8888))
    
    # 创建半连接池
    server.listen(5)
    
    while True:
        # 与客户端建立连接通道,并获取其IP地址
        conn, addr = server.accept()
    
        while True:
            try:
                # 接收报头
                msg = conn.recv(4)
    
                # 解析报头
                header_len = struct.unpack('i', msg)[0]
    
                # 接收报头字典
                header_dic = conn.recv(header_len)
    
                # 反序列化
                json_d = json.loads(header_dic.decode('utf-8'))
    
                # 获取数据长度及文件名
                file_size = json_d.get('file_size')
                file_name = json_d.get('file_name')
    
                # 接收数据,将数据写入文件
                data_count = 0
                with open(f'upload/{file_name}', 'wb') as f:
                    while data_count < file_size:
                        data = conn.recv(1024)
                        f.write(data)
                        f.flush()
                        data_count += len(data)
                print('上传成功')
            except ConnectionResetError:
                break
    
        # 数据接收完毕与客户端断开连接.
        conn.close()
    服务端

    基于TCP协议,实现客户端与服务端进行文件上传操作.

    服务器端与客户端的操作,一定要一一对应.一方是发送状态,另一方必须是读取状态

    客户端:

    因为TCP是一种流式传输,传数据像流水一样源源不断,不会自动分割,所以,得通过先传递报头,把即将要发送的文件大小,先告之对方,

    这时,考虑到发送的文件,可能长度很长,无法用普通方法告知服务端,于引入了字典

    将文件大小,文件名等信息,以键传对的形式存入字典,再用json将字典序列化,并用encode编译成二进制,再获取其长度,然后再调用struct包,将字典的长度进行打包,发送给服务端,

    再发送二进制形式的json格式字典

    然后,考虑到一次性读取文件,可能会导致内存溢出的问题,于是,采用读取一行发送一行的方式,减轻内存压力

    服务端:

    因为struct的长度相对固定,要么4位,要么8位,这里用4位接收,

    接收到后,再用struct解析

    获取字典长度

    接收字典,再用decode解码,再用json反序列化,再获取内的信息,如文件大小,文件名,等信息.

    然后用文件存储接收到的数据,采用接收一行写入一行的方式,减轻内存压力

  • 相关阅读:
    Combine 框架,从0到1 —— 4.在 Combine 中使用计时器
    Combine 框架,从0到1 —— 4.在 Combine 中使用通知
    Combine 框架,从0到1 —— 3.使用 Subscriber 控制发布速度
    Combine 框架,从0到1 —— 2.通过 ConnectablePublisher 控制何时发布
    使用 Swift Package Manager 集成依赖库
    iOS 高效灵活地配置可复用视图组件的主题
    构建个人博客网站(基于Python Flask)
    Swift dynamic关键字
    Swift @objcMembers
    仅用递归函数操作逆序一个栈(Swift 4)
  • 原文地址:https://www.cnblogs.com/hellozizi/p/11321397.html
Copyright © 2011-2022 走看看