1、
(1)Protocol Buffers(简称protobuf)用于结构化数据和字节码之间互相转换(即实现从结构体转换为字节流以及从字节流转换为结构体),一旦你定义了自己的报文格式(message),你就可以运行ProtocolBuffer编译器,将你的.proto文件编译成特定语言的类。
(2)proto里的message,pb.go里的结构体(带方法)
proto里的service,pb.go里Client API for Events service处供客户端使用的接口定义、接口实例、接口实例的初始化函数。Server API for Events service处供服务端使用的接口定义,注册函数。如果其中某一端或同时两端为流式RPC,在有流的一端,会专门为其流生成接口定义、接口实例。可以直接使用生成的实例,也可以自己实现接口,自定义实例。接口定义的主要方法就是Send和Recv。
(3)GRPC的Client与Server,均通过Netty Channel作为数据通信;序列化、反序列化则使用Protobuf,每个请求都将被封装成HTTP2的Stream,在整个生命周期中,客户端Channel应该保持长连接,而不是每次调用重新创建Channel、响应结束后关闭Channel(即短连接、交互式的RPC),目的就是达到链接的复用,进而提高交互效率。
(4)服务端用pb.go里的方法主要有注册;客户端用pb.go主要用生成客户端实例,再调用实例的方法。
2、https://github.com/protocolbuffers/protobuf/releases,下载protocol buffer编译器protoc,找到对应的系统版本,如linux下为x86_64。下载后解压,将bin目录下的可执行文件放到系统环境变量$GOPATH/bin下。
3、$GOPATH:go get -u github.com/golang/protobuf/protoc-gen-go
,获取protol buffer的编译器插件protoc-gen-go,gRPC 提供 protocol buffer 编译插件,能够从一个服务定义的 .proto 文件生成客户端和服务端代码。
4、$GOPATH:go get github.com/golang/protobuf/proto
,将库源码拉到本地,执行此命令时会自动下载库依赖。
5、go build github.com/golang/protobuf/proto
,进行编译。
(github源码:https://github.com/grpc/grpc-go)
6、git clone https://github.com/grpc/grpc-go.git $GOPATH/src/google.golang.org/grpc
7、git clone https://github.com/golang/net.git $GOPATH/src/golang.org/x/net
8、git clone https://github.com/golang/sys.git $GOPATH/src/golang.org/x/sys
9、git clone https://github.com/golang/text.git $GOPATH/src/golang.org/x/text
10、git clone https://github.com/google/go-genproto.git $GOPATH/src/google.golang.org/genproto
运行hellowrold例子:
$GOPATH/src/google.golang.org/grpc/examples/helloworld/greeter_server$ go run main.go
$GOPATH/src/google.golang.org/grpc/examples/helloworld/greeter_client$ go run main.go
输出:
wang@wang:~/go/src/google.golang.org/grpc/examples/helloworld/greeter_client$ go run main.go
2018/09/22 17:20:40 Greeting: Hello world
再做一个Demo:
新建工程grpcT,目录如上。
1.common.proto内容:
syntax = "proto3";
package common;
option java_multiple_files = true;
option java_package = "io.grpc.examples.common";
option java_outer_classname = "BlockServiceProto";
message Block {
int32 id = 1;
string hash = 2;
string payload = 3;
}
service BlockService {
rpc BKService (BlockRequest) returns (BlockResponse) {}
}
message BlockRequest {
string name = 1;
}
message BlockResponse {
string message = 1;
}
使用protoc命令编译.proto文件:
- -I 参数:指定import路径,可以指定多个 -I参数,按顺序查找,默认只查找当前目录
- –go_out :golang编译支持,支持以下参数:
1、plugins=plugin1+plugin2 - 指定插件,目前只有grpc,即:plugins=grpc
2、M 参数 - 指定导入的.proto文件路径编译后对应的golang包名(不指定本参数默认就是.proto文件中import语句的路径)
3、import_prefix=xxx - 为所有import路径添加前缀,主要用于编译子目录内的多个proto文件,这个参数按理说很有用,尤其适用替代hello_http.proto编译时的M参数,但是实际使用时有个蛋疼的问题,自己尝试看看吧
4、import_path=foo/bar - 用于指定未声明package或go_package的文件的包名,最右面的斜线前的字符会被忽略
5、:编译文件路径 .proto文件路径(支持通配符)
6、同一个包内包含多个.proto文件时使用通配符同时编译所有文件,单独编译每个文件会存在变量命名冲突
完整示例:
protoc --go_out=plugins=grpc,Mfoo/bar.proto=bar,import_prefix=foo/,import_path=foo/bar:. ./*.proto
利用protoc在当前文件夹内生成pb源代码文件:
命令:protoc --go_out=plugins=grpc:. ./common.proto
对生成的common.pb.go文件,对文件内的xxx内容进行删除,删除完如下:
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: common.proto
package common
import (
fmt "fmt"
proto "github.com/golang/protobuf/proto"
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
type Block struct {
Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
Hash string `protobuf:"bytes,2,opt,name=hash,proto3" json:"hash,omitempty"`
Payload string `protobuf:"bytes,3,opt,name=payload,proto3" json:"payload,omitempty"`
//XXX_NoUnkeyedLiteral struct{} `json:"-"`
//XXX_unrecognized []byte `json:"-"`
//XXX_sizecache int32 `json:"-"`
}
func (m *Block) Reset() { *m = Block{} }
func (m *Block) String() string { return proto.CompactTextString(m) }
func (*Block) ProtoMessage() {}
func (*Block) Descriptor() ([]byte, []int) {
return fileDescriptor_555bd8c177793206, []int{0}
}
//func (m *Block) XXX_Unmarshal(b []byte) error {
// return xxx_messageInfo_Block.Unmarshal(m, b)
//}
//func (m *Block) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
// return xxx_messageInfo_Block.Marshal(b, m, deterministic)
//}
//func (m *Block) XXX_Merge(src proto.Message) {
// xxx_messageInfo_Block.Merge(m, src)
//}
//func (m *Block) XXX_Size() int {
// return xxx_messageInfo_Block.Size(m)
//}
//func (m *Block) XXX_DiscardUnknown() {
// xxx_messageInfo_Block.DiscardUnknown(m)
//}
//
//var xxx_messageInfo_Block proto.InternalMessageInfo
func (m *Block) GetId() int32 {
if m != nil {
return m.Id
}
return 0
}
func (m *Block) GetHash() string {
if m != nil {
return m.Hash
}
return ""
}
func (m *Block) GetPayload() string {
if m != nil {
return m.Payload
}
return ""
}
type BlockRequest 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 *BlockRequest) Reset() { *m = BlockRequest{} }
func (m *BlockRequest) String() string { return proto.CompactTextString(m) }
func (*BlockRequest) ProtoMessage() {}
func (*BlockRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_555bd8c177793206, []int{1}
}
//func (m *BlockRequest) XXX_Unmarshal(b []byte) error {
// return xxx_messageInfo_BlockRequest.Unmarshal(m, b)
//}
//func (m *BlockRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
// return xxx_messageInfo_BlockRequest.Marshal(b, m, deterministic)
//}
//func (m *BlockRequest) XXX_Merge(src proto.Message) {
// xxx_messageInfo_BlockRequest.Merge(m, src)
//}
//func (m *BlockRequest) XXX_Size() int {
// return xxx_messageInfo_BlockRequest.Size(m)
//}
//func (m *BlockRequest) XXX_DiscardUnknown() {
// xxx_messageInfo_BlockRequest.DiscardUnknown(m)
//}
//
//var xxx_messageInfo_BlockRequest proto.InternalMessageInfo
func (m *BlockRequest) GetName() string {
if m != nil {
return m.Name
}
return ""
}
type BlockResponse 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 *BlockResponse) Reset() { *m = BlockResponse{} }
func (m *BlockResponse) String() string { return proto.CompactTextString(m) }
func (*BlockResponse) ProtoMessage() {}
func (*BlockResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_555bd8c177793206, []int{2}
}
//func (m *BlockResponse) XXX_Unmarshal(b []byte) error {
// return xxx_messageInfo_BlockResponse.Unmarshal(m, b)
//}
//func (m *BlockResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
// return xxx_messageInfo_BlockResponse.Marshal(b, m, deterministic)
//}
//func (m *BlockResponse) XXX_Merge(src proto.Message) {
// xxx_messageInfo_BlockResponse.Merge(m, src)
//}
//func (m *BlockResponse) XXX_Size() int {
// return xxx_messageInfo_BlockResponse.Size(m)
//}
//func (m *BlockResponse) XXX_DiscardUnknown() {
// xxx_messageInfo_BlockResponse.DiscardUnknown(m)
//}
//
//var xxx_messageInfo_BlockResponse proto.InternalMessageInfo
func (m *BlockResponse) GetMessage() string {
if m != nil {
return m.Message
}
return ""
}
func init() {
proto.RegisterType((*Block)(nil), "common.Block")
proto.RegisterType((*BlockRequest)(nil), "common.BlockRequest")
proto.RegisterType((*BlockResponse)(nil), "common.BlockResponse")
}
// 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
// BlockServiceClient is the client API for BlockService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type BlockServiceClient interface {
BKService(ctx context.Context, in *BlockRequest, opts ...grpc.CallOption) (*BlockResponse, error)
}
type blockServiceClient struct {
cc *grpc.ClientConn
}
func NewBlockServiceClient(cc *grpc.ClientConn) BlockServiceClient {
return &blockServiceClient{cc}
}
func (c *blockServiceClient) BKService(ctx context.Context, in *BlockRequest, opts ...grpc.CallOption) (*BlockResponse, error) {
out := new(BlockResponse)
err := c.cc.Invoke(ctx, "/common.BlockService/BKService", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// BlockServiceServer is the server API for BlockService service.
type BlockServiceServer interface {
BKService(context.Context, *BlockRequest) (*BlockResponse, error)
}
func RegisterBlockServiceServer(s *grpc.Server, srv BlockServiceServer) {
s.RegisterService(&_BlockService_serviceDesc, srv)
}
func _BlockService_BKService_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(BlockRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(BlockServiceServer).BKService(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/common.BlockService/BKService",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(BlockServiceServer).BKService(ctx, req.(*BlockRequest))
}
return interceptor(ctx, in, info, handler)
}
var _BlockService_serviceDesc = grpc.ServiceDesc{
ServiceName: "common.BlockService",
HandlerType: (*BlockServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "BKService",
Handler: _BlockService_BKService_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "common.proto",
}
func init() { proto.RegisterFile("common.proto", fileDescriptor_555bd8c177793206) }
var fileDescriptor_555bd8c177793206 = []byte{
// 218 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x5c, 0x90, 0xc1, 0x4a, 0x03, 0x31,
0x10, 0x86, 0xcd, 0x6a, 0x2b, 0x3b, 0x54, 0xc1, 0xa0, 0x18, 0x3c, 0x95, 0x9c, 0xea, 0x25, 0x07,
0xbd, 0x79, 0x0c, 0x78, 0xd1, 0x4b, 0x89, 0x4f, 0x10, 0xb3, 0x43, 0x1b, 0xdc, 0xec, 0xc4, 0x4d,
0x15, 0x7d, 0x7b, 0xd9, 0x34, 0x81, 0xc5, 0xdb, 0x7c, 0xc3, 0x9f, 0xef, 0x27, 0x03, 0x2b, 0x47,
0x21, 0xd0, 0xa0, 0xe2, 0x48, 0x07, 0xe2, 0xcb, 0x23, 0xc9, 0x67, 0x58, 0xe8, 0x9e, 0xdc, 0x07,
0xbf, 0x84, 0xc6, 0x77, 0x82, 0xad, 0xd9, 0x66, 0x61, 0x1a, 0xdf, 0x71, 0x0e, 0x67, 0x7b, 0x9b,
0xf6, 0xa2, 0x59, 0xb3, 0x4d, 0x6b, 0xf2, 0xcc, 0x05, 0x9c, 0x47, 0xfb, 0xdb, 0x93, 0xed, 0xc4,
0x69, 0x5e, 0x57, 0x94, 0x12, 0x56, 0x59, 0x63, 0xf0, 0xf3, 0x0b, 0xd3, 0x61, 0x7a, 0x3d, 0xd8,
0x80, 0xd9, 0xd7, 0x9a, 0x3c, 0xcb, 0x7b, 0xb8, 0x28, 0x99, 0x14, 0x69, 0x48, 0x38, 0xe9, 0x02,
0xa6, 0x64, 0x77, 0x35, 0x57, 0xf1, 0xe1, 0xa5, 0xe8, 0xde, 0x70, 0xfc, 0xf6, 0x0e, 0xf9, 0x13,
0xb4, 0xfa, 0xb5, 0xc2, 0xb5, 0x2a, 0x3f, 0x99, 0x37, 0xde, 0xdd, 0xfc, 0xdb, 0x1e, 0x3b, 0xe4,
0x89, 0x56, 0x70, 0xeb, 0x49, 0xed, 0xc6, 0xe8, 0x14, 0xfe, 0xd8, 0x10, 0x7b, 0x4c, 0x25, 0xaa,
0xaf, 0xe6, 0x25, 0xdb, 0xe9, 0x2e, 0x5b, 0xf6, 0xbe, 0xcc, 0x07, 0x7a, 0xfc, 0x0b, 0x00, 0x00,
0xff, 0xff, 0x70, 0x66, 0xc7, 0xc1, 0x30, 0x01, 0x00, 0x00,
}
2.写对应的server.go和client.go。
server.go内容如下:
package main
import (
"grpcT/common"
"net"
"log"
"google.golang.org/grpc"
"golang.org/x/net/context"
)
const (
port = "8080"
)
type server struct {
}
func (s *server)BKService(ctx context.Context, in *common.BlockRequest) (*common.BlockResponse, error) {
return &common.BlockResponse{"bolck msg"+in.Name}, nil
}
//listen,server on
func main() {
listen, err := net.Listen("tcp4", "localhost:"+port)
if err != nil {
log.Fatal("failed to listen: %v",err)
}
s := grpc.NewServer()
common.RegisterBlockServiceServer(s,&server{})
s.Serve(listen)
}
client.go内容如下:
package main
import (
"google.golang.org/grpc"
"log"
"grpcT/common"
"os"
"golang.org/x/net/context"
)
const (
address = "localhost:8080"
defaultName = "block"
)
func main() {
conn, err := grpc.Dial(address,grpc.WithInsecure())
if err != nil {
log.Fatal("did not connect: %v",err )
}
defer conn.Close()
client := common.NewBlockServiceClient(conn)
name := defaultName
if len(os.Args) >1 {
name = os.Args[1]
}
request, err := client.BKService(context.Background(), &common.BlockRequest{name})
if err != nil {
log.Fatal("could not block: %v", err)
}
log.Printf("block: %s",request.Message)
}
运行:
wang@wang:~/go/src/grpcT/main$ go run server.go
wang@wang:~/go/src/grpcT/main$ go run client.go
输出:
wang@wang:~/go/src/grpcT/main$ go run client.go
2018/09/22 17:29:00 block: bolck msgblock
linux下goland2018.1.5安装了0.10.2版本的Protobuf Support:
file->Settings->Plugins->Browse repositories->输入protobuf support->install
file->Settings->Editor->File Types,找到Protobuf,进行注册*.proto->restart goland
来源:CSDN
作者:导演我躺哪儿
链接:https://blog.csdn.net/u010931295/article/details/82811113