golang中使用gRPC

前期准备

  1. go get -u "google.golang.org/grpc"
  2. go get -u "google.golang.org/grpc/reflection"

例如我定义的文件exporttask.proto:

// 微生活导出服务
// 导出功能接口
/*
    1、 创建任务模板
    2、 查询、列出任务模板
    3、 删除任务模板
    4、 添加导出任务实例
    5、 查询任务状态
*/
syntax = "proto3";
// java 语法特别选项
option java_multiple_files = true;
option java_package = "io.grpc.welife.WshExportTask";
option java_outer_classname = "WshExportTask";
// 包名 golang包名,php中namespase,
package exporttask;
// 导出任务服务定义
service ExportTask {
  // 创建任务模板
  rpc CreateTpl(WshExportTaskCreateTplReq) returns (WshExportTaskCreateTplRes) {}
  // 查询任务模板
  rpc ListTpl(WshExportTaskListTplReq) returns (WshExportTaskListTplRes) {}
}
// 枚举类型,必须从0开始,序号可跨越。同一包下不能重名,所以加前缀来区别
enum WshExportTplStatus {
    TPL_INITED = 0;
    TPL_NORMAL = 1;
    TPL_DELETED = 9;
}
enum WshExportFormat {
    FMT_DEFAULT = 0;
    FMT_CSV = 1;
    FMT_XLS = 2;
}
message WshExportTpl {
    string etplName = 1;
    string etplTag = 2;
    WshExportFormat etplOutputFormat = 3;
    string etplOutputColumns = 4;
    string etplExpr = 5;
    int32 etplId = 6;
    int32 etplExecTimes = 7;
    int32 etplExecOkTimes = 8;
    int32 etplStatus = 9;
    string etplCreated = 10;
    string etplUpdated = 11;
    string etplDeleted = 12;
    int32 operatorId = 13;
}
message WshExportTaskCreateTplReq {
    string etplName = 1;
    string etplTag = 2;
    string etplExpr = 3;
    string etplOutputColumns = 4;
    WshExportFormat etplOutputFormat = 5;
    int32 operatorId = 6;
}
message WshExportTaskCreateTplRes {
    string errCode = 1;
    string errMsg = 2;
    WshExportTpl data = 3;
}
message WshExportTaskListTplReq {
    int32 etplId = 1;
    string etplName = 2;
    string etplTag = 3;
}
// repeated 表示数组
message WshExportTaskListTplRes {
    string errCode = 1;
    string errMsg = 2;
    repeated WshExportTpl data = 3;
}

使用protoc命令生成golang对应的rpc代码:

#格式 protoc --go_out=plugins=grpc:{go代码输出路径} {proto文件}
protoc --go_out=plugins=grpc:./ ./exporttask.proto

生成对应当exporttask.pb.go

// Code generated by protoc-gen-go. DO NOT EDIT.
// source: exporttask.proto
/*
Package exporttask is a generated protocol buffer package.
包名 golang包名,php中namespase,
It is generated from these files:
    exporttask.proto
It has these top-level messages:
    WshExportTpl
    WshExportTaskCreateTplReq
    WshExportTaskCreateTplRes
    WshExportTaskListTplReq
    WshExportTaskListTplRes
*/
package exporttask
import 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.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.ProtoPackageIsVersion2 // please upgrade the proto package
// 枚举类型,必须从0开始,序号可跨越。同一包下不能重名,所以加前缀来区别
type WshExportTplStatus int32
const (
    WshExportTplStatus_TPL_INITED  WshExportTplStatus = 0
    WshExportTplStatus_TPL_NORMAL  WshExportTplStatus = 1
    WshExportTplStatus_TPL_DELETED WshExportTplStatus = 9
)
var WshExportTplStatus_name = map[int32]string{
    0: "TPL_INITED",
    1: "TPL_NORMAL",
    9: "TPL_DELETED",
}
var WshExportTplStatus_value = map[string]int32{
    "TPL_INITED":  0,
    "TPL_NORMAL":  1,
    "TPL_DELETED": 9,
}
func (x WshExportTplStatus) String() string {
    return proto.EnumName(WshExportTplStatus_name, int32(x))
}
func (WshExportTplStatus) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
type WshExportFormat int32
const (
    WshExportFormat_FMT_DEFAULT WshExportFormat = 0
    WshExportFormat_FMT_CSV     WshExportFormat = 1
    WshExportFormat_FMT_XLS     WshExportFormat = 2
)
var WshExportFormat_name = map[int32]string{
    0: "FMT_DEFAULT",
    1: "FMT_CSV",
    2: "FMT_XLS",
}
var WshExportFormat_value = map[string]int32{
    "FMT_DEFAULT": 0,
    "FMT_CSV":     1,
    "FMT_XLS":     2,
}
func (x WshExportFormat) String() string {
    return proto.EnumName(WshExportFormat_name, int32(x))
}
func (WshExportFormat) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
type WshExportTpl struct {
    EtplName          string          `protobuf:"bytes,1,opt,name=etplName" json:"etplName,omitempty"`
    EtplTag           string          `protobuf:"bytes,2,opt,name=etplTag" json:"etplTag,omitempty"`
    EtplOutputFormat  WshExportFormat `protobuf:"varint,3,opt,name=etplOutputFormat,enum=exporttask.WshExportFormat" json:"etplOutputFormat,omitempty"`
    EtplOutputColumns string          `protobuf:"bytes,4,opt,name=etplOutputColumns" json:"etplOutputColumns,omitempty"`
    EtplExpr          string          `protobuf:"bytes,5,opt,name=etplExpr" json:"etplExpr,omitempty"`
    EtplId            int32           `protobuf:"varint,6,opt,name=etplId" json:"etplId,omitempty"`
    EtplExecTimes     int32           `protobuf:"varint,7,opt,name=etplExecTimes" json:"etplExecTimes,omitempty"`
    EtplExecOkTimes   int32           `protobuf:"varint,8,opt,name=etplExecOkTimes" json:"etplExecOkTimes,omitempty"`
    EtplStatus        int32           `protobuf:"varint,9,opt,name=etplStatus" json:"etplStatus,omitempty"`
    EtplCreated       string          `protobuf:"bytes,10,opt,name=etplCreated" json:"etplCreated,omitempty"`
    EtplUpdated       string          `protobuf:"bytes,11,opt,name=etplUpdated" json:"etplUpdated,omitempty"`
    EtplDeleted       string          `protobuf:"bytes,12,opt,name=etplDeleted" json:"etplDeleted,omitempty"`
    OperatorId        int32           `protobuf:"varint,13,opt,name=operatorId" json:"operatorId,omitempty"`
}
func (m *WshExportTpl) Reset()                    { *m = WshExportTpl{} }
func (m *WshExportTpl) String() string            { return proto.CompactTextString(m) }
func (*WshExportTpl) ProtoMessage()               {}
func (*WshExportTpl) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
func (m *WshExportTpl) GetEtplName() string {
    if m != nil {
        return m.EtplName
    }
    return ""
}
func (m *WshExportTpl) GetEtplTag() string {
    if m != nil {
        return m.EtplTag
    }
    return ""
}
func (m *WshExportTpl) GetEtplOutputFormat() WshExportFormat {
    if m != nil {
        return m.EtplOutputFormat
    }
    return WshExportFormat_FMT_DEFAULT
}
func (m *WshExportTpl) GetEtplOutputColumns() string {
    if m != nil {
        return m.EtplOutputColumns
    }
    return ""
}
func (m *WshExportTpl) GetEtplExpr() string {
    if m != nil {
        return m.EtplExpr
    }
    return ""
}
func (m *WshExportTpl) GetEtplId() int32 {
    if m != nil {
        return m.EtplId
    }
    return 0
}
func (m *WshExportTpl) GetEtplExecTimes() int32 {
    if m != nil {
        return m.EtplExecTimes
    }
    return 0
}
func (m *WshExportTpl) GetEtplExecOkTimes() int32 {
    if m != nil {
        return m.EtplExecOkTimes
    }
    return 0
}
func (m *WshExportTpl) GetEtplStatus() int32 {
    if m != nil {
        return m.EtplStatus
    }
    return 0
}
func (m *WshExportTpl) GetEtplCreated() string {
    if m != nil {
        return m.EtplCreated
    }
    return ""
}
func (m *WshExportTpl) GetEtplUpdated() string {
    if m != nil {
        return m.EtplUpdated
    }
    return ""
}
func (m *WshExportTpl) GetEtplDeleted() string {
    if m != nil {
        return m.EtplDeleted
    }
    return ""
}
func (m *WshExportTpl) GetOperatorId() int32 {
    if m != nil {
        return m.OperatorId
    }
    return 0
}
type WshExportTaskCreateTplReq struct {
    EtplName          string          `protobuf:"bytes,1,opt,name=etplName" json:"etplName,omitempty"`
    EtplTag           string          `protobuf:"bytes,2,opt,name=etplTag" json:"etplTag,omitempty"`
    EtplExpr          string          `protobuf:"bytes,3,opt,name=etplExpr" json:"etplExpr,omitempty"`
    EtplOutputColumns string          `protobuf:"bytes,4,opt,name=etplOutputColumns" json:"etplOutputColumns,omitempty"`
    EtplOutputFormat  WshExportFormat `protobuf:"varint,5,opt,name=etplOutputFormat,enum=exporttask.WshExportFormat" json:"etplOutputFormat,omitempty"`
    OperatorId        int32           `protobuf:"varint,6,opt,name=operatorId" json:"operatorId,omitempty"`
}
func (m *WshExportTaskCreateTplReq) Reset()                    { *m = WshExportTaskCreateTplReq{} }
func (m *WshExportTaskCreateTplReq) String() string            { return proto.CompactTextString(m) }
func (*WshExportTaskCreateTplReq) ProtoMessage()               {}
func (*WshExportTaskCreateTplReq) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
func (m *WshExportTaskCreateTplReq) GetEtplName() string {
    if m != nil {
        return m.EtplName
    }
    return ""
}
func (m *WshExportTaskCreateTplReq) GetEtplTag() string {
    if m != nil {
        return m.EtplTag
    }
    return ""
}
func (m *WshExportTaskCreateTplReq) GetEtplExpr() string {
    if m != nil {
        return m.EtplExpr
    }
    return ""
}
func (m *WshExportTaskCreateTplReq) GetEtplOutputColumns() string {
    if m != nil {
        return m.EtplOutputColumns
    }
    return ""
}
func (m *WshExportTaskCreateTplReq) GetEtplOutputFormat() WshExportFormat {
    if m != nil {
        return m.EtplOutputFormat
    }
    return WshExportFormat_FMT_DEFAULT
}
func (m *WshExportTaskCreateTplReq) GetOperatorId() int32 {
    if m != nil {
        return m.OperatorId
    }
    return 0
}
type WshExportTaskCreateTplRes struct {
    ErrCode string        `protobuf:"bytes,1,opt,name=errCode" json:"errCode,omitempty"`
    ErrMsg  string        `protobuf:"bytes,2,opt,name=errMsg" json:"errMsg,omitempty"`
    Data    *WshExportTpl `protobuf:"bytes,3,opt,name=data" json:"data,omitempty"`
}
func (m *WshExportTaskCreateTplRes) Reset()                    { *m = WshExportTaskCreateTplRes{} }
func (m *WshExportTaskCreateTplRes) String() string            { return proto.CompactTextString(m) }
func (*WshExportTaskCreateTplRes) ProtoMessage()               {}
func (*WshExportTaskCreateTplRes) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
func (m *WshExportTaskCreateTplRes) GetErrCode() string {
    if m != nil {
        return m.ErrCode
    }
    return ""
}
func (m *WshExportTaskCreateTplRes) GetErrMsg() string {
    if m != nil {
        return m.ErrMsg
    }
    return ""
}
func (m *WshExportTaskCreateTplRes) GetData() *WshExportTpl {
    if m != nil {
        return m.Data
    }
    return nil
}
type WshExportTaskListTplReq struct {
    EtplId   int32  `protobuf:"varint,1,opt,name=etplId" json:"etplId,omitempty"`
    EtplName string `protobuf:"bytes,2,opt,name=etplName" json:"etplName,omitempty"`
    EtplTag  string `protobuf:"bytes,3,opt,name=etplTag" json:"etplTag,omitempty"`
}
func (m *WshExportTaskListTplReq) Reset()                    { *m = WshExportTaskListTplReq{} }
func (m *WshExportTaskListTplReq) String() string            { return proto.CompactTextString(m) }
func (*WshExportTaskListTplReq) ProtoMessage()               {}
func (*WshExportTaskListTplReq) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} }
func (m *WshExportTaskListTplReq) GetEtplId() int32 {
    if m != nil {
        return m.EtplId
    }
    return 0
}
func (m *WshExportTaskListTplReq) GetEtplName() string {
    if m != nil {
        return m.EtplName
    }
    return ""
}
func (m *WshExportTaskListTplReq) GetEtplTag() string {
    if m != nil {
        return m.EtplTag
    }
    return ""
}
// repeated 表示数组
type WshExportTaskListTplRes struct {
    ErrCode string          `protobuf:"bytes,1,opt,name=errCode" json:"errCode,omitempty"`
    ErrMsg  string          `protobuf:"bytes,2,opt,name=errMsg" json:"errMsg,omitempty"`
    Data    []*WshExportTpl `protobuf:"bytes,3,rep,name=data" json:"data,omitempty"`
}
func (m *WshExportTaskListTplRes) Reset()                    { *m = WshExportTaskListTplRes{} }
func (m *WshExportTaskListTplRes) String() string            { return proto.CompactTextString(m) }
func (*WshExportTaskListTplRes) ProtoMessage()               {}
func (*WshExportTaskListTplRes) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} }
func (m *WshExportTaskListTplRes) GetErrCode() string {
    if m != nil {
        return m.ErrCode
    }
    return ""
}
func (m *WshExportTaskListTplRes) GetErrMsg() string {
    if m != nil {
        return m.ErrMsg
    }
    return ""
}
func (m *WshExportTaskListTplRes) GetData() []*WshExportTpl {
    if m != nil {
        return m.Data
    }
    return nil
}
func init() {
    proto.RegisterType((*WshExportTpl)(nil), "exporttask.WshExportTpl")
    proto.RegisterType((*WshExportTaskCreateTplReq)(nil), "exporttask.WshExportTaskCreateTplReq")
    proto.RegisterType((*WshExportTaskCreateTplRes)(nil), "exporttask.WshExportTaskCreateTplRes")
    proto.RegisterType((*WshExportTaskListTplReq)(nil), "exporttask.WshExportTaskListTplReq")
    proto.RegisterType((*WshExportTaskListTplRes)(nil), "exporttask.WshExportTaskListTplRes")
    proto.RegisterEnum("exporttask.WshExportTplStatus", WshExportTplStatus_name, WshExportTplStatus_value)
    proto.RegisterEnum("exporttask.WshExportFormat", WshExportFormat_name, WshExportFormat_value)
}
// 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 ExportTask service
type ExportTaskClient interface {
    // 创建任务模板
    CreateTpl(ctx context.Context, in *WshExportTaskCreateTplReq, opts ...grpc.CallOption) (*WshExportTaskCreateTplRes, error)
    // 查询任务模板
    ListTpl(ctx context.Context, in *WshExportTaskListTplReq, opts ...grpc.CallOption) (*WshExportTaskListTplRes, error)
}
type exportTaskClient struct {
    cc *grpc.ClientConn
}
func NewExportTaskClient(cc *grpc.ClientConn) ExportTaskClient {
    return &exportTaskClient{cc}
}
func (c *exportTaskClient) CreateTpl(ctx context.Context, in *WshExportTaskCreateTplReq, opts ...grpc.CallOption) (*WshExportTaskCreateTplRes, error) {
    out := new(WshExportTaskCreateTplRes)
    err := grpc.Invoke(ctx, "/exporttask.ExportTask/CreateTpl", in, out, c.cc, opts...)
    if err != nil {
        return nil, err
    }
    return out, nil
}
func (c *exportTaskClient) ListTpl(ctx context.Context, in *WshExportTaskListTplReq, opts ...grpc.CallOption) (*WshExportTaskListTplRes, error) {
    out := new(WshExportTaskListTplRes)
    err := grpc.Invoke(ctx, "/exporttask.ExportTask/ListTpl", in, out, c.cc, opts...)
    if err != nil {
        return nil, err
    }
    return out, nil
}
// Server API for ExportTask service
type ExportTaskServer interface {
    // 创建任务模板
    CreateTpl(context.Context, *WshExportTaskCreateTplReq) (*WshExportTaskCreateTplRes, error)
    // 查询任务模板
    ListTpl(context.Context, *WshExportTaskListTplReq) (*WshExportTaskListTplRes, error)
}
func RegisterExportTaskServer(s *grpc.Server, srv ExportTaskServer) {
    s.RegisterService(&_ExportTask_serviceDesc, srv)
}
func _ExportTask_CreateTpl_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
    in := new(WshExportTaskCreateTplReq)
    if err := dec(in); err != nil {
        return nil, err
    }
    if interceptor == nil {
        return srv.(ExportTaskServer).CreateTpl(ctx, in)
    }
    info := &grpc.UnaryServerInfo{
        Server:     srv,
        FullMethod: "/exporttask.ExportTask/CreateTpl",
    }
    handler := func(ctx context.Context, req interface{}) (interface{}, error) {
        return srv.(ExportTaskServer).CreateTpl(ctx, req.(*WshExportTaskCreateTplReq))
    }
    return interceptor(ctx, in, info, handler)
}
func _ExportTask_ListTpl_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
    in := new(WshExportTaskListTplReq)
    if err := dec(in); err != nil {
        return nil, err
    }
    if interceptor == nil {
        return srv.(ExportTaskServer).ListTpl(ctx, in)
    }
    info := &grpc.UnaryServerInfo{
        Server:     srv,
        FullMethod: "/exporttask.ExportTask/ListTpl",
    }
    handler := func(ctx context.Context, req interface{}) (interface{}, error) {
        return srv.(ExportTaskServer).ListTpl(ctx, req.(*WshExportTaskListTplReq))
    }
    return interceptor(ctx, in, info, handler)
}
var _ExportTask_serviceDesc = grpc.ServiceDesc{
    ServiceName: "exporttask.ExportTask",
    HandlerType: (*ExportTaskServer)(nil),
    Methods: []grpc.MethodDesc{
        {
            MethodName: "CreateTpl",
            Handler:    _ExportTask_CreateTpl_Handler,
        },
        {
            MethodName: "ListTpl",
            Handler:    _ExportTask_ListTpl_Handler,
        },
    },
    Streams:  []grpc.StreamDesc{},
    Metadata: "exporttask.proto",
}
func init() { proto.RegisterFile("exporttask.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
    // 550 bytes of a gzipped FileDescriptorProto
    0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xa4, 0x54, 0x5f, 0x8f, 0xd2, 0x4e,
    0x14, 0xa5, 0xb0, 0xc0, 0x72, 0x59, 0x96, 0xfe, 0xe6, 0xe1, 0xe7, 0x88, 0xc6, 0x90, 0xaa, 0x09,
    0xd9, 0x6c, 0x30, 0xc1, 0x57, 0x5f, 0x76, 0xa1, 0x18, 0x92, 0x02, 0x1b, 0x28, 0x6a, 0xe2, 0xc3,
    0xa6, 0x6e, 0x47, 0x24, 0x14, 0x5b, 0x67, 0x86, 0xb8, 0xc6, 0x57, 0x3f, 0x98, 0x5f, 0xc6, 0xef,
    0x61, 0x66, 0xda, 0x61, 0x5a, 0xfe, 0xc4, 0x75, 0x7d, 0x9b, 0x73, 0xe6, 0x94, 0x7b, 0xef, 0x39,
    0x77, 0x00, 0x93, 0xdc, 0x46, 0x21, 0xe5, 0xdc, 0x63, 0xcb, 0x76, 0x44, 0x43, 0x1e, 0x22, 0xd0,
    0x8c, 0xf5, 0xab, 0x00, 0x27, 0x6f, 0xd9, 0x27, 0x5b, 0x32, 0x6e, 0x14, 0xa0, 0x06, 0x1c, 0x13,
    0x1e, 0x05, 0x23, 0x6f, 0x45, 0xb0, 0xd1, 0x34, 0x5a, 0x95, 0xc9, 0x06, 0x23, 0x0c, 0x65, 0x71,
    0x76, 0xbd, 0x39, 0xce, 0xcb, 0x2b, 0x05, 0xd1, 0x6b, 0x30, 0xc5, 0x71, 0xbc, 0xe6, 0xd1, 0x9a,
    0xf7, 0x43, 0xba, 0xf2, 0x38, 0x2e, 0x34, 0x8d, 0xd6, 0x69, 0xe7, 0x51, 0x3b, 0x55, 0x7f, 0x53,
    0x29, 0x96, 0x4c, 0x76, 0x3e, 0x42, 0xe7, 0xf0, 0x9f, 0xe6, 0xba, 0x61, 0xb0, 0x5e, 0x7d, 0x66,
    0xf8, 0x48, 0x16, 0xdb, 0xbd, 0x50, 0xcd, 0xda, 0xb7, 0x11, 0xc5, 0x45, 0xdd, 0xac, 0xc0, 0xe8,
    0x7f, 0x28, 0x89, 0xf3, 0xc0, 0xc7, 0xa5, 0xa6, 0xd1, 0x2a, 0x4e, 0x12, 0x84, 0x9e, 0x41, 0x2d,
    0xd6, 0x90, 0x1b, 0x77, 0xb1, 0x22, 0x0c, 0x97, 0xe5, 0x75, 0x96, 0x44, 0x2d, 0xa8, 0x2b, 0x62,
    0xbc, 0x8c, 0x75, 0xc7, 0x52, 0xb7, 0x4d, 0xa3, 0x27, 0x00, 0x82, 0x9a, 0x72, 0x8f, 0xaf, 0x19,
    0xae, 0x48, 0x51, 0x8a, 0x41, 0x4d, 0xa8, 0x0a, 0xd4, 0xa5, 0xc4, 0xe3, 0xc4, 0xc7, 0x20, 0xdb,
    0x4c, 0x53, 0x4a, 0x31, 0x8b, 0x7c, 0xa9, 0xa8, 0x6a, 0x45, 0x42, 0x29, 0x45, 0x8f, 0x04, 0x44,
    0x28, 0x4e, 0xb4, 0x22, 0xa1, 0x44, 0x17, 0x61, 0x44, 0xa8, 0xc7, 0x43, 0x3a, 0xf0, 0x71, 0x2d,
    0xee, 0x42, 0x33, 0xd6, 0x8f, 0x3c, 0x3c, 0xd4, 0x39, 0x7b, 0x6c, 0x19, 0x17, 0x77, 0xa3, 0x60,
    0x42, 0xbe, 0xdc, 0x33, 0xf4, 0xb4, 0xfb, 0x85, 0x2d, 0xf7, 0xff, 0x2e, 0xc7, 0x7d, 0xeb, 0x53,
    0xbc, 0xcf, 0xfa, 0x64, 0x6d, 0x28, 0xed, 0xd8, 0xf0, 0xfd, 0xb0, 0x0b, 0x4c, 0x4e, 0x4a, 0x69,
    0x37, 0xf4, 0x95, 0x09, 0x0a, 0xca, 0x5d, 0xa2, 0x74, 0xc8, 0x94, 0x05, 0x09, 0x42, 0xe7, 0x70,
    0xe4, 0x7b, 0xdc, 0x93, 0xd3, 0x57, 0x3b, 0x78, 0x6f, 0xaf, 0xe2, 0xc7, 0xa5, 0xca, 0x9a, 0xc3,
    0x83, 0x4c, 0x71, 0x67, 0xc1, 0x78, 0x12, 0x80, 0x5e, 0x56, 0x23, 0xb3, 0xac, 0xe9, 0x60, 0xf2,
    0x87, 0x83, 0x29, 0x64, 0x82, 0xb1, 0xbe, 0x1d, 0x2a, 0xf4, 0x6f, 0x33, 0x16, 0xfe, 0x3c, 0xe3,
    0x99, 0x0d, 0x28, 0xcd, 0x26, 0x6f, 0xe0, 0x14, 0xc0, 0xbd, 0x72, 0xae, 0x07, 0xa3, 0x81, 0x6b,
    0xf7, 0xcc, 0x9c, 0xc2, 0xa3, 0xf1, 0x64, 0x78, 0xe1, 0x98, 0x06, 0xaa, 0x43, 0x55, 0xe0, 0x9e,
    0xed, 0xd8, 0x42, 0x50, 0x39, 0x7b, 0x05, 0xf5, 0xad, 0xb0, 0x85, 0xa6, 0x3f, 0x74, 0xaf, 0x7b,
    0x76, 0xff, 0x62, 0xe6, 0xb8, 0x66, 0x0e, 0x55, 0xa1, 0x2c, 0x88, 0xee, 0xf4, 0x8d, 0x69, 0x28,
    0xf0, 0xce, 0x99, 0x9a, 0xf9, 0xce, 0x4f, 0x03, 0x40, 0x4f, 0x8f, 0xde, 0x43, 0x65, 0x93, 0x33,
    0x7a, 0xbe, 0x7f, 0x80, 0xad, 0x17, 0xd1, 0xb8, 0x93, 0x8c, 0x59, 0x39, 0x34, 0x83, 0x72, 0x62,
    0x2f, 0x7a, 0x7a, 0xf0, 0x1b, 0x9d, 0x74, 0xe3, 0x0e, 0x22, 0x66, 0xe5, 0x2e, 0x5f, 0xc0, 0xe3,
    0x45, 0xd8, 0x9e, 0xd3, 0xe8, 0xa6, 0xfd, 0x95, 0x04, 0x8b, 0x8f, 0x24, 0xab, 0xbd, 0xac, 0x65,
    0xe0, 0x95, 0xf1, 0xa1, 0x24, 0xff, 0xdb, 0x5f, 0xfe, 0x0e, 0x00, 0x00, 0xff, 0xff, 0x60, 0x9b,
    0xec, 0x89, 0xef, 0x05, 0x00, 0x00,
}

服务端实现proto中的接口:

package main
import (
    "log"
    //"net"
    svcExport "../../common/exporttask" // 包含上面的pb生成的go包
    "./model"
    _ "github.com/go-sql-driver/mysql"
    "golang.org/x/net/context"
    //"google.golang.org/grpc"
    //"google.golang.org/grpc/reflection"
)
// server 这个对象来实现 exporttask 包中的pb定义的rpc服务
// 实现的方式是将服务转化成本地的数据库操作
type server struct{}
func (s *server) CreateTpl(ctx context.Context, in *svcExport.WshExportTaskCreateTplReq) (res *svcExport.WshExportTaskCreateTplRes, err error) {
    res = new(svcExport.WshExportTaskCreateTplRes)
    res.Data = new(svcExport.WshExportTpl)
    var etplId int32 = 0
    etplId, err = model.CreateTpl(in.EtplName, in.EtplTag, in.EtplExpr, in.EtplOutputColumns, int32(in.EtplOutputFormat), in.OperatorId)
    //res.Data, err = model.GetTpl(etplId)
    res.Data.EtplId = etplId
    return res, err
}
func (s *server) ListTpl(ctx context.Context, in *svcExport.WshExportTaskListTplReq) (*svcExport.WshExportTaskListTplRes, error) {
    res := new(svcExport.WshExportTaskListTplRes)
    entList, err := model.ListTpl(in.EtplId, in.EtplName, in.EtplTag)
    if err != nil {
        res.ErrMsg = err.Error()
        res.ErrCode = "2"
    }
    for _, ent := range entList {
        t := new(svcExport.WshExportTpl)
        ent.CopyToPb(t)
        res.Data = append(res.Data, t)
    }
    return res, err
}

服务端main启动服务main.go

/**
 * exporttask server main
 * $ go build exporttask.go
 */
package main
import (
    "log"
    "net"
    svcExport "../../common/exporttask"
    //"./model"
    _ "github.com/go-sql-driver/mysql"
    //"golang.org/x/net/context"
    "google.golang.org/grpc"
    "google.golang.org/grpc/reflection"
)
const (
    port = ":50051"
)
func main() {
    lis, err := net.Listen("tcp", port)
    if err != nil {
        log.Fatalf("failed to listen: %v", err)
    }
    // 生成一个rpc服务器
    s := grpc.NewServer()
    // 使用pb包调用注册已实现的rpc接口类server
    svcExport.RegisterExportTaskServer(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)
    }
}

Golang gRPC客户端
客户端的代码相对比较简单

package main
import (
    "flag"
    "log"
    "os"
    svcExport "../../common/exporttask"
    "golang.org/x/net/context"
    "google.golang.org/grpc"
)
const (
    address     = "127.0.0.1:50052"
    defaultName = "world"
)
func main() {
    // 发起链接
    conn, err := grpc.Dial(address, grpc.WithInsecure())
    if err != nil {
        log.Fatalf("did not connect: %v", err)
    }
    defer conn.Close()
    // 创建pb包的客户端
    c := svcExport.NewExportTaskClient(conn)
    name := defaultName
    if len(os.Args) > 1 {
        name = os.Args[1]
    }
    // 发起请求
    var r2 *svcExport.WshExportTaskCreateTplRes
    req := svcExport.WshExportTaskCreateTplReq{EtplName: name, EtplTag: "mall", EtplExpr: "select EtplName from welife_export_tpl", EtplOutputFormat: svcExport.WshExportFormat_FMT_CSV, EtplOutputColumns: ""}
    r2, err = c.CreateTpl(context.Background(), &req)
    // 打印结果
    log.Println("create tpl: r=", r2, err)
}