Go gRPC Series 2: унарный клиент и сервер

Go

предисловие

Всем привет, меня зовут Jianyu. В этой главе я буду использовать Go для написания сервера gRPC и клиента для связи друг с другом. Кроме того, будут использоваться следующие библиотеки:

  • google.golang.org/grpc
  • github.com/golang/protobuf/protoc-gen-go

Установить

gRPC

go get -u google.golang.org/grpc

Protocol Buffers v3

wget https://github.com/google/protobuf/releases/download/v3.5.1/protobuf-all-3.5.1.zip
unzip protobuf-all-3.5.1.zip
cd protobuf-3.5.1/
./configure
make
make install

Проверьте, прошла ли установка успешно

protoc --version

Если возникает следующая ошибка, выполнитеldconfigИменование решает эту проблему

protoc: error while loading shared libraries: libprotobuf.so.15: cannot open shared object file: No such file or directory

Protoc Plugin

go get -u github.com/golang/protobuf/protoc-gen-go

Если есть проблема со средой установки, обратитесь к моей предыдущей статье«Введение и установка среды»В нем есть подробные вступления, поэтому я не буду их повторять.

gRPC

В этом разделе начинается формальное написание программ, связанных с gRPC, давайте вместе сядем в автобус 😄

значок

image

Структура каталогов

$ tree go-grpc-example 
go-grpc-example
├── client
├── proto
│   └── search.proto
└── server.go

IDL

написать

В файле search.proto в папке proto напишите следующее:

syntax = "proto3";

package proto;

service SearchService {
    rpc Search(SearchRequest) returns (SearchResponse) {}
}

message SearchRequest {
    string request = 1;
}

message SearchResponse {
    string response = 1;
}

генерировать

Выполните следующую команду в папке proto:

$ protoc --go_out=plugins=grpc:. *.proto
  • plugins=plugin1+plugin2: указывает список подплагинов для загрузки

Определим проточный файл участвует в службе RPC, и по умолчанию не собирается генерировать код RPC, и поэтому необходимо датьpluginsпараметр, переданныйprotoc-gen-go, подскажите, пожалуйста, поддержите RPC (здесь указан gRPC)

  • --go_out=.: Установить каталог для вывода кода Go

Эта команда загрузит плагин protoc-gen-go для генерации кода Go, а сгенерированный файл будет иметь суффикс .pb.go.

  • : (двоеточие)

В качестве разделителя выступает двоеточие, за которым следует требуемый набор параметров. Если здесь не задействован RPC, команду можно упростить до:

$ protoc --go_out=. *.proto

Примечание: я предлагаю вам посмотреть на файлы .pb.go, сгенерированный двумя командами, в чем разница?

после генерации

После выполнения команды вы получите файл .pb.go со следующим содержимым:

type SearchRequest struct {
	Request              string   `protobuf:"bytes,1,opt,name=request" json:"request,omitempty"`
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

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

func (m *SearchRequest) GetRequest() string {
	if m != nil {
		return m.Request
	}
	return ""
}

Прочитав эту часть кода, вы можете узнать, что в основном задействованы следующие аспекты:

  • Преобразование имен полей из нижнего регистра подчеркивания в верхний регистр верблюжьего (экспорт поля)
  • Создайте набор методов Getters для облегчения обработки некоторых значений нулевого указателя.
  • Метод ProtoMessage реализует интерфейс proto.Message.
  • Создание методов Rest для восстановления структур Protobuf до нулевых значений
  • Повторное преобразование в фрагмент
type SearchRequest struct {
	Request              string   `protobuf:"bytes,1,opt,name=request" json:"request,omitempty"`
}

func (*SearchRequest) Descriptor() ([]byte, []int) {
	return fileDescriptor_search_8b45f79ee13ff6a3, []int{0}
}

type SearchResponse struct {
	Response             string   `protobuf:"bytes,1,opt,name=response" json:"response,omitempty"`
}

func (*SearchResponse) Descriptor() ([]byte, []int) {
	return fileDescriptor_search_8b45f79ee13ff6a3, []int{1}
}

...

func init() { proto.RegisterFile("search.proto", fileDescriptor_search_8b45f79ee13ff6a3) }

var fileDescriptor_search_8b45f79ee13ff6a3 = []byte{
	// 131 bytes of a gzipped FileDescriptorProto
	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x29, 0x4e, 0x4d, 0x2c,
	0x4a, 0xce, 0xd0, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x05, 0x53, 0x4a, 0x9a, 0x5c, 0xbc,
	0xc1, 0x60, 0xe1, 0xa0, 0xd4, 0xc2, 0xd2, 0xd4, 0xe2, 0x12, 0x21, 0x09, 0x2e, 0xf6, 0x22, 0x08,
	0x53, 0x82, 0x51, 0x81, 0x51, 0x83, 0x33, 0x08, 0xc6, 0x55, 0xd2, 0xe1, 0xe2, 0x83, 0x29, 0x2d,
	0x2e, 0xc8, 0xcf, 0x2b, 0x4e, 0x15, 0x92, 0xe2, 0xe2, 0x28, 0x82, 0xb2, 0xa1, 0x8a, 0xe1, 0x7c,
	0x23, 0x0f, 0x98, 0xc1, 0xc1, 0xa9, 0x45, 0x65, 0x99, 0xc9, 0xa9, 0x42, 0xe6, 0x5c, 0x6c, 0x10,
	0x01, 0x21, 0x11, 0x88, 0x13, 0xf4, 0x50, 0x2c, 0x96, 0x12, 0x45, 0x13, 0x85, 0x98, 0xa3, 0xc4,
	0x90, 0xc4, 0x06, 0x16, 0x37, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0xf3, 0xba, 0x74, 0x95, 0xc0,
	0x00, 0x00, 0x00,
}

Эта часть кода в основном вращается вокругfileDescriptorпродолжайте, здесьfileDescriptor_search_8b45f79ee13ff6a3Представляет скомпилированный прото-файл, и каждый метод содержит метод Descriptor, что означает, что этот метод находится вfileDescriptorКонкретное поле сообщения в

Server

В этом разделе будет написан базовый шаблон сервера gRPC для завершения вызова метода. Напишите на server.go следующее:

package main

import (
	"context"
	"log"
	"net"

	"google.golang.org/grpc"

	pb "github.com/EDDYCJY/go-grpc-example/proto"
)

type SearchService struct{}

func (s *SearchService) Search(ctx context.Context, r *pb.SearchRequest) (*pb.SearchResponse, error) {
	return &pb.SearchResponse{Response: r.GetRequest() + " Server"}, nil
}

const PORT = "9001"

func main() {
	server := grpc.NewServer()
	pb.RegisterSearchServiceServer(server, &SearchService{})

	lis, err := net.Listen("tcp", ":"+PORT)
	if err != nil {
		log.Fatalf("net.Listen err: %v", err)
	}

	server.Serve(lis)
}
  • Создайте объект сервера gRPC, вы можете понимать его как абстрактный объект на стороне сервера.
  • Зарегистрируйте SearchService (который содержит интерфейс сервера, который необходимо вызвать) во внутреннем реестре сервера gRPC. Таким образом, при получении запроса через обнаружение внутренней службы интерфейс сервера может быть обнаружен и передан для логической обработки.
  • Создать Listen, слушать на порту TCP
  • gRPC Server запускает lis.Accept до Stop или GracefulStop

Client

Затем напишите базовый шаблон gRPC Go Client, откройте файл client/client.go и напишите следующее:

package main

import (
	"context"
	"log"

	"google.golang.org/grpc"

	pb "github.com/EDDYCJY/go-grpc-example/proto"
)

const PORT = "9001"

func main() {
	conn, err := grpc.Dial(":"+PORT, grpc.WithInsecure())
	if err != nil {
		log.Fatalf("grpc.Dial err: %v", err)
	}
	defer conn.Close()

	client := pb.NewSearchServiceClient(conn)
	resp, err := client.Search(context.Background(), &pb.SearchRequest{
		Request: "gRPC",
	})
	if err != nil {
		log.Fatalf("client.Search err: %v", err)
	}

	log.Printf("resp: %s", resp.GetResponse())
}
  • Создайте взаимодействие соединения с заданной целью (сервер)
  • Создайте клиентский объект для SearchService
  • Отправьте запрос RPC, дождитесь синхронного ответа и верните ответ после получения обратного вызова.
  • вывод результата ответа

проверять

запустить сервер

$ pwd
$GOPATH/github.com/EDDYCJY/go-grpc-example
$ go run server.go

Запустить клиент

$ pwd             
$GOPATH/github.com/EDDYCJY/go-grpc-example/client
$ go run client.go 
2018/09/23 11:06:23 resp: gRPC Server

Суммировать

В этой главе мы познакомимся с Protobuf и клиентом/сервером gRPC соответственно. Надеюсь вы напишете Демо для более глубокого понимания на основе содержания в статье, оно точно будет лучше 🤔

?

Если у вас есть какие-либо вопросы или ошибки, добро пожаловать вissuesЗадавайте вопросы или вносите исправления, если вам нравится или вам помогают, добро пожаловатьStar, является своеобразным поощрением и продвижением автора.

мой публичный аккаунт

image

Ссылаться на

Пример кода для этой серии