grpc双向流

简介

grpc是一个高性能、开源和通用的 RPC 框架,面向移动和 HTTP/2 设计。目前提供 C、Java 和 Go 语言版本,分别是:grpc, grpc-java, grpc-go. 其中 C 版本支持 C, C++, Node.js, Python, Ruby, Objective-C, PHP 和 C# 支持.

gRPC 基于 HTTP/2 标准设计,带来诸如双向流、流控、头部压缩、单 TCP 连接上的多复用请求等特。这些特性使得其在移动设备上表现更好,更省电和节省空间占用。

开发环境配置

首先配置maven引用jar包,导入全部grpc用的包,也可不全部导入,我这里求方便。

<dependency>
  <groupId>io.grpc</groupId>
  <artifactId>grpc-all</artifactId>
  <version>1.17.1</version>
</dependency>
<dependency>复制代码

然后引入protobuf文件解析和代码生成:

<extensions>
   <extension>
      <groupId>kr.motd.maven</groupId>
      <artifactId>os-maven-plugin</artifactId>
      <version>1.5.0.Final</version>
   </extension>
</extensions>
<plugins>
   <plugin>
      <groupId>org.xolstice.maven.plugins</groupId>
      <artifactId>protobuf-maven-plugin</artifactId>
      <version>0.5.1</version>
      <configuration>
         <protocArtifact>com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier}</protocArtifact>
         <pluginId>grpc-java</pluginId>
         <pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}: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-enforcer-plugin</artifactId>
      <version>1.4.1</version>
      <executions>
         <execution>
            <id>enforce</id>
            <goals>
               <goal>enforce</goal>
            </goals>
            <configuration>
               <rules>
                  <requireUpperBoundDeps/>
               </rules>
            </configuration>
         </execution>
      </executions>
   </plugin>
</plugins>复制代码

引入后,在idea中maven projects中的plugins中就会看到protobuf,在这个里面就能生成所需要的java文件。到“lifecycle”中执行compile或者执行maven命令“mvn compile”,就能生成需要的java文件。


注:定义的protobuf文件要与“java,resources”同级。


入门实例

grpc Client:

import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import java.util.concurrent.TimeUnit;


public class HelloWorldClient {

  private final ManagedChannel channel;
  
  private static final GreeterGrpc.GreeterBlockingStub blockingStub;
  
  HelloWorldClient(String host, int port) {
    this.channel =  ManagedChannelBuilder.forAddress(host, port)
            .usePlaintext()
            .build();
    blockingStub = GreeterGrpc.newBlockingStub(channel);
  }

  public void shutdown() throws InterruptedException {
    channel.shutdown().awaitTermination(5, TimeUnit.SECONDS);
  }

  public static void main(String[] args) throws Exception {
    HelloWorldClient client = new HelloWorldClient("localhost", 50051);
    try {
      blockingStub.sayHello(HelloRequest.newBuilder().setName("hello").build();) 
    } finally {
      client.shutdown();
    }
  }
}
复制代码

grpc-server


import io.grpc.Server;
import io.grpc.ServerBuilder;
import io.grpc.stub.StreamObserver;
import java.io.IOException;
import java.util.logging.Logger;


public class HelloWorldServer {
  private static final Logger logger = Logger.getLogger(HelloWorldServer.class.getName());

  private Server server;

  private void start() throws IOException {
    int port = 50051;
    server = ServerBuilder.forPort(port)
        .addService(new GreeterImpl())
        .build()
        .start();
    Runtime.getRuntime().addShutdownHook(new Thread() {
      @Override
      public void run() {
        HelloWorldServer.this.stop();
      }
    });
  }

  private void stop() {
    if (server != null) {
      server.shutdown();
    }
  }

  /**
   * 等待主线程终止,因为GRPC库使用守护进程线程。
   */
  private void blockUntilShutdown() throws InterruptedException {
    if (server != null) {
      server.awaitTermination();
    }
  }

  public static void main(String[] args) throws IOException, InterruptedException {
    final HelloWorldServer server = new HelloWorldServer();
    server.start();
    server.blockUntilShutdown();
  }

  static class GreeterImpl extends GreeterGrpc.GreeterImplBase {

    @Override
    public void sayHello(HelloRequest req, StreamObserver<HelloReply> responseObserver) {
      HelloReply reply = HelloReply.newBuilder().setMessage("Hello " + req.getName()).build();
      responseObserver.onNext(reply);
      responseObserver.onCompleted();
    }
  }
}
复制代码


官方入门实例详见:https://github.com/grpc/grpc-java/tree/master/examples/src/main/java/io/grpc/examples/helloworld

双向流

server :

    Map<String,StreamObserver<Object> > streamObserverMap = new HashMap();
 static class GreeterImpl extends GreeterGrpc.GreeterImplBase {

    @Override
    public void sayHello(HelloRequest req, StreamObserver<HelloReply> responseObserver) {
      HelloReply reply = HelloReply.newBuilder().setMessage("Hello " + req.getName()).build();
          //客户端调用时,将observer保存起
      streamObserverMap.put("sayHello",responseObserver);
    }
  }    /**
    * 发送消息
    */
    public void sendMsgToclient() {
        //使用时,从保存的streamObserver调用onNext()
        StreamObserver<Object> streamObserver = streamObserverMap.get("sayHello");
        streamObserver.onNext();
        //这里注意不要调用onCompleted()方法,onCompleted()会将流关闭。当然如果这个流不用了你可以关闭
//        responseObserver.onCompleted();
    }
复制代码

Client:

//客户端要在连接上服务端的时候要显示的调用sendMsg方法,作为流的注册
  public static void main(String[] args) throws Exception {
    HelloWorldClient client = new HelloWorldClient("localhost", 50051);
    try {
      //注册StreamObserver
      blockingStub.sayHello(HelloRequest.newBuilder().setName("").build()) 
    } finally {
      client.shutdown();
    }
  }复制代码


参考:grpc官方文档(http://doc.oschina.net/grpc?t=58008)


如有写的不对地方欢迎在评论指出。




### gRPC 双向流式通信与 Protocol Buffer 集成使用指南 gRPC双向流式通信是一种客户端和服务端都可以持续发送和接收数据流的通信方式。这种通信模式非常适合需要实时数据交换的场景,例如实时聊天、实时数据同步、流媒体等应用场景[^2]。Protocol Buffer(简称 Protobuf)作为 gRPC 的默认数据序列化机制,为双向流式通信提供了结构化的数据定义和高效的序列化能力。 #### 1. 定义 `.proto` 接口文件 在使用双向流式通信时,首先需要在 `.proto` 文件中定义一个 `rpc` 方法,并使用 `stream` 关键字指定客户端和服务端都可以发送流式数据。例如: ```proto syntax = "proto3"; package example; service ChatService { rpc ChatStream(stream ChatMessage) returns (stream ChatResponse); } message ChatMessage { string user = 1; string message = 2; } message ChatResponse { string reply = 1; } ``` 在上述定义中,`ChatStream` 是一个双向流式方法,客户端可以发送多个 `ChatMessage`,服务端也可以返回多个 `ChatResponse`。这种定义方式充分利用了 Protobuf 的结构化数据定义能力[^3]。 #### 2. 生成服务端与客户端代码 使用 `protoc` 编译器配合 gRPC 插件生成服务端和客户端的代码。以 Go 语言为例,命令如下: ```bash protoc --go_out=. --go-grpc_out=. chat.proto ``` 生成的代码包括服务接口、客户端存根以及消息类型的序列化和反序列化方法。这些代码为实现双向流提供了基础结构。 #### 3. 实现服务端逻辑 在服务端,需要实现一个函数来处理双向流。以 Go 语言为例,代码如下: ```go func (s *ChatServer) ChatStream(stream pb.ChatService_ChatStreamServer) error { for { // 接收客户端消息 in, err := stream.Recv() if err != nil { return err } // 处理消息并发送响应 response := &pb.ChatResponse{ Reply: "Server received: " + in.Message, } if err := stream.Send(response); err != nil { return err } } } ``` 服务端通过 `Recv()` 方法接收客户端发送的消息流,并通过 `Send()` 方法向客户端发送响应流。 #### 4. 实现客户端逻辑 在客户端,可以通过调用 `ChatStream` 方法并使用 `Send()` 和 `Recv()` 方法进行双向通信。例如: ```go client, err := grpc.Dial("localhost:50051", grpc.WithInsecure()) if err != nil { log.Fatalf("did not connect: %v", err) } defer client.Close() c := pb.NewChatServiceClient(client) stream, err := c.ChatStream(context.Background()) if err != nil { log.Fatalf("failed to open stream: %v", err) } // 启动一个 goroutine 接收服务端响应 go func() { for { reply, err := stream.Recv() if err != nil { log.Fatalf("failed to receive: %v", err) } fmt.Println(reply.Reply) } }() // 发送消息到服务端 messages := []string{"Hello", "How are you?", "Goodbye"} for _, msg := range messages { if err := stream.Send(&pb.ChatMessage{User: "Client", Message: msg}); err != nil { log.Fatalf("failed to send: %v", err) } } ``` 客户端通过 `Send()` 方法发送消息流,并通过 `Recv()` 方法接收服务端的响应流,从而实现双向通信。 #### 5. 运行与测试 启动服务端并监听指定端口后,运行客户端代码即可进行双向流式通信测试。通过这种方式,可以验证数据是否正确地在客户端和服务端之间流动,并确保 Protobuf 的序列化和反序列化过程无误。 ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值