golang 相互引用_grpc在go和java之间进行互相调用的过程-Go语言中文社区

下面记录使用golang开发grpc的服务端程序,然后供java去调用grpc服务的过程,先看服务端proto文件内容

syntax = "proto3";

package proto;

option java_package = "com.test.rpc";

option java_multiple_files = false;

message SayHelloRequest{

bytes name=1;

}

message SayHelloResponse{

bytes result=1;

}

service SayHelloService{

rpc SayHello(SayHelloRequest) returns (SayHelloResponse);

}

以上文件命名为service.proto文件保存,grpc要求每一个方法调用都要有一个请求参数,一个响应参数,这里面的SayHelloRequest就是请求参数,具体来讲grpc远程方法调用时就只需要传递一个name参数,bytes对应的是字符串类型。相对应的SayHelloResponse就是grpc方法调用的返回结果,返回的也是个字符串,参数名称叫做result,具体的grpc方法名称是SayHello。

go语言端通过以下命令生成go代码(在service.proto所在的目录执行):

protoc --go_out=plugins=grpc:. service.proto

命令执行以后会产生一个Service.pb.go文件,里面会自动生成如下内容(部分):

上面自动生成的代码里面的interface就是等待我们去具体实现的grpc服务内容,具体来说就是去具体实现SayHello那个方法,随便找个地方去实现这个方法,例如:

package main

import (

"golang.org/x/net/context"

"google.golang.org/grpc"

"log"

"motorway/proto"

"net"

"runtime"

"strconv"

)

const (

port = "41005"

)

type Data struct{}

func main() {

runtime.GOMAXPROCS(runtime.NumCPU())

//起服务

lis, err := net.Listen("tcp", ":"+port)

if err != nil {

log.Fatalf("failed to listen: %v", err)

}

s := grpc.NewServer()

data:=&Data{}

proto.RegisterSayHelloServiceServer(s,data)

log.Printf("grpc server in: %s", port)

s.Serve(lis)

}

func (t *Data) SayHello(ctx context.Context,in *proto.SayHelloRequest) (result *proto.SayHelloResponse, err error){

return &proto.SayHelloResponse{

Result:[] byte("hello :"+string(in.Name)),

},nil

}

在上面的代码中,Data对象的SayHello就是我们实现的接口方法(因为 go语言实现接口没有implements等关键字,只要写的方法名称,参数,返回值和interface里面的方法定义一样就认为是实现该方法了),上面的main方法里面实例化一个grpc的server,向server对象注册SayHello服务对象data,最后调用Serve方法就可以对外提供grpc服务了。

以上go语言端的grpc服务已经就绪,可以等待调用了,要是急于验证服务的可用性,go的客户端调用代码如下:

package main

import (

"fmt"

"motorway/proto"

"log"

"runtime"

"strconv"

"strings"

"sync"

"time"

"math/rand"

"golang.org/x/net/context"

"google.golang.org/grpc"

)

var (

wg sync.WaitGroup

)

const (

networkType = "tcp"

server = "127.0.0.1" //"172.0.16.111" "172.0.16.105"//"127.0.0.1"

port = "41005"

parallel = 50 //连接并行度

times = 1000 //每连接请求次数

)

func main() {

runtime.GOMAXPROCS(runtime.NumCPU())

currTime := time.Now()

//并行请求

for i := 0; i < int(parallel); i++ {

wg.Add(1)

go func() {

defer wg.Done()

exe()

}()

}

wg.Wait()

log.Printf("time taken: %.2f s ", time.Now().Sub(currTime).Seconds())

}

func exe() {

//建立连接

conn, err := grpc.Dial(server + ":" + port,grpc.WithInsecure())

if nil!=conn{

defer conn.Close()

}

if (nil!=err){

fmt.Printf("创建连接失败!%sn",err)

return

}

client2 := proto.NewSayHelloServiceClient(conn)

for i := 0; i < int(times); i++ {

testSayHello(client2)

}

}

func testSayHello(client proto.SayHelloServiceClient){

req:=&proto.SayHelloRequest{

Name:[]byte("张三"),

}

result,_:=client.SayHello(context.Background(),req)

if nil!=result{

//fmt.Printf("%s n",string(result.Result))

}else{

fmt.Println("response is nil")

}

}

代码里面模拟了50个并发客户端,每个客户端请求调用1000次的情况,在我的i5 cpu机器上面差不多需要4.2s完成这5万次调用。

好了,言归正传,接着说java端怎么进行调用的问题,新建一个spring boot项目,在pom.xml里面增加maven依赖如下:

io.grpc

grpc-netty-shaded

1.20.0

io.grpc

grpc-protobuf

1.20.0

io.grpc

grpc-stub

1.20.0

然后继续在pom.xml的build里面增加plugin等如下(不要完全照搬,就是org.xolstice.maven.plugins那个还有下面那个extensions需要复制):

org.springframework.boot

spring-boot-maven-plugin

org.xolstice.maven.plugins

protobuf-maven-plugin

0.5.1

com.google.protobuf:protoc:3.7.1:exe:${os.detected.classifier}

grpc-java

io.grpc:protoc-gen-grpc-java:1.20.0:exe:${os.detected.classifier}

compile

compile-custom

kr.motd.maven

os-maven-plugin

1.5.0.Final

然后在项目里面建立proto目录,将go语言那边的service.proto文件复制进去,如下图:

然后打开maven工具,找到如下图所示的插件:

先执行protobuf:compile一遍,再执行protobuf:copile-custom,会自动生成如下文件:

正常情况下应该生成两个文件,一个是com.test.rpc.Service,另外一个是com.test.rpc.SayHelloServiceGrpc,回到spring boot application入口main方法,编写如下代码:

package com.grpc;

import com.google.protobuf.ByteString;

import com.test.rpc.SayHelloServiceGrpc;

import com.test.rpc.Service;

import io.grpc.netty.shaded.io.grpc.netty.NegotiationType;

import io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder;

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import java.io.UnsupportedEncodingException;

import java.nio.charset.Charset;

@SpringBootApplication

public class DemoApplication {

private static final String host="127.0.0.1";

private static final int port=41005;

public static void main(String[] args) {

SpringApplication.run(DemoApplication.class, args);

io.grpc.Channel channel = NettyChannelBuilder.forAddress(host, port)

.negotiationType(NegotiationType.PLAINTEXT)

.build();

Service.SayHelloRequest req=Service.SayHelloRequest.newBuilder().setName(ByteString.copyFrom("测试",Charset.forName("utf-8"))).build();

Service.SayHelloResponse result= SayHelloServiceGrpc.newBlockingStub(channel).sayHello(req);

try {

System.out.println(result.getResult().toString("utf-8"));

} catch (UnsupportedEncodingException e) {

e.printStackTrace();

}

}

}

java这边请求参数是通过Service.XXXXX(请求对象).newBuilder().不断的set各个请求参数值(xxx).build()去构造出来的,然后是调用SayHelloServiceGrpc.newBlockingStub(channel).sayHello(req);  这种方式去调用的,grpc貌似有多种调用方式,还没有研究到那么深入,最后是调用结果的输出。

golang服务端程序正确的返回了grpc调用结果。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值