服务端
需求:制作一个可以接收文件的服务,操作客户端往服务端传输文件
服务端代码
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