python-文件上传下载(Python file upload and download)

一、数据粘包

【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()
————————

一、数据粘包

【1】 The client sends the request twice, but it may be received by the same recv of the server, which cannot be distinguished, resulting in data sticking packets (in fact, the server needs to accept the two requests separately)

二、服务器
# -*- 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()

3、 Client

# -*- 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()