How to use grpc

The first step is to install the environment

The official website installation command:

go get -u google.golang.org/grpc

It seems that it ca n’t be used, and I ca n’t even connect to the server. Even if I hang up the VPN, it ’s useless. There is no way to install it in a roundabout way. Anyway, the code is available on github, just clone it from github. The required libraries include grpc-go, golang / net, golang / text, protobuf / proto, protobuf / protoc-gen-go, google / go-genproto

# 如果已经安装了proto(编译proto文件的工具)和protoc-gen-go(proto将proto文件编译成go语言形式的插件)的话就不用安装了
go get -u github.com/golang/protobuf/{proto,protoc-gen-go}

# 下载grpc-go
git clone https://github.com/grpc/grpc-go.git $GOPATH/src/google.golang.org/grpc

# 下载golang/net
git clone https://github.com/golang/net.git $GOPATH/src/golang.org/x/net

# 下载golang/text
git clone https://github.com/golang/text.git $GOPATH/src/golang.org/x/text

# 下载go-genproto
git clone https://github.com/google/go-genproto.git $GOPATH/src/google.golang.org/genproto

# 安装
cd $GOPATH/src/
go install google.golang.org/grpc

 

The second step is to write a proto file

Construct a message, message is a parameter, there are generally request parameters and response parameters

Write an interface, the methods in the interface are used by the client and the server to call

$ GOPATH / src / helloworld / helloworld / helloworld.proto code:

syntax = "proto3";

package helloworld;

//定义服务
service Greeter{ //定义了这么一个接口,protoc这个工具将会生成两个,一个是client一个是server,因为这是一个rpc接口,里面的方法SayHello,客户端会调用这个方法,调用的这个请求会发送给服务端,服务端那边也要实现,服务端那边实现,客户端这边用
    rpc SayHello(HelloRequest) returns(HelloReply){}; //接口中的方法
}
message HelloRequest{ //方法的请求参数
    string name = 1;
}
message HelloReply{ //方法的响应参数
    string message = 1;
}

Generate go code through protoc:

$GOPATH/src/helloworld/helloworld/helloworld.pb.go代码

// Code generated by protoc-gen-go. DO NOT EDIT.
// source: helloworld/helloworld.proto

package helloworld

import (
	"context"
	"fmt"
	"github.com/golang/protobuf/proto"
	"google.golang.org/grpc"
	"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

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_73149fedf49f4319, []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 ""
}

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_73149fedf49f4319, []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/helloworld.proto", fileDescriptor_73149fedf49f4319) }

var fileDescriptor_73149fedf49f4319 = []byte{
	// 144 bytes of a gzipped FileDescriptorProto
	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0xce, 0x48, 0xcd, 0xc9,
	0xc9, 0x2f, 0xcf, 0x2f, 0xca, 0x49, 0xd1, 0x47, 0x30, 0xf5, 0x0a, 0x8a, 0xf2, 0x4b, 0xf2, 0x85,
	0xb8, 0x10, 0x22, 0x4a, 0x4a, 0x5c, 0x3c, 0x1e, 0x20, 0x5e, 0x50, 0x6a, 0x61, 0x69, 0x6a, 0x71,
	0x89, 0x90, 0x10, 0x17, 0x4b, 0x5e, 0x62, 0x6e, 0xaa, 0x04, 0xa3, 0x02, 0xa3, 0x06, 0x67, 0x10,
	0x98, 0xad, 0xa4, 0xc6, 0xc5, 0x05, 0x55, 0x53, 0x90, 0x53, 0x29, 0x24, 0xc1, 0xc5, 0x9e, 0x9b,
	0x5a, 0x5c, 0x9c, 0x98, 0x0e, 0x53, 0x04, 0xe3, 0x1a, 0x79, 0x72, 0xb1, 0xbb, 0x17, 0xa5, 0xa6,
	0x96, 0xa4, 0x16, 0x09, 0xd9, 0x71, 0x71, 0x04, 0x27, 0x56, 0x82, 0x75, 0x09, 0x49, 0xe8, 0x21,
	0xb9, 0x00, 0xd9, 0x32, 0x29, 0x31, 0x2c, 0x32, 0x05, 0x39, 0x95, 0x4a, 0x0c, 0x49, 0x6c, 0x60,
	0x97, 0x1a, 0x03, 0x02, 0x00, 0x00, 0xff, 0xff, 0xea, 0x27, 0x0c, 0x07, 0xc8, 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

// GreeterClient is the client API for Greeter service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type GreeterClient interface {
	SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error)
}

// greeterClient已经实现了那个接口,到时候调用SayHello直接掉就行了
type greeterClient struct {
	cc *grpc.ClientConn
}

func NewGreeterClient(cc *grpc.ClientConn) GreeterClient { //客户端产生一个新的客户端,这个是给客户端使用的
	return &greeterClient{cc}
}

func (c *greeterClient) SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error) {
	out := new(HelloReply)
	err := c.cc.Invoke(ctx, "/helloworld.Greeter/SayHello", in, out, opts...) //客户端调用完SayHello自动就会往grpc上发
	if err != nil {
		return nil, err
	}
	return out, nil
}

// GreeterServer is the server API for Greeter service.
type GreeterServer interface {
	//服务端怎么实现这个接口它根本就不知道怎么实现,服务端向让它实现什么它就实现什么,比如接收了SayHello了怎么处理,完了怎么回复,这个工具是不知道,这个是留给我们来实现的,这个是代码的核心逻辑
	SayHello(context.Context, *HelloRequest) (*HelloReply, error)
}

func RegisterGreeterServer(s *grpc.Server, srv GreeterServer) {
	s.RegisterService(&_Greeter_serviceDesc, srv)
}

func _Greeter_SayHello_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
	in := new(HelloRequest)
	if err := dec(in); err != nil {
		return nil, err
	}
	if interceptor == nil {
		return srv.(GreeterServer).SayHello(ctx, in)
	}
	info := &grpc.UnaryServerInfo{
		Server:     srv,
		FullMethod: "/helloworld.Greeter/SayHello",
	}
	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
		return srv.(GreeterServer).SayHello(ctx, req.(*HelloRequest))
	}
	return interceptor(ctx, in, info, handler)
}

var _Greeter_serviceDesc = grpc.ServiceDesc{
	ServiceName: "helloworld.Greeter",
	HandlerType: (*GreeterServer)(nil),
	Methods: []grpc.MethodDesc{
		{
			MethodName: "SayHello",
			Handler:    _Greeter_SayHello_Handler,
		},
	},
	Streams:  []grpc.StreamDesc{},
	Metadata: "helloworld/helloworld.proto",
}

The third step is to realize the server

First define a structure. This structure must implement the above interface. Only after this interface is implemented can external services be provided.

Then you can start the main program

$ GOPATH / src / helloworld / greeter_server / main.go code:

package main

import (
	"golang.org/x/net/context"
	"google.golang.org/grpc/examples/helloworld/helloworld"
	"fmt"
	"net"
	"log"
	"google.golang.org/grpc"
)

const(
	port = ":5001"
)

type service struct{ //用来实现前面生成的接口

}

//对外提供一个供客户端调用的函数,只要客户端按照我这里要求传参,我就能对外提供一个我这里规定返回数据
func (s *service)SayHello(ctx context.Context, r *helloworld.HelloRequest) (*helloworld.HelloReply, error){ //通过Alt+Enter加入引入的包
	fmt.Println(r.Name)
	return &helloworld.HelloReply{Message:"hello," + r.Name},nil
}

func main(){
	lis,err := net.Listen("tcp", port) //监听请求

	if err != nil{
		log.Fatal("fail to listen")
	}

	s := grpc.NewServer() //NewServer一个grpc
	helloworld.RegisterGreeterServer(s, &service{}) //起到桥梁的作用 把GreaterServer注册到grpc里面去 把前面实现的service服务的结构体注册到grpc里面去,目的是实现的东西要让grpc系统知道
	if err := s.Serve(lis);err != nil{ //启动 这个服务由grpc来完成 死循环永远启动在这里
		log.Fatal("fail to server")
	}
}

The fourth step is to implement the client

First connect to the server, and then generate a client structure

$ GOPATH / src / helloworld / greeter_clinet / main.go code:

package main

import (
	"google.golang.org/grpc"
	"log"
	"helloworld/helloworld"
	"golang.org/x/net/context"
	"fmt"
)

const(
	address = "127.0.0.1:5001"
)
//在客户端这里就不需要实现接口,客户端只管调用
func main(){
	conn,err := grpc.Dial(address, grpc.WithInsecure())
	if err != nil{
		log.Fatal("didnot connect server")
	}

	defer conn.Close()

	c := helloworld.NewGreeterClient(conn) //创建一个客户端 GreeterClient它内部维护了grpc链接 通过这个grpc链接就具有了远程调用能力

	r,err := c.SayHello(context.Background(), &helloworld.HelloRequest{Name:"xww"})
	if err != nil{
		log.Fatal("could not greet")
	}
	fmt.Println(r.Message)

}

 

Published 25 original articles · Like2 · Visits 20,000+

Guess you like

Origin blog.csdn.net/longjuanfengzc/article/details/88183982