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反序列化,再获取内的信息,如文件大小,文件名,等信息.

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

  • 相关阅读:
    embed 与 object
    通道
    Silverlight 插件中的FindName方法使用
    RenderTransformOrigin 的作用
    Photoshop工具与绘图
    Silverlight动画
    VS2005 数据连接提示:该项不适于在指定状态下使用
    IIS6注册.net4.0
    .NET中的动态编译
    DevExpress换肤
  • 原文地址:https://www.cnblogs.com/hellozizi/p/11321397.html
Copyright © 2011-2022 走看看