Golang-gRPC的简单使用

1、环境准备 grpc 编码之前需要准备以下环境:

  • 安装protobuf:https://blog.csdn.net/weixin_42117918/article/details/88920221
  • 安装gRPC runtime:go get google.golang.org/grpc(一般下载不了)
解决办法:
grpc官方提供的下载命令是:
go get google.golang.org/grpc

因为无法访问,所以我们需要在$GOPATH/src目录下面创建一个google.golang.org的目录。
在github上找到对应的grpc的包,https://github.com/grpc/grpc-go
其实google.golang.org对应的就是https://github.com/grpc/grpc-go
然后我们进入到$GOPATH/src/google.golang.org这个目录。执行git命令
git clone --depth=1 https://github.com/grpc/grpc-go.git grpc


命令解析:
其中--depth=1 这个参数的意思是只克隆最新的commit分支。不加也行。
最后的grpc表示的是将克隆的文件存放到那个文件夹里面。
执行完上面的命令,我们就成功的将grpc的包下载到本地了。
  • 安装GoLang protoc 插件
go get -a github.com/golang/protobuf/protoc-gen-go

如果缺少:golang.org/x 包,或者此包无法下载,解决方法:
git clone https://github.com/golang/sys.git $GOPATH/src/github.com/golang/sys git clone https://github.com/golang/net.git $GOPATH/src/github.com/golang/net git clone https://github.com/golang/text.git $GOPATH/src/github.com/golang/text git clone https://github.com/golang/lint.git $GOPATH/src/github.com/golang/lint git clone https://github.com/golang/tools.git $GOPATH/src/github.com/golang/tools git clone https://github.com/golang/crypto.git $GOPATH/src/github.com/golang/crypto git clone https://github.com/golang/time.git $GOPATH/src/github.com/golang/crypto ln -s $GOPATH/src/github.com/golang/ $GOPATH/src/golang.org/x

或者手动下载:
下载: https://github.com/golang/sys.git #改名:sys 下载: https://github.com/golang/net.git #改名:net 下载: https://github.com/golang/text.git #改名:text 下载: https://github.com/golang/lint.git #改名:lint 下载: https://github.com/golang/tools.git #改名:tools 下载: https://github.com/golang/crypto.git #改名:crypto 下载: https://github.com/golang/time.git #改名:time 放在对应的:src/golang.org/x 目录下

go get github.com/xxx/xxx 出现 :fatal: early EOF时解决方法:
git config --global --add core.compression -1
2、protobuf文件
syntax="proto3"; package hello; // 请求参数-根据自己的需求定义 message HelloRequest{ string greeting=1; } // 返回参数-根据自己的需求定义 message HelloResponse{ string reply=1; } // 定义一个HelloMyService服务,其中API为SayHello // 形式参数: HelloRequest // 返回参数:HelloResponse service HelloMyService { rpc SayHello(HelloRequest) returns (HelloResponse){} // rpc 借口的类型分为一下四种: A为接受参数,B为返回参数 // 1. rpc GetFeature(Point) returns (Feature) {} 普通调用:A-B // 2. rpc ListFeatures(Rectangle) returns (stream Feature) {} 单向流:A - B(流) // 3. rpc RecordRoute(stream Point) returns (RouteSummary) {} 单向流:A(流) - B // 4. rpc RouteChat(stream RouteNote) returns (stream RouteNote) {} 双向流:A(流) - B(流) }

3、将protobuf文件(文件名为:hello)生成go文件
protoc --go_out=plugins=grpc:. hello.proto

生成对应的文件(文件名为:hello.pb.go)内容为:
// Code generated by protoc-gen-go. DO NOT EDIT. // source: hello.protopackage helloimport ( context "context" fmt "fmt" proto "github.com/golang/protobuf/proto" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" math "math" )// Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal var _ = fmt.Errorf var _ = math.Inf// This is a compile-time assertion to ensure that this generated file // is compatible with the proto package it is being compiled against. // A compilation error at this line likely means your copy of the // proto package needs to be updated. const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package// 请求参数-根据自己的需求定义 type HelloRequest struct { Greetingstring`protobuf:"bytes,1,opt,name=greeting,proto3" json:"greeting,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized[]byte`json:"-"` XXX_sizecacheint32`json:"-"` }func (m *HelloRequest) Reset(){ *m = HelloRequest{} } func (m *HelloRequest) String() string { return proto.CompactTextString(m) } func (*HelloRequest) ProtoMessage(){} func (*HelloRequest) Descriptor() ([]byte, []int) { return fileDescriptor_61ef911816e0a8ce, []int{0} }func (m *HelloRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_HelloRequest.Unmarshal(m, b) } func (m *HelloRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_HelloRequest.Marshal(b, m, deterministic) } func (m *HelloRequest) XXX_Merge(src proto.Message) { xxx_messageInfo_HelloRequest.Merge(m, src) } func (m *HelloRequest) XXX_Size() int { return xxx_messageInfo_HelloRequest.Size(m) } func (m *HelloRequest) XXX_DiscardUnknown() { xxx_messageInfo_HelloRequest.DiscardUnknown(m) }var xxx_messageInfo_HelloRequest proto.InternalMessageInfofunc (m *HelloRequest) GetGreeting() string { if m != nil { return m.Greeting } return "" }// 返回参数-根据自己的需求定义 type HelloResponse struct { Replystring`protobuf:"bytes,1,opt,name=reply,proto3" json:"reply,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized[]byte`json:"-"` XXX_sizecacheint32`json:"-"` }func (m *HelloResponse) Reset(){ *m = HelloResponse{} } func (m *HelloResponse) String() string { return proto.CompactTextString(m) } func (*HelloResponse) ProtoMessage(){} func (*HelloResponse) Descriptor() ([]byte, []int) { return fileDescriptor_61ef911816e0a8ce, []int{1} }func (m *HelloResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_HelloResponse.Unmarshal(m, b) } func (m *HelloResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_HelloResponse.Marshal(b, m, deterministic) } func (m *HelloResponse) XXX_Merge(src proto.Message) { xxx_messageInfo_HelloResponse.Merge(m, src) } func (m *HelloResponse) XXX_Size() int { return xxx_messageInfo_HelloResponse.Size(m) } func (m *HelloResponse) XXX_DiscardUnknown() { xxx_messageInfo_HelloResponse.DiscardUnknown(m) }var xxx_messageInfo_HelloResponse proto.InternalMessageInfofunc (m *HelloResponse) GetReply() string { if m != nil { return m.Reply } return "" }func init() { proto.RegisterType((*HelloRequest)(nil), "hello.HelloRequest") proto.RegisterType((*HelloResponse)(nil), "hello.HelloResponse") }func init() { proto.RegisterFile("hello.proto", fileDescriptor_61ef911816e0a8ce) }var fileDescriptor_61ef911816e0a8ce = []byte{ // 145 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0xce, 0x48, 0xcd, 0xc9, 0xc9, 0xd7, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x05, 0x73, 0x94, 0xb4, 0xb8, 0x78, 0x3c, 0x40, 0x8c, 0xa0, 0xd4, 0xc2, 0xd2, 0xd4, 0xe2, 0x12, 0x21, 0x29, 0x2e, 0x8e, 0xf4, 0xa2, 0xd4, 0xd4, 0x92, 0xcc, 0xbc, 0x74, 0x09, 0x46, 0x05, 0x46, 0x0d, 0xce, 0x20, 0x38, 0x5f, 0x49, 0x95, 0x8b, 0x17, 0xaa, 0xb6, 0xb8, 0x20, 0x3f, 0xaf, 0x38, 0x55, 0x48, 0x84, 0x8b, 0xb5, 0x28, 0xb5, 0x20, 0xa7, 0x12, 0xaa, 0x12, 0xc2, 0x31, 0xf2, 0xe4, 0xe2, 0x03, 0x2b, 0xf3, 0xad, 0x0c, 0x4e, 0x2d, 0x2a, 0xcb, 0x4c, 0x4e, 0x15, 0x32, 0xe7, 0xe2, 0x08, 0x4e, 0xac, 0x04, 0x0b, 0x0a, 0x09, 0xeb, 0x41, 0x5c, 0x81, 0x6c, 0xab, 0x94, 0x08, 0xaa, 0x20, 0xc4, 0x78, 0x25, 0x86, 0x24, 0x36, 0xb0, 0x5b, 0x8d, 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, 0x49, 0xb3, 0x8a, 0xab, 0xba, 0x00, 0x00, 0x00, }// Reference imports to suppress errors if they are not otherwise used. var _ context.Context var _ grpc.ClientConn// This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. const _ = grpc.SupportPackageIsVersion4// HelloMyServiceClient is the client API for HelloMyService service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. type HelloMyServiceClient interface { SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloResponse, error) }type helloMyServiceClient struct { cc *grpc.ClientConn }func NewHelloMyServiceClient(cc *grpc.ClientConn) HelloMyServiceClient { return &helloMyServiceClient{cc} }func (c *helloMyServiceClient) SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloResponse, error) { out := new(HelloResponse) err := c.cc.Invoke(ctx, "/hello.HelloMyService/SayHello", in, out, opts...) if err != nil { return nil, err } return out, nil }// HelloMyServiceServer is the server API for HelloMyService service. type HelloMyServiceServer interface { SayHello(context.Context, *HelloRequest) (*HelloResponse, error) }// UnimplementedHelloMyServiceServer can be embedded to have forward compatible implementations. type UnimplementedHelloMyServiceServer struct { }func (*UnimplementedHelloMyServiceServer) SayHello(ctx context.Context, req *HelloRequest) (*HelloResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method SayHello not implemented") }func RegisterHelloMyServiceServer(s *grpc.Server, srv HelloMyServiceServer) { s.RegisterService(&_HelloMyService_serviceDesc, srv) }func _HelloMyService_SayHello_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(HelloRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(HelloMyServiceServer).SayHello(ctx, in) } info := &grpc.UnaryServerInfo{ Server:srv, FullMethod: "/hello.HelloMyService/SayHello", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(HelloMyServiceServer).SayHello(ctx, req.(*HelloRequest)) } return interceptor(ctx, in, info, handler) }var _HelloMyService_serviceDesc = grpc.ServiceDesc{ ServiceName: "hello.HelloMyService", HandlerType: (*HelloMyServiceServer)(nil), Methods: []grpc.MethodDesc{ { MethodName: "SayHello", Handler:_HelloMyService_SayHello_Handler, }, }, Streams:[]grpc.StreamDesc{}, Metadata: "hello.proto", }

4、服务器、客户端代码实例 (1)服务器端代码
package mainimport ( "context" "fmt" "google.golang.org/grpc" pb "hello" "net" )const ( port = ":8088" )type server struct { }func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloResponse, error) { result := &pb.HelloResponse{} fmt.Println(in.Greeting) result.Reply = "这里是服务器,请求服务成功!" return result, nil} /* 1. 首先我们必须实现我们自定义rpc服务,例如:rpc SayHello()-在此我们可以实现我们自己的逻辑 2. 创建监听listener 3. 创建grpc的服务 4. 将我们的服务注册到grpc的server中 5. 启动grpc服务,将我们自定义的监听信息传递给grpc客户端 */ func main() { //创建server端监听端口 listener, err := net.Listen("tcp", port) if err!=nil { fmt.Println(err) return } defer listener.Close() myServer:=grpc.NewServer()//创建grpc的service pb.RegisterHelloMyServiceServer(myServer,&server{})//注册服务 fmt.Println("启动grpc服务...") myServer.Serve(listener)//启动监听服务 }

(2)客户端代码
package mainimport ( "context" "fmt" "google.golang.org/grpc" pb "hello" ) //访问服务的IP及端口,要与服务端的IP、端口对应 const address="127.0.0.1:8088" /* 1. 创建groc连接器 2. 创建grpc客户端,并将连接器赋值给客户端 3. 向grpc服务端发起请求 4. 获取grpc服务端返回的结果 */ func main() { //创建一个grpc的连接 conn, err := grpc.Dial(address, grpc.WithInsecure()) if err !=nil{ fmt.Println(err) return } defer conn.Close() //创建grpc客户端 c := pb.NewHelloMyServiceClient(conn) request:=&pb.HelloRequest{} request.Greeting="我是客户端,请求连接..." fmt.Println("开始请求服务...") //客户端向服务端发送请求,同时返回服务端的结果 result, err := c.SayHello(context.Background(), request) if err !=nil{ fmt.Println(err) return } fmt.Println(result.Reply) }

5、运行结果 首先启动服务端,再次启动客户端(一般防火墙会提示是否运行网络访问,运行即可)。执行结果分别如下:
Golang-gRPC的简单使用
文章图片

【Golang-gRPC的简单使用】Golang-gRPC的简单使用
文章图片

    推荐阅读