Go-GRPC 初體驗


grpc 跟常見的client-server模型相似(doubbo)
grpc 編碼之前需要准備以下環境:

  • 安裝protobuf,grpc的client與server之間消息傳遞使用的protoc格式消息,比起json,xml速度快
  • 安裝grpc 的源碼包

下面開始編寫grpc示例代碼:

  1. 首先編寫proto文件,示例:helloworld
syntax = "proto3";

option objc_class_prefix = "HLW";

package helloworld;

// 定義一個Greeter服務,其中API為SayHello
// 形式參數: HelloRequest
// 返回參數:HelloReply
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply) {}

  // rpc 借口的類型分為一下四種: A為接受參數,B為返回參數
  // 1. rpc GetFeature(Point) returns (Feature) {} 普通調用:A-B
  // 2. rpc ListFeatures(Rectangle) returns (stream Feature) {} 單向流:A - B(流)
  // 3. rpc RecordRoute(stream Point) returns (RouteSummary) {} 單向流:A(流) - B
  // 4. rpc RouteChat(stream RouteNote) returns (stream RouteNote) {} 雙向流:A(流) - B(流)
}

// 請求參數-根據自己的需求定義
message HelloRequest {
  string name = 1;
}

// 返回參數-根據自己的需求定義
message HelloReply {
  string message = 1;
}

  2.  將helloworld.proto轉化為helloworld.proto.go 

命令:protoc --go_out=plugins=grpc:. helloworld.proto 結果如下:

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

/*
Package helloworld is a generated protocol buffer package.

It is generated from these files:
	helloworld.proto

It has these top-level messages:
	HelloRequest
	HelloReply
*/
package myblogproto

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

// 請求參數-根據自己的需求定義
type HelloRequest struct {
	Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
}

func (m *HelloRequest) Reset()                    { *m = HelloRequest{} }
func (m *HelloRequest) String() string            { return proto.CompactTextString(m) }
func (*HelloRequest) ProtoMessage()               {}
func (*HelloRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }

func (m *HelloRequest) GetName() string {
	if m != nil {
		return m.Name
	}
	return ""
}

// 返回參數-根據自己的需求定義
type HelloReply struct {
	Message string `protobuf:"bytes,1,opt,name=message" json:"message,omitempty"`
}

func (m *HelloReply) Reset()                    { *m = HelloReply{} }
func (m *HelloReply) String() string            { return proto.CompactTextString(m) }
func (*HelloReply) ProtoMessage()               {}
func (*HelloReply) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }

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")
}

// 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 Greeter service

type GreeterClient interface {
	// Sends a greeting
	SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error)
}

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 := grpc.Invoke(ctx, "/helloworld.Greeter/SayHello", in, out, c.cc, opts...)
	if err != nil {
		return nil, err
	}
	return out, nil
}

// Server API for Greeter service

type GreeterServer interface {
	// Sends a greeting
	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.proto",
}

func init() { proto.RegisterFile("helloworld.proto", fileDescriptor0) }

var fileDescriptor0 = []byte{
	// 149 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, 0x38, 0xb1, 0x2d, 0x62, 0x62, 0xf6,
	0xf0, 0x09, 0x4f, 0x62, 0x03, 0xbb, 0xd8, 0x18, 0x10, 0x00, 0x00, 0xff, 0xff, 0xbe, 0xde, 0x1d,
	0x2e, 0xc5, 0x00, 0x00, 0x00,
}

  3. 編寫grpc服務端,偽代碼:

package main

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

	pb "unicontract-validate/tests/grpcStudy/mybloggrpc/myblogproto"
)

const port = ":50051"

// 定義struct實現我們自定義的helloworld.proto對應的服務
type myServer struct {
}

func (m *myServer) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
	return &pb.HelloReply{"請求server端成功!"}, nil
}

/**
	1. 首先我們必須實現我們自定義rpc服務,例如:rpc SayHello()-在此我們可以實現我們自己的邏輯
	2. 創建監聽listener
	3. 創建grpc的服務
	4. 將我們的服務注冊到grpc的server中
	5. 啟動grpc服務,將我們自定義的監聽信息傳遞給grpc服務器
 */

func main() {

	//	創建server端監聽端口
	list, err := net.Listen("tcp", port)
	if err != nil {
		fmt.Println(err)
	}

	//	創建grpc的server
	server := grpc.NewServer()
	//	注冊我們自定義的helloworld服務
	pb.RegisterGreeterServer(server, &myServer{})

	//	啟動grpc服務
	fmt.Println("grpc 服務啟動... ...")
	server.Serve(list)
}

  4. 編寫client端代碼,偽代碼如下:

package main

import (
	"google.golang.org/grpc"
	"fmt"
	"context"

	pb "unicontract-validate/tests/grpcStudy/mybloggrpc/myblogproto"
)

// 此處應與服務器端對應
const address  = "127.0.0.1:50051"

/**
	1. 創建groc連接器
	2. 創建grpc客戶端,並將連接器賦值給客戶端
	3. 向grpc服務端發起請求
	4. 獲取grpc服務端返回的結果
 */
func main()  {

	// 創建一個grpc連接器
	conn, err := grpc.Dial(address, grpc.WithInsecure())
	if err != nil{
		fmt.Println(err)
	}
	// 當請求完畢后記得關閉連接,否則大量連接會占用資源
	defer conn.Close()

	// 創建grpc客戶端
	c := pb.NewGreeterClient(conn)

	name := "我是客戶端,正在請求服務端!!!"
	// 客戶端向grpc服務端發起請求
	result, err := c.SayHello(context.Background(), &pb.HelloRequest{Name:name})
	fmt.Println(name)
	if err != nil{
		fmt.Println("請求失敗!!!")
		return
	}
	// 獲取服務端返回的結果
	fmt.Println(result.Message)
}

  服務端結果:

  客戶端請求之后結果:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM