1.gRPC是什么?
在 gRPC里客户端应用可以像调用本地对象一样直接调用另一台不同的机器上服务端应用的方法,使得您能够更容易地创建分布式应用和服务。与许多 RPC系统类似, gRPC也是基于以下理念:
定义一个服务,指定其能够被远程调用的方法(包含参数和返回类型)。在服务端实现这个接口,并运行一个 gRPC服务器来处理客户端调用。
2.gRPC环境安装
(1)进入GOPATH/src/目录下,打开终端输入:
$ git clone https://github.com/junaozun/golang.org
$ git clone https://github.com/junaozun/google.golang.org
(2)解压上面下载的两个压缩包,然后都放入GOPATH/src目录下
(3)测试环境是否安装完好:
启动服务端:
$ cd $GOPATH/src/google.golang.org/grpc/examples/helloworld/greeter_server
$ go run main.go
启动客户端:
$ cd $GOPATH/src/google.golang.org/grpc/examples/helloworld/greeter_client
$ go run main.go
客户端显示hello world表示测试成功,如下图所示:
3.go语言实现gRPC远程调用
(1)protobuf协议定义
a.在src目录下创建grpcProto目录,进入该目录下,创建一个grpcProto.proto文件,内容如下:
b.调用protoc编译器,生成.pb.go文件,这里需要增加grpc插件,如下图所示:
$ protoc --go_out=plugins=grpc:./ *.proto //添加grpc插件
c.我们打开grpcProto.pb.go文件,查看内容:
(2)gRPC服务端
在src目录下创建grpcGo目录,进入该目录下,创建一个grpcServer.go文件,内容如下:
package main
import (
"context"
"fmt"
"google.golang.org/grpc"
pd "grpcProto"
"net"
)
type server struct {}
//打招呼的服务
//func(对象)函数名(context,客户端发送过来的参数)(返回给客户端的参数,错误)
func (this *server) Sayhello(ctx context.Context, in *pd.HelloReq) (out *pd.HelloRsp, err error){
return &pd.HelloRsp{Msg:in.Msg+";你也好,我是服务端"},err
}
//说名字的服务
func (this *server) Sayname(ctx context.Context, in *pd.NameReq) (out *pd.NameRsp,err error){
return &pd.NameRsp{Msg:in.Name+";我的名字叫服务端10010"},err
}
func main() {
//创建网络
listener ,err := net.Listen("tcp","127.0.0.1:8080")
if err != nil{
fmt.Println("网络错误",err)
}
//创建grpc的服务
ser := grpc.NewServer()
//注册服务
pd.RegisterHelloServerServer(ser,&server{})
//等待网络连接
fmt.Println("等待连接中.....")
err = ser.Serve(listener)
if err != nil{
fmt.Println("网络错误",err)
}
}
运行服务端:
(3)gRPC客户端
在src/grpcGo目录下,创建一个grpcClient.go文件,内容如下:
package main
import (
"context"
"fmt"
"google.golang.org/grpc"
pd "grpcProto"
)
func main() {
//客户端连接服务器
conn ,err := grpc.Dial("127.0.0.1:8080",grpc.WithInsecure())
if err != nil{
fmt.Println("网络异常",err)
}
defer conn.Close()
//获取grpc句柄
c := pd.NewHelloServerClient(conn)
//通过句柄调用函数
req1 ,err := c.Sayhello(context.Background(),&pd.HelloReq{Msg:"你好,我是客户端"})
if err != nil{
fmt.Println("Sayhello服务调用失败",err)
}
fmt.Println("调用sayhello函数:",req1.Msg)
req2 ,err := c.Sayname(context.Background(),&pd.NameReq{Name:"我名字叫客户端10086"})
if err != nil{
fmt.Println("Sayname服务调用失败",err)
}
fmt.Println("调用sayname函数:",req2.Msg)
}
运行客户端: