网络编程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'\r{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反序列化,再获取内的信息,如文件大小,文件名,等信息.

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

 

posted @ 2019-08-08 16:13  去遇见最好的自己  阅读(160)  评论(0编辑  收藏  举报