golang中gRpc的安装&goland 插件protobuf support

一、简介
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主要用生成客户端实例,再调用实例的方法。
二、安装
1、https://github.com/protocolbuffers/protobuf/releases,下载protocol buffer编译器protoc,找到对应的系统版本,如linux下为x86_64。下载后解压,将bin目录下的可执行文件放到系统环境变量$GOPATH/bin下。
2、$GOPATH:go get -u github.com/golang/protobuf/protoc-gen-go,获取protol buffer编译器的插件protoc-gen-go,gRPC 提供 protocol buffer 编译插件,能够从一个服务定义的 .proto 文件生成客户端和服务端代码。
3、$GOPATH:go get github.com/golang/protobuf/proto,将库源码拉到本地,执行此命令时会自动下载库依赖。
4、go build github.com/golang/protobuf/proto,进行编译。
(github源码:https://github.com/grpc/grpc-go)
5、git clone https://github.com/grpc/grpc-go.git $GOPATH/src/google.golang.org/grpc
6、git clone https://github.com/golang/net.git $GOPATH/src/golang.org/x/net
7、git clone https://github.com/golang/sys.git $GOPATH/src/golang.org/x/sys
8、git clone https://github.com/golang/text.git $GOPATH/src/golang.org/x/text
9、git clone https://github.com/google/go-genproto.git $GOPATH/src/google.golang.org/genproto
即protoc编译器二进制文件和插件protoc-gen-go

三、运行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)
}

如果没删除pb.go中内容则对server.go和client.go中内容进行对应修改:

server.go
	return &common.BlockResponse{"bolck msg"+in.Name, struct{}{},[]byte{},2}, nil
client.go
	request, err := client.BKService(context.Background(), &common.BlockRequest{name, struct{}{},[]byte{},10})

运行:

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

五、goland 插件protobuf support
1、直接能找到插件
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
2、如果没有Protobuf Support插件则可手动安装:
https://github.com/protostuff/protobuf-jetbrains-plugin/releases找到对应goland版本的版本,如我用的goland2018.1,下载的protobuf-jetbrains-plugin-0.10.2.zip。下载完直接拖进打开的goland,会提示重启goland。可能出现的情况就是版本不兼容。
在这里插入图片描述
6、更换插件版本

../../vendor/github.com/hyperledger/fabric/opbridge/opbridge/opbridge.pb.go:44:11: undefined: "github.com/hyperledger/fabric/vendor/github.com/golang/protobuf/proto".ProtoPackageIsVersion4

遇到问题undefined: proto.ProtoPackageIsVersion4时候,发现fabric2.1所用的版本是:const _ = proto.ProtoPackageIsVersion3,需要将protobuf版本回退到v1.3.0,重新编译proto-gen-go插件:

wang@wang:~/go/src/github.com/golang/protobuf$ git checkout -f v1.3.0
Note: checking out 'v1.3.0'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

  git checkout -b <new-branch-name>

HEAD is now at c823c79... ptypes: More cleanly construct a Timestamp (#797)
wang@wang:~/go/src/github.com/golang/protobuf$
wang@wang:~/go/src/github.com/golang/protobuf$ cd protoc-gen-go/
wang@wang:~/go/src/github.com/golang/protobuf/protoc-gen-go$ ls
descriptor  generator       grpc          main.go  testdata
doc.go      golden_test.go  link_grpc.go  plugin
wang@wang:~/go/src/github.com/golang/protobuf/protoc-gen-go$ go install

然后重新生成xx.pb.go文件,查看const _ = proto.ProtoPackageIsVersion3

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值