gRPC实例-python作为服务端,java作为客户端

一、python服务端配置

1、添加依赖

pip install grpcio
pip install protobuf
pip install grpcio_tools

2、编辑协议文件ocrapi.proto

syntax = "proto3"; //说明使用proto3语法定义协议

package com.qlisv.grpc.ocr; // 包名,注意与所在文件夹保持一致

service Ocrapi {

    // 用于识别单色图片上的文字,不包含表情的图片
    rpc getText (ImgRequest) returns (ImgResponse) {}

    // 用于识别复杂的彩色图片上的文字
    rpc getImgText (ImgRequest) returns (ImgResponse) {}
}

message ImgRequest {
    // 文件地址
    string imgPath = 1;
}

message ImgResponse {
    // 识别到的文本内容
    string content = 1;
}

3、进入协议文件所在目录下执行命令

python -m grpc_tools.protoc -I ./ --python_out=. --grpc_python_out=. ocrapi.proto

执行成功后会在协议文件同目录下新生成以下两个文件:
ocrapi_pb2.py 里面有消息序列化类
ocrapi_pb2_grpc.py 包含了服务器 Service 类和客户端 Stub 类,以及待实现的服务 RPC 接口。

文件目录如下:

4、编写服务端脚本ocr_server.py

import grpc
# from concurrent import futures
# from cnstd import CnStd
# from cnocr import CnOcr
# import random

import com.qlisv.grpc.ocr.ocrapi_pb2 as ocrapi_pb2, com.qlisv.grpc.ocr.ocrapi_pb2_grpc as ocrapi_pb2_grpc


class OcrapiServicer(ocrapi_pb2_grpc.OcrapiServicer):

    def getText(self, request, ctx):

        _res = 'msg from server.getText'
        return ocrapi_pb2.ImgResponse(content=_res)

    def getImgText(self, request, context):

        _res = 'msg from server.getImgText'
        return ocrapi_pb2.ImgResponse(content=_res)


def main():

    # 服务端
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
    # 实例化
    servicer = OcrapiServicer()
    # 注册本地服务
    ocrapi_pb2_grpc.add_OcrapiServicer_to_server(servicer, server)
    # 监听端口
    server.add_insecure_port('127.0.0.1:19999')
    # 开始接收请求进行服务
    server.start()
    # 使用 ctrl+c 可以退出服务
    try:
        print("running...")
        server.wait_for_termination()
    except KeyboardInterrupt:
        print("stopping...")
        server.stop(0)


if __name__ == '__main__':
    main()

二、Java客户端配置

1、ocrapi.proto文件配置

使用与python相同的proto文件,放在proto文件夹下,包名和路径也保持一致

2、在maven中加入以下grpc依赖库

<!--grpc-->
<dependency>
    <groupId>io.grpc</groupId>
    <artifactId>grpc-netty-shaded</artifactId>
    <version>1.29.0</version>
</dependency>
<dependency>
    <groupId>io.grpc</groupId>
    <artifactId>grpc-protobuf</artifactId>
    <version>1.29.0</version>
</dependency>
<dependency>
    <groupId>io.grpc</groupId>
    <artifactId>grpc-stub</artifactId>
    <version>1.29.0</version>
</dependency>

3、在maven的build标签下加入以下插件

<extensions>
    <extension>
        <groupId>kr.motd.maven</groupId>
        <artifactId>os-maven-plugin</artifactId>
        <version>1.6.2</version>
    </extension>
</extensions>
<plugins>
    <!--grpc plugin-->
    <plugin>
        <groupId>org.xolstice.maven.plugins</groupId>
        <artifactId>protobuf-maven-plugin</artifactId>
        <version>0.6.1</version>
        <configuration>
            <protocArtifact>com.google.protobuf:protoc:3.12.0:exe:${os.detected.classifier}</protocArtifact>
            <pluginId>grpc-java</pluginId>
            <pluginArtifact>io.grpc:protoc-gen-grpc-java:1.30.0:exe:${os.detected.classifier}</pluginArtifact>
        </configuration>
        <executions>
            <execution>
                <goals>
                    <goal>compile</goal>
                    <goal>compile-custom</goal>
                </goals>
            </execution>
        </executions>
    </plugin>
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
            <source>8</source>
            <target>8</target>
        </configuration>
    </plugin>

</plugins>

4、maven运行clean、package

运行成功后,系统会自动在target\generated-sources\protobuf生成对应的文件目录和文件,文件目录如下:

5、编写java客户端代码

package com.qlisv.grpc.ocr;

import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.StatusRuntimeException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


import java.util.concurrent.TimeUnit;

/**
 * <p> 通过ocr获取图片上的文本 </p>
 *
 * @author AsyDong
 * @version 1.0
 * @time 2020/6/23 16:23
 */
public class OcrapiClient {

    private static final Logger logger = LoggerFactory.getLogger(OcrapiClient.class);

    private ManagedChannel channel;

    private String rpcOcrServer = "127.0.0.1:19999";

    /**
     * Construct client for accessing HelloWorld server using the existing channel.
     */
    public OcrapiClient() {

        this.channel = getChannel();

    }

    private OcrapiGrpc.OcrapiBlockingStub getBlockingStub() {

        // Passing Channels to code makes code easier to test and makes it easier to reuse Channels.
        OcrapiGrpc.OcrapiBlockingStub blockingStub = OcrapiGrpc.newBlockingStub(getChannel());

        return blockingStub;
    }

    private ManagedChannel getChannel() {

        if (channel == null || channel.isShutdown() || channel.isTerminated()) {
            // Create a communication channel to the server, known as a Channel. Channels are thread-safe
            // and reusable. It is common to create channels at the beginning of your application and reuse
            // them until the application shuts down.
            channel = ManagedChannelBuilder.forTarget(rpcOcrServer)
                    // Channels are secure by default (via SSL/TLS). For the example we disable TLS to avoid
                    // needing certificates.
                    .usePlaintext()
                    .build();
        }

        return channel;
    }

    private void closeChannel() {
        try {
            if (channel != null && !channel.isShutdown()) {
                channel.shutdownNow().awaitTermination(5, TimeUnit.SECONDS);
            }
        } catch (InterruptedException e) {
            logger.error("通道关闭异常");
            e.printStackTrace();
        }
    }

    /**
     * 调用服务端的获取图像上的文本
     *
     * @param path 图片地址
     * @author AsyDong
     * @version 1.0
     * @time 2020/6/23 16:23
     */
    public String getText(String path) {

        logger.info(" try to connect server ...");
        try {
            OcrapiOuterClass.ImgRequest request = OcrapiOuterClass.ImgRequest.newBuilder().setImgPath(path).build();
            OcrapiOuterClass.ImgResponse response;

            response = getBlockingStub().getText(request);
            logger.debug("提取结果: " + response.getContent());
            return response.getContent();
        } catch (StatusRuntimeException e) {
            logger.error("RPC failed: {0}", e.getStatus());
            return "";
        } finally {
            closeChannel();
        }
    }

    /**
     * 调用服务端的获取图像上的文本,用于复杂图片背景
     *
     * @param path 图片地址
     * @author AsyDong
     * @version 1.0
     * @time 2020/6/23 16:23
     */
    public String getImgText(String path) {
        logger.info(" try to connect server ...");
        try {
            OcrapiOuterClass.ImgRequest request = OcrapiOuterClass.ImgRequest.newBuilder().setImgPath(path).build();
            OcrapiOuterClass.ImgResponse response;

            response = getBlockingStub().getImgText(request);
            logger.debug("提取结果: " + response.getContent());
            return response.getContent();
        } catch (StatusRuntimeException e) {
            logger.error("RPC failed: {0}", e.getStatus());
            return "";
        } finally {
            closeChannel();
        }
    }

    /**
     * Greet server. If provided, the first element of {@code args} is the name to use in the
     * greeting. The second argument is the target server.
     */
    public static void main(String[] args) throws Exception {
        String path = "d:/TMP/t1.png";

        OcrapiClient client = new OcrapiClient();

        System.out.println(client.getText(path));

        System.out.println(client.getImgText(path));
    }
}

最后先启动python服务端,然后再启动java客户端就可以啦。 

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是一个简单的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()方法,实现了多个客户端同时向服务端发起请求的并发执行。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值