python-文件上传下载
一、数据粘包
【1】客户端两次发送请求,但是可能被服务端的同个recv收到,不能区分,会造成数据粘包(实际上需要服务端将两次请求区分接受)
二、服务器
# -*- coding:utf-8 -*-
# __author__:pansy
# 2022/5/14
import socket
# 创建socket对象
sk = socket.socket()
# 给服务器绑定ip和端口
sk.bind(('127.0.0.1',8889))
# 创建监听,监听客户端是否有发请求过来
sk.listen()
def get_file(sk_obj):
'''
接收文件
:param sk_obj: 文件对象
:return:
'''
# 从服务端会发送1个请求,用来传输文件大小,文件大小是整形,需要将string类型强转成int类型
file_size = int(sk_obj.recv(1024).decode('utf8'))
# 为了避免粘包,当执行完接收file_size语句后,需要告知post_file,文件大小已经接收成功
sk_obj.sendall(b'ok')
# 从服务端会发送1个请求,用来传输文件名称
file_name = sk_obj.recv(1024).decode('utf8')
sk_obj.sendall(b'ok')
# 接收文件内容
with open('./%s' %file_name,'wb') as f:
while file_size > 0:
f.write(sk_obj.recv(1024))
file_size -= 1024
# 阻塞状态,若接收到数据,则阻塞解除
# accept返回一个套接字和客户端的ip端口
conn ,addr = sk.accept()
# 调用接收文件方法,conn是专门用来处理客户端业务的套接字
get_file(conn)
conn.close()
sk.close()
三、客户端
# -*- coding:utf-8 -*-
# __author__:pansy
# 2022/5/14
import os
import socket
# 创建socket对象
sk = socket.socket()
# 连接服务器,连接的是服务器绑定的ip和端口
sk.connect(('127.0.0.1',8889))
def post_file(sk_obj,file_path):
'''
发送文件,需要和接收文件一一对应
:param sk_obj:文件对象
:param file_path:文件路径
:return:
'''
# 发送文件大小,用os.stat方法可以获取文件属性
file_size = os.stat(file_path).st_size
# 获取到的file_size是整形,不能直接编码,所以需要先强转成字符串
sk_obj.sendall(str(file_size).encode('utf8'))
# 为了避免粘包,需要用recv接收下参数,直到接收到ok后,才会继续下面的代码
sk_obj.recv(1024)
# 发送文件名称,用os.path.split方法,可以将文件路径切割成路径和文件名,返回这两个字段
file_name = os.path.split(file_path)[1]
sk_obj.sendall(file_name.encode('utf8'))
sk_obj.recv(1024)
# 发送文件内容,循环发送,1次发送1024个字节
# 1、先读取文件,用rb二进制读取
with open(file_path,'rb') as f:
# 每发送1次,file_size会减少1024,不满足1024的,全部发送
while file_size > 0:
sk_obj.sendall(f.read(1024))
file_size -= 1024
# 调用发送文件方法
path = '/Users/panshaoying/Desktop/database/data/img1.png'
post_file(sk,path)
sk.close()