前面简单介绍过GRPC的基本原理,本文着重介绍golang版GRPC实例,本实例主要包含三部分,客户端代码,服务端代码,协议文件代码。(GRPC详见 )
实例功能说明
本例子是一个ToUpper程序,接收客户端请求包含一个传入字符串参数,服务端返回大写字符串。
定义protoc文件
定义了一个ToUpper服务,定义了两个消息UpperRequest和UpperReply分别用来接收消息和回复消息。(protobuf详见学习笔记-Protobuf简单理解)
syntax = "proto3";
package proto;
// The service definition.
service ToUpper{
// Sends a greeting
rpc Upper (UpperRequest) returns (UpperReply) {}
}
// The request message
message UpperRequest {
string name = 1;
}
// The response message
message UpperReply {
string message = 1;
}
根据协议文件生成的go代码
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: toupper.proto
package proto
import (
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
// The request message
type UpperRequest struct {
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *UpperRequest) Reset() { *m = UpperRequest{} }
func (m *UpperRequest) String() string { return proto.CompactTextString(m) }
func (*UpperRequest) ProtoMessage() {}
func (*UpperRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_b9263bae945d71a4, []int{0}
}
func (m *UpperRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_UpperRequest.Unmarshal(m, b)
}
func (m *UpperRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_UpperRequest.Marshal(b, m, deterministic)
}
func (m *UpperRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_UpperRequest.Merge(m, src)
}
func (m *UpperRequest) XXX_Size() int {
return xxx_messageInfo_UpperRequest.Size(m)
}
func (m *UpperRequest) XXX_DiscardUnknown() {
xxx_messageInfo_UpperRequest.DiscardUnknown(m)
}
var xxx_messageInfo_UpperRequest proto.InternalMessageInfo
func (m *UpperRequest) GetName() string {
if m != nil {
return m.Name
}
return ""
}
// The response message
type UpperReply struct {
Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *UpperReply) Reset() { *m = UpperReply{} }
func (m *UpperReply) String() string { return proto.CompactTextString(m) }
func (*UpperReply) ProtoMessage() {}
func (*UpperReply) Descriptor() ([]byte, []int) {
return fileDescriptor_b9263bae945d71a4, []int{1}
}
func (m *UpperReply) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_UpperReply.Unmarshal(m, b)
}
func (m *UpperReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_UpperReply.Marshal(b, m, deterministic)
}
func (m *UpperReply) XXX_Merge(src proto.Message) {
xxx_messageInfo_UpperReply.Merge(m, src)
}
func (m *UpperReply) XXX_Size() int {
return xxx_messageInfo_UpperReply.Size(m)
}
func (m *UpperReply) XXX_DiscardUnknown() {
xxx_messageInfo_UpperReply.DiscardUnknown(m)
}
var xxx_messageInfo_UpperReply proto.InternalMessageInfo
func (m *UpperReply) GetMessage() string {
if m != nil {
return m.Message
}
return ""
}
func init() {
proto.RegisterType((*UpperRequest)(nil), "proto.UpperRequest")
proto.RegisterType((*UpperReply)(nil), "proto.UpperReply")
}
func init() { proto.RegisterFile("toupper.proto", fileDescriptor_b9263bae945d71a4) }
var fileDescriptor_b9263bae945d71a4 = []byte{
// 130 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x2d, 0xc9, 0x2f, 0x2d,
0x28, 0x48, 0x2d, 0xd2, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x05, 0x53, 0x4a, 0x4a, 0x5c,
0x3c, 0xa1, 0x20, 0xd1, 0xa0, 0xd4, 0xc2, 0xd2, 0xd4, 0xe2, 0x12, 0x21, 0x21, 0x2e, 0x96, 0xbc,
0xc4, 0xdc, 0x54, 0x09, 0x46, 0x05, 0x46, 0x0d, 0xce, 0x20, 0x30, 0x5b, 0x49, 0x8d, 0x8b, 0x0b,
0xaa, 0xa6, 0x20, 0xa7, 0x52, 0x48, 0x82, 0x8b, 0x3d, 0x37, 0xb5, 0xb8, 0x38, 0x31, 0x1d, 0xa6,
0x08, 0xc6, 0x35, 0xb2, 0xe1, 0x62, 0x0f, 0xc9, 0x07, 0xab, 0x14, 0x32, 0xe4, 0x62, 0x85, 0x30,
0x84, 0x21, 0xd6, 0xe9, 0x21, 0x5b, 0x22, 0x25, 0x88, 0x2a, 0x58, 0x90, 0x53, 0xa9, 0xc4, 0x90,
0xc4, 0x06, 0x16, 0x33, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0xb6, 0xd6, 0xe6, 0x20, 0xa8, 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
// ToUpperClient is the client API for ToUpper service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to #ClientConn.NewStream.
type ToUpperClient interface {
// Sends a greeting
Upper(ctx context.Context, in *UpperRequest, opts ...grpc.CallOption) (*UpperReply, error)
}
type toUpperClient struct {
cc *grpc.ClientConn
}
func NewToUpperClient(cc *grpc.ClientConn) ToUpperClient {
return &toUpperClient{cc}
}
func (c *toUpperClient) Upper(ctx context.Context, in *UpperRequest, opts ...grpc.CallOption) (*UpperReply, error) {
out := new(UpperReply)
err := c.cc.Invoke(ctx, "/proto.ToUpper/Upper", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// ToUpperServer is the server API for ToUpper service.
type ToUpperServer interface {
// Sends a greeting
Upper(context.Context, *UpperRequest) (*UpperReply, error)
}
// UnimplementedToUpperServer can be embedded to have forward compatible implementations.
type UnimplementedToUpperServer struct {
}
func (*UnimplementedToUpperServer) Upper(ctx context.Context, req *UpperRequest) (*UpperReply, error) {
return nil, status.Errorf(codes.Unimplemented, "method Upper not implemented")
}
func RegisterToUpperServer(s *grpc.Server, srv ToUpperServer) {
s.RegisterService(&_ToUpper_serviceDesc, srv)
}
func _ToUpper_Upper_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(UpperRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ToUpperServer).Upper(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/proto.ToUpper/Upper",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ToUpperServer).Upper(ctx, req.(*UpperRequest))
}
return interceptor(ctx, in, info, handler)
}
var _ToUpper_serviceDesc = grpc.ServiceDesc{
ServiceName: "proto.ToUpper",
HandlerType: (*ToUpperServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "Upper",
Handler: _ToUpper_Upper_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "toupper.proto",
}
客户端代码
客户端传入小写字符串 “hello world”
package main
import (
"log"
"golang.org/x/net/context"
"google.golang.org/grpc"
pb "toupper/proto"
)
const (
address = "localhost:8848"//监听端口
)
func main() {
// Set up a connection to the server.
conn, err := grpc.Dial(address, grpc.WithInsecure())
if err != nil {
log.Fatalf("did not connect: %v", err)
}
defer conn.Close()
c := pb.NewToUpperClient(conn)
// Contact the server and print out its response.
name := "hello world"
r, err := c.Upper(context.Background(), &pb.UpperRequest{Name: name})
if err != nil {
log.Fatalf("could not greet: %v", err)
}
log.Printf("Response: %s", r.Message)
}
服务端代码
服务端接收到小写字符串 “hello world”,返回大写字符串” HELLO WORLD”。
package main
import (
"log"
"net"
"strings"
"golang.org/x/net/context"
"google.golang.org/grpc"
pb "toupper/proto"
"google.golang.org/grpc/reflection"
)
const (
port = ":8848"
)
type server struct{}
func (s *server) Upper(ctx context.Context, in *pb.UpperRequest) (*pb.UpperReply, error) {
log.Printf("Received: %s", in.Name)
return &pb.UpperReply{Message: strings.ToUpper(in.Name)}, nil
}
func main() {
lis, err := net.Listen("tcp", port)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
s := grpc.NewServer()
pb.RegisterToUpperServer(s, &server{})
// Register reflection service on gRPC server.
reflection.Register(s)
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
目录结构
toupper
├── main
│ ├── client.go
│ └── server.go
└── proto
├──toupper.proto
└──toupper.pb.go
编译
注意在编译前需要把前面安装的protoc和protoc-gen-go设置到PATH环境变量。
编译完总共会生成3个文件:
生成协议golang文件
protoc -I proto toupper.proto --go_out=plugins=grpc:proto
生成client可执行文件
go build main/client.go
生成server可执行文件
go build main/server.go
运行
先运行服务端,再启动客户端。
客户端:HELLO WORLD
服务端:hello world
本文的初衷为学习笔记的分享,部分图文来源于网络,如侵,联删。