1 go get -u github.com/golang/protobuf/proto
go get -u github.com/golang/protobuf/protoc-gen-go
2 下载 https://github.com/google/protobuf/releases
将bin目录添加到path目录下。
3 编写proto文件rpctest.proto
// 使用方法:protoc -I ./rpctest/ ./rpctest/rpctest.proto --go_out=plugins=grpc:rpctest
syntax = "proto3";
package serverpb;
service funcname
{
rpc FuncName(MessReq) returns (MessRes);
};
message MessReq{
int32 NameId = 1 [ json_name="nameid" ];
};
message MessRes{
int32 result = 1;
};
//
执行方法:protoc -I ./rpctest/ ./rpctest/rpctest.proto –go_out=plugins=grpc:rpctest
【grpc 示例】路径根据自己的路径来处理
4 生成go文件。 就会获取到
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: funname.protopackage serverpbimport proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"import (
context "golang.org/x/net/context"
grpc "google.golang.org/grpc"
)// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inftype MessReq struct {
NameId int32 `protobuf:"varint,1,opt,name=NameId,json=nameid" json:"NameId,omitempty"`
}func (m *MessReq) Reset(){ *m = MessReq{} }
func (m *MessReq) String() string{ return proto.CompactTextString(m) }
func (*MessReq) ProtoMessage(){}
func (*MessReq) Descriptor() ([]byte, []int) { return fileDescriptor3, []int{0} }func (m *MessReq) GetNameId() int32 {
if m != nil {
return m.NameId
}
return 0
}type MessRes struct {
Result int32 `protobuf:"varint,1,opt,name=result" json:"result,omitempty"`
}func (m *MessRes) Reset(){ *m = MessRes{} }
func (m *MessRes) String() string{ return proto.CompactTextString(m) }
func (*MessRes) ProtoMessage(){}
func (*MessRes) Descriptor() ([]byte, []int) { return fileDescriptor3, []int{1} }func (m *MessRes) GetResult() int32 {
if m != nil {
return m.Result
}
return 0
}func init() {
proto.RegisterType((*MessReq)(nil), "serverpb.MessReq")
proto.RegisterType((*MessRes)(nil), "serverpb.MessRes")
}// 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// Client API for Funcname servicetype FuncnameClient interface {
FuncName(ctx context.Context, in *MessReq, opts ...grpc.CallOption) (*MessRes, error)
}type funcnameClient struct {
cc *grpc.ClientConn
}func NewFuncnameClient(cc *grpc.ClientConn) FuncnameClient {
return &funcnameClient{cc}
}func (c *funcnameClient) FuncName(ctx context.Context, in *MessReq, opts ...grpc.CallOption) (*MessRes, error) {
out := new(MessRes)
err := grpc.Invoke(ctx, "/serverpb.funcname/FuncName", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}// Server API for Funcname servicetype FuncnameServer interface {
FuncName(context.Context, *MessReq) (*MessRes, error)
}func RegisterFuncnameServer(s *grpc.Server, srv FuncnameServer) {
s.RegisterService(&_Funcname_serviceDesc, srv)
}func _Funcname_FuncName_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(MessReq)
if err := dec(in);
err != nil {
return nil, err
}
if interceptor == nil {
return srv.(FuncnameServer).FuncName(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server:srv,
FullMethod: "/serverpb.funcname/FuncName",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(FuncnameServer).FuncName(ctx, req.(*MessReq))
}
return interceptor(ctx, in, info, handler)
}var _Funcname_serviceDesc = grpc.ServiceDesc{
ServiceName: "serverpb.funcname",
HandlerType: (*FuncnameServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "FuncName",
Handler:_Funcname_FuncName_Handler,
},
},
Streams:[]grpc.StreamDesc{},
Metadata: "funname.proto",
}func init() { proto.RegisterFile("funname.proto", fileDescriptor3) }var fileDescriptor3 = []byte{
// 134 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x4d, 0x2b, 0xcd, 0xcb,
0x4b, 0xcc, 0x4d, 0xd5, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x28, 0x4e, 0x2d, 0x2a, 0x4b,
0x2d, 0x2a, 0x48, 0x52, 0x52, 0xe4, 0x62, 0xf7, 0x4d, 0x2d, 0x2e, 0x0e, 0x4a, 0x2d, 0x14, 0x12,
0xe3, 0x62, 0xf3, 0x4b, 0xcc, 0x4d, 0xf5, 0x4c, 0x91, 0x60, 0x54, 0x60, 0xd4, 0x60, 0x0d, 0x62,
0x03, 0x69, 0xc8, 0x4c, 0x41, 0x28, 0x29, 0x06, 0x29, 0x29, 0x4a, 0x2d, 0x2e, 0xcd, 0x29, 0x81,
0x29, 0x81, 0xf0, 0x8c, 0x6c, 0xb8, 0x38, 0xd2, 0x4a, 0xf3, 0x92, 0x41, 0x1a, 0x84, 0x0c, 0xb8,
0x38, 0xdc, 0x4a, 0xf3, 0x92, 0x41, 0x46, 0x09, 0x09, 0xea, 0xc1, 0x2c, 0xd2, 0x83, 0xda, 0x22,
0x85, 0x21, 0x54, 0x9c, 0xc4, 0x06, 0x76, 0x94, 0x31, 0x20, 0x00, 0x00, 0xff, 0xff, 0xdf, 0x35,
0x1b, 0xe8, 0xa5, 0x00, 0x00, 0x00,
}
5 编写服务端代码 根据.go文件编写服务端代码
package mainimport (
"context"
"fmt"
"net"
proto "rpctest""google.golang.org/grpc"
)type server struct {
}func (s *server) FuncName(c context.Context, in *proto.MessReq) (*proto.MessRes, error) {
return &proto.MessRes{Result :in.NameId }, nil
}func main() {
listen, err := net.Listen("tcp", ":50051")
if err != nil {
fmt.Println("listen failed err:", err)
return
}
s := grpc.NewServer()
proto.RegisterGreeterServer(s, &server{})
s.Serve(listen)
}
6 编写客户端代码
package mainimport (
"context"
"log"
proto "rpctest"
"google.golang.org/grpc"
)func main() {
conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure())
if err != nil {
log.Fatal("new dial failed err:", err)
}defer conn.Close()
c := proto.NewGreeterClient(conn)
r, err := c.FuncName(context.Background(), &proto.MessReq{NameId : 1})
if err != nil {
log.Fatal("get reply failed err:", err)
}
log.Print(r.GetMessage())
}
其他服务方法: (1) 单项 RPC,即客户端发送一个请求给服务端,从服务端获取一个应答,就像一次普通的函数调用。
rpc SayHello(HelloRequest) returns (HelloResponse){
}
(2) 服务端流式 RPC,即客户端发送一个请求给服务端,可获取一个数据流用来读取一系列消息。客户端从返回的数据流里一直读取直到没有更多消息为止。
rpc LotsOfReplies(HelloRequest) returns (stream HelloResponse){
}
(3)客户端流式 RPC,即客户端用提供的一个数据流写入并发送一系列消息给服务端。一旦客户端完成消息写入,就等待服务端读取这些消息并返回应答。
rpc LotsOfGreetings(stream HelloRequest) returns (HelloResponse) {
}
(4) 双向流式 RPC,即两边都可以分别通过一个读写数据流来发送一系列消息。这两个数据流操作是相互独立的,所以客户端和服务端能按其希望的任意顺序读写,例如:服务端可以在写应答前等待所有的客户端消息,或者它可以先读一个消息再写一个消息,或者是读写相结合的其他方式。每个数据流里消息的顺序会被保持。
rpc BidiHello(stream HelloRequest) returns (stream HelloResponse){
}
连接
推荐阅读
- 【golang】leetcode中级-字母异位词分组&无重复字符的最长子串
- 彻底理解Golang Map
- kratos线上开源年会它来啦~
- 深入浅出 Golang 资源嵌入方案(go-bindata篇)
- 深入浅出 Golang 资源嵌入方案(前篇)
- golang 经典案例总结
- Go实战 | 基于有向无环图的并发执行流的实现
- Golang 数组和切片
- Go JSON编码与解码()
- golang map基础知识