首页 > 其他分享 >socket与struct实战应用(传输文件)

socket与struct实战应用(传输文件)

时间:2022-12-25 14:44:07浏览次数:31  
标签:实战 文件大小 socket 字典 struct client file 接收 size

服务端

需求:制作一个可以接收文件的服务,操作客户端往服务端传输文件

服务端代码

import struct
import socket
import json
import os

# 1. 先起动服务端服务
server = socket.socket()
server.bind(('localhost', 18000))
server.listen(5)
by_client, addr = server.accept()
# 2. 接收客户端发送来的字典报头信息
by_client_stru_size = by_client.recv(4)
# 3. 接收后进行解压,获取到真实的字典大小
by_client_dict_size = struct.unpack('i', by_client_stru_size)[0]
# 4. 按真实的字典大小进行接收客户端的字典信息,并使用json反序列化,得到字典信息
# 4. 这时候的文件大小为by_client_dict.get('file_size')
by_client_dict = json.loads(by_client.recv(by_client_dict_size))
file_size = by_client_dict.get('file_size')
# 5. 打开一个文件,并将接收到的二进制信息写入到文件中
with open(by_client_dict.get('file_name'), 'wb') as f:
    while True:
        '''
        思路:
            1. 每次接收到的文件大小不宜过大,否则会过度消耗服务器资源,最大不要设置超过1024*8大小
            2. 因为是三次握手为流式接收文件,所以多次接收没有问题。
        '''
        # 1. 先获取当前服务器本身文件大小(首次肯定是0)
        server_file_size = os.path.getsize(by_client_dict.get('file_name'))
        # 2. file_size为最终文件大小,这个是从字典中获取到的,客户端在发送的时候就指定好了
        # 2. 真实文件大小减去服务器当时文件的大小,可得到还未接收到的文件大小
        receive_server_file_size = file_size - server_file_size
        # 3. 如果还未接收到的文件大于1024字节,则接收的时候就使用1024大小进行接收
        #   例如:本次接收的文件为57123945字节大小,那么前几次接收后,未接收到的文件大小依次为:
        #       57,122,921/57,121,897/57,120,873....接收55785次后还剩105字节大小
        if receive_server_file_size > 1024:
            f.write(by_client.recv(1024))
        # 4. 如果接收到最后,未接收到的文件小于或者等于1024,则使用还未接收到的文件大小进行接收
        #   接第三步的例子,现在还剩105字节大小
        elif receive_server_file_size <= 1024:  # 此时105 < 1024,就走这个if分支
            f.write(by_client.recv(receive_server_file_size))  # 这时候就按105字节进行接收
            print('文件接收成功')  # 走到这个if分支证明文件已传输至最后,传输完这次后打印接收成功
            break  # 最后跳出循环,不再接收文件

客户端代码:

import struct, socket, os, json

client = socket.socket()
# 1. 客户端连接服务器
client.connect(('localhost', 18000))
# 2. 获取真实文件大小
file_size = os.path.getsize(r'D:\迅雷下载\Edius_Pro_8.10.188.rar')
# 3. 定义字典,将真实文件大小写入进去
send_dict = {
    'file_name': 'edius_test.rar',
    'file_size': file_size,
    'file_info': '我是一个视频剪辑软件,很多人都在用!'
}
# 4. 序列化字典
file_json = json.dumps(send_dict).encode('utf8')
# 5. 获取字典的真实长度,将真实长度制作成头部信息并发送给服务器端,这样,服务端就可以根据字典的真实长度来接收字典了。
file_head = struct.pack('i', len(file_json))
# 6. 将制作好的报头发送给服务端,服务端进行解压后可得出序列化后的字典长度,再根据字典长度进行接收
client.send(file_head)
# 7. 发送字典,字典中有记录真实的文件大小信息,也就是file_size,服务端解压后,获取到真实的file_size后,再根据file_size大小制定接收的策略
client.send(file_json)
# 8. 最后一步发送真实的文件。
with open(r'D:\迅雷下载\Edius_Pro_8.10.188.rar', 'rb') as f:
    # 分步发送的原因是,可以节省内存开支,如果是非常大的文件,会占用大量内存,有可能会撑暴
    for line in f:
        client.send(line)
print('文件已发送完成')

标签:实战,文件大小,socket,字典,struct,client,file,接收,size
From: https://www.cnblogs.com/smyz/p/17004017.html

相关文章