首先,我们创建一个空的项目目录
然后,打开goland一次设置配置。
本次使用golang 1.14版本。
使用modules模式开发。
第一步,初始化项目
go mod init protoTest
第二步,下载tarsgo包、proto、protoc-gen-go
go get github.com/TarsCloud/TarsGo/tars
go get github.com/golang/protobuf/proto
go get github.com/golang/protobuf/protoc-gen-go
第三步,为protoc-gen-go添加tarsrpc插件
不会生成protoc-gen-go的,查看:https://www.cnblogs.com/cnlihao/p/12903160.html
第四步,我们创建一个简单的helloworld.proto和放置其生成文件的目录proto/helloworld
syntax = "proto3";
package helloworld;
// The greeting service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
// The request message containing the user's name.
message HelloRequest {
string name = 1;
}
// The response message containing the greetings
message HelloReply {
string message = 1;
}
第五步,使用命令生成文件helloworld.pb.go
protoc --go_out=plugins=tarsrpc:./proto/helloworld helloworld.proto
#其中plugins后面是我们自定义的tarsrpc协议,再后面是生成文件放置的目录
生成的helloworld.pb.go如下:
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: helloworld.proto
package helloworld
import (
context "context"
fmt "fmt"
tars "github.com/TarsCloud/TarsGo/tars"
model "github.com/TarsCloud/TarsGo/tars/model"
requestf "github.com/TarsCloud/TarsGo/tars/protocol/res/requestf"
current "github.com/TarsCloud/TarsGo/tars/util/current"
tools "github.com/TarsCloud/TarsGo/tars/util/tools"
proto "github.com/golang/protobuf/proto"
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 containing the user's name.
type HelloRequest 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 *HelloRequest) Reset() { *m = HelloRequest{} }
func (m *HelloRequest) String() string { return proto.CompactTextString(m) }
func (*HelloRequest) ProtoMessage() {}
func (*HelloRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_17b8c58d586b62f2, []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.InternalMessageInfo
func (m *HelloRequest) GetName() string {
if m != nil {
return m.Name
}
return ""
}
// The response message containing the greetings
type HelloReply 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 *HelloReply) Reset() { *m = HelloReply{} }
func (m *HelloReply) String() string { return proto.CompactTextString(m) }
func (*HelloReply) ProtoMessage() {}
func (*HelloReply) Descriptor() ([]byte, []int) {
return fileDescriptor_17b8c58d586b62f2, []int{1}
}
func (m *HelloReply) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_HelloReply.Unmarshal(m, b)
}
func (m *HelloReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_HelloReply.Marshal(b, m, deterministic)
}
func (m *HelloReply) XXX_Merge(src proto.Message) {
xxx_messageInfo_HelloReply.Merge(m, src)
}
func (m *HelloReply) XXX_Size() int {
return xxx_messageInfo_HelloReply.Size(m)
}
func (m *HelloReply) XXX_DiscardUnknown() {
xxx_messageInfo_HelloReply.DiscardUnknown(m)
}
var xxx_messageInfo_HelloReply proto.InternalMessageInfo
func (m *HelloReply) GetMessage() string {
if m != nil {
return m.Message
}
return ""
}
func init() {
proto.RegisterType((*HelloRequest)(nil), "helloworld.HelloRequest")
proto.RegisterType((*HelloReply)(nil), "helloworld.HelloReply")
}
func init() {
proto.RegisterFile("helloworld.proto", fileDescriptor_17b8c58d586b62f2)
}
var fileDescriptor_17b8c58d586b62f2 = []byte{
// 141 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0xc8, 0x48, 0xcd, 0xc9,
0xc9, 0x2f, 0xcf, 0x2f, 0xca, 0x49, 0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x42, 0x88,
0x28, 0x29, 0x71, 0xf1, 0x78, 0x80, 0x78, 0x41, 0xa9, 0x85, 0xa5, 0xa9, 0xc5, 0x25, 0x42, 0x42,
0x5c, 0x2c, 0x79, 0x89, 0xb9, 0xa9, 0x12, 0x8c, 0x0a, 0x8c, 0x1a, 0x9c, 0x41, 0x60, 0xb6, 0x92,
0x1a, 0x17, 0x17, 0x54, 0x4d, 0x41, 0x4e, 0xa5, 0x90, 0x04, 0x17, 0x7b, 0x6e, 0x6a, 0x71, 0x71,
0x62, 0x3a, 0x4c, 0x11, 0x8c, 0x6b, 0xe4, 0xc9, 0xc5, 0xee, 0x5e, 0x94, 0x9a, 0x5a, 0x92, 0x5a,
0x24, 0x64, 0xc7, 0xc5, 0x11, 0x9c, 0x58, 0x09, 0xd6, 0x25, 0x24, 0xa1, 0x87, 0xe4, 0x02, 0x64,
0xcb, 0xa4, 0xc4, 0xb0, 0xc8, 0x14, 0xe4, 0x54, 0x2a, 0x31, 0x24, 0xb1, 0x81, 0x5d, 0x6a, 0x0c,
0x08, 0x00, 0x00, 0xff, 0xff, 0xd6, 0x53, 0x4e, 0xf7, 0xbd, 0x00, 0x00, 0x00,
}
// This following code was generated by tarsrpc
// Gernerated from helloworld.proto
type Greeter struct {
s model.Servant
}
//SetServant is required by the servant interface.
func (obj *Greeter) SetServant(s model.Servant) {
obj.s = s
}
//AddServant is required by the servant interface
func (obj *Greeter) AddServant(imp impGreeter, objStr string) {
tars.AddServant(obj, imp, objStr)
}
////AddServant adds servant for the service with context
func (obj *Greeter) AddServantWithContext(imp impGreeterWithContext, objStr string) {
tars.AddServantWithContext(obj, imp, objStr)
}
//TarsSetTimeout is required by the servant interface. t is the timeout in ms.
func (obj *Greeter) TarsSetTimeout(t int) {
obj.s.TarsSetTimeout(t)
}
//TarsSetProtocol is required by the servant interface. t is the protocol.
func (obj *Greeter) TarsSetProtocol(p model.Protocol) {
obj.s.TarsSetProtocol(p)
}
type impGreeter interface {
SayHello(input HelloRequest) (output HelloReply, err error)
}
type impGreeterWithContext interface {
SayHello(ctx context.Context, input HelloRequest) (output HelloReply, err error)
}
//Dispatch is used to call the user implement of the defined method.
func (obj *Greeter) Dispatch(ctx context.Context, val interface{}, req *requestf.RequestPacket, resp *requestf.ResponsePacket, withContext bool) (err error) {
input := tools.Int8ToByte(req.SBuffer)
var output []byte
funcName := req.SFuncName
switch funcName {
case "SayHello":
inputDefine := HelloRequest{}
if err = proto.Unmarshal(input, &inputDefine); err != nil {
return err
}
var res HelloReply
if withContext == false {
imp := val.(impGreeter)
res, err = imp.SayHello(inputDefine)
if err != nil {
return err
}
} else {
imp := val.(impGreeterWithContext)
res, err = imp.SayHello(ctx, inputDefine)
if err != nil {
return err
}
}
output, err = proto.Marshal(&res)
if err != nil {
return err
}
default:
return fmt.Errorf("func mismatch")
}
var _status map[string]string
s, ok := current.GetResponseStatus(ctx)
if ok && s != nil {
_status = s
}
var _context map[string]string
c, ok := current.GetResponseContext(ctx)
if ok && c != nil {
_context = c
}
*resp = requestf.ResponsePacket{
IVersion: 1,
CPacketType: 0,
IRequestId: req.IRequestId,
IMessageType: 0,
IRet: 0,
SBuffer: tools.ByteToInt8(output),
Status: _status,
SResultDesc: "",
Context: _context,
}
return nil
}
// SayHello is client rpc method as defined
func (obj *Greeter) SayHello(input HelloRequest, _opt ...map[string]string) (output HelloReply, err error) {
ctx := context.Background()
return obj.SayHelloWithContext(ctx, input, _opt...)
}
// SayHelloWithContext is client rpc method as defined
func (obj *Greeter) SayHelloWithContext(ctx context.Context, input HelloRequest, _opt ...map[string]string) (output HelloReply, err error) {
var inputMarshal []byte
inputMarshal, err = proto.Marshal(&input)
if err != nil {
return output, err
}
var _status map[string]string
var _context map[string]string
if len(_opt) == 1 {
_context = _opt[0]
} else if len(_opt) == 2 {
_context = _opt[0]
_status = _opt[1]
}
resp := new(requestf.ResponsePacket)
err = obj.s.Tars_invoke(ctx, 0, "SayHello", inputMarshal, _status, _context, resp)
if err != nil {
return output, err
}
if err = proto.Unmarshal(tools.Int8ToByte(resp.SBuffer), &output); err != nil {
return output, err
}
if len(_opt) == 1 {
for k := range _context {
delete(_context, k)
}
for k, v := range resp.Context {
_context[k] = v
}
} else if len(_opt) == 2 {
for k := range _context {
delete(_context, k)
}
for k, v := range resp.Context {
_context[k] = v
}
for k := range _status {
delete(_status, k)
}
for k, v := range resp.Status {
_status[k] = v
}
}
return output, nil
}
第六步,我们在项目下创建一个服务端和客户端,完整目录如下:
客户端:
package main
import (
"fmt"
"github.com/TarsCloud/TarsGo/tars"
"protoTest/proto/helloworld"
)
func main() {
comm := tars.NewCommunicator()
obj := fmt.Sprintf("StressTest.HelloPbServer.GreeterTestObj@tcp -h 127.0.0.1 -p 10014 -t 60000")
app := new(helloworld.Greeter)
comm.StringToProxy(obj, app)
input := helloworld.HelloRequest{Name: "sandyskies"}
output, err := app.SayHello(input)
if err != nil {
fmt.Println("err: ", err)
}
fmt.Println("result is:", output.Message)
}
服务端:
package main
import (
"github.com/TarsCloud/TarsGo/tars"
"protoTest/proto/helloworld"
)
type GreeterImp struct {
}
func (imp *GreeterImp) SayHello(input helloworld.HelloRequest)(output helloworld.HelloReply, err error) {
output.Message = "hello" + input.GetName()
return output, nil
}
func main() { //Init servant
imp := new(GreeterImp) //New Imp
app := new(helloworld.Greeter) //New init the A JCE
cfg := tars.GetServerConfig() //Get Config File Object
app.AddServant(imp, cfg.App+"."+cfg.Server+".GreeterTestObj") //Register Servant
tars.Run()
}
最后,tarsgo基于protobuf开发的小栗子完成。