gRPC 实现服务端文件下载(python)

gRPC 客户端(client)从服务端(server)下载文件 python 简单实现

前提准备:

1、gRPC 环境

2、python 环境

3、protobuf tools 生成 python 代码工具

一、编写 Protocol Buffers 文件并编译

编写用于生成 server 与 client 接口代码的 gRPC IDL:file.proto 文件:

创建 file.proto 文件,示例代码:

syntax = "proto3";

package filetransfer;

// file request
message FileRequest {
  string file_path = 1;
  string file_name = 2;
}

// file response
message FileResponse {
  bytes file_content = 1;
}

// the service of file transfer
service FileTransfer {
  // Download file from server to client
  rpc DownloadFile(FileRequest) returns (FileResponse);
}

此文件定义了服务类 FileTransfer 及其实现的方法 DownloadFile 并指定了传入参数 FileRequest 与返回值 FileResponse。

FileRequest 包含两个 string 类型字符串,分别表示想要下载的文件名及其在服务端的存放路径,FileResponse 包含一个 bytes 类型变量,用于传输文件内容。

在 file.proto 目录下启动 powershell 或命令行执行 file.proto 文件编译命令:

python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. file.proto

此命令会在当前目录下生成两个文件:file_pb2.pyfile_pb2_grpc.py,它们包含了基于 Protocol Buffers 定义的消息类型和 gRPC 服务的代码。其中 --python_out 为 file_pb2.py 的输出路径,--grpc_python_out 为 file_pb2_grpc.py 的输出路径。

二、编写 server.py 实现具体业务逻辑

在定义服务接口后,server.py 负责具体服务逻辑的实现。

创建 server.py 文件,示例代码:

import grpc
from concurrent import futures
import time
import file_pb2
import file_pb2_grpc

class FileTransferServicer(file_pb2_grpc.FileTransferServicer):

    def DownloadFile(self, request, context):
        file_name = request.file_name
        file_path = request.file_path

        try:
            # read the file
            print('Prepare to download file: ' + file_path + file_name)
            with open(file_path + file_name, 'rb') as file:
                file_content = file.read()

            # response
            response = file_pb2.FileResponse(file_content=file_content)
            return response
        except FileNotFoundError:
            context.set_code(grpc.StatusCode.NOT_FOUND)
            context.set_details('The file is not exist: ' + file_path + file_name)
            return file_pb2.FileResponse()

def serve():
    # make gRPC server
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))

    # Add server implementation to gRPC server
    file_pb2_grpc.add_FileTransferServicer_to_server(FileTransferServicer(), server)

    # open the port
    server.add_insecure_port('[::]:50051')
    server.start()
    print('The server is running, waiting for connect...')

    try:
        # Blocking threads, continuously providing services
        while True:
            time.sleep(86400)
    except KeyboardInterrupt:
        # close the server
        server.stop(0)


if __name__ == '__main__':
    serve()

class FileTransferServicer 具体实现服务类,其中 DownloadFile 具体实现下载文件方法。

def serve() 实现 server 的实例化,包括创建 server,添加 gRPC 注册,为服务指定端口。

三、编写 client.py 实现服务测试

在实现服务端服务方法后,client.py 负责测试服务端功能(也可使用 grpcurl 等工具进行客户侧测试)。

创建 client.py 文件,示例代码:

import grpc
import file_pb2
import file_pb2_grpc

def download_file_from_server(file_path, file_name, file_save_to_path):
    # make channel connecting 
    channel = grpc.insecure_channel('localhost:50051', options=[
        ('grpc.max_receive_message_length', 2000 * 1024 * 1024) # the max size is 2000MB
    ])

    # make stub
    stub = file_pb2_grpc.FileTransferStub(channel)

    # make request
    request = file_pb2.FileRequest(file_name=file_name, file_path=file_path)

    try:
        # call the DownloadFile method
        response = stub.DownloadFile(request)
        file_content = response.file_content

        file_save_to_path = file_save_to_path

        # save the file to local dir
        with open(file_save_to_path + file_name, 'wb') as file:
            file.write(file_content)

        print('Succeed')
    except grpc.RpcError as e:
        print('Failed: %s' % e.details())

if __name__ == '__main__':
    file_path = 'C:\\file_service/downloadfrom/'  # the file path of server
    file_name = 'test.txt'  # the file name
    file_save_to_path = 'C:\\file_service/downloadto/'  # the local save file path
    download_file_from_server(file_path, file_name, file_save_to_path)

此 client 端测试代码实现将 test.txt 文件从 server 端(downloadfrom 目录)下载到 client 端(downloadto 目录),在具体实践中 server 与 client 可能不在同一台主机上,可自行指定目录。 

客户端的实例包括创建存根 stub,初始化传入数据 request 及针对服务端提供的端口调用方法,若客户端与服务器不在同一主机,还需自行指定域名或 IP 地址。

四、运行 server.py 及 client.py

分别在不同的终端执行以下命令:

server.py 目录下,运行:

python server.py

此时服务端会在指定端口(本文为 50051)上执行监听,显示:

The server is running, waiting for connect...

client.py 目录下,运行:

python client.py

客户端将对服务端提供的端口发送下载文件请求,而后将指定文件下载至指定目录下。

此时服务端显示:

Prepare to download file: C:\file_service/downloadfrom/test.txt

下载成功,客户端显示:

Succeed

文件成功从服务端(downloadfrom 目录)下载至(downloadto 目录)。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
下面是一个简单的Python代码示例,演示如何使用gRPC实现客户服务的多进程并发执行: 服务代码: ```python import grpc from concurrent import futures import time import hello_pb2 import hello_pb2_grpc class HelloService(hello_pb2_grpc.HelloServicer): def sayHello(self, request, context): print("Received message: ", request.message) return hello_pb2.HelloReply(message="Hello, %s!" % request.message) def serve(): server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) hello_pb2_grpc.add_HelloServicer_to_server(HelloService(), server) server.add_insecure_port("[::]:50051") server.start() print("Server started at [::]:50051") while True: time.sleep(86400) if __name__ == '__main__': serve() ``` 客户代码: ```python import grpc import hello_pb2 import hello_pb2_grpc from concurrent import futures import multiprocessing def run_client(): channel = grpc.insecure_channel("localhost:50051") stub = hello_pb2_grpc.HelloStub(channel) response = stub.sayHello(hello_pb2.HelloRequest(message="world")) print("Response received from server: ", response.message) if __name__ == '__main__': pool = multiprocessing.Pool(processes=4) for i in range(4): pool.apply_async(run_client) pool.close() pool.join() ``` 在上面的示例中,服务使用了Python的concurrent.futures模块创建了一个线程池,用于处理客户的请求,同时使用了Python的multiprocessing模块创建了多个子进程,同时向服务发起请求。客户通过调用multiprocessing.Pool()方法创建进程池,并使用apply_async()方法异步调用run_client()方法,实现了多个客户同时向服务发起请求的并发执行。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值