GRPC beginnend mit Go-Server und Dart-Client

Einführung

Ich werde darüber schreiben, wie gRPC für die Kommunikation zwischen dem Go API-Server und dem Dart-Client verwendet wird (unter der Annahme von Flutter).

Entwicklung der Haniya Music Festival Osanpo App 2020 hinter den Kulissen / Server Edition DeNAs 20 neue Absolventen und 21 Absolventen Ich habe auf den Artikel der Person verwiesen, also werde ich ihn teilen.

Der Grund, warum ich gerne gRPC verwende, ist die Sitzung von Herrn Nao Minami von den Cloud Native Days Tokyo 2020 "Migration der realen Welt von HTTP zu gRPC". Es ist leicht zu verstehen, wenn Sie zuhören, also werde ich dies auch teilen. Sie können über den Link zum archivierten Video springen.

Vorbereitung

Um automatisch aus einer .proto-Datei zu generieren, müssen Sie den Befehl protoc und die Peripherie-Plug-Ins verwenden, aber ich möchte verschiedene Dinge nicht lokal installieren, also starte ich einen Docker-Container und generiere Code für jede Sprache. Sie können die neueste Version der aktuellen Protokollpuffer im GitHub-Repository (https://github.com/protocolbuffers/protobuf/releases) überprüfen.

Dockerfile



FROM golang:1.15.0

ENV DEBIAN_FRONTEND=noninteractive

ARG PROTO_VERSION=3.13.0

WORKDIR /proto

COPY ./proto .

RUN mkdir /output /output/server /output/client

RUN apt-get -qq update && apt-get -qq install -y \
  unzip

RUN curl -sSL https://github.com/protocolbuffers/protobuf/releases/download/v${PROTO_VERSION}/protoc-${PROTO_VERSION}-linux-x86_64.zip -o protoc.zip && \
  unzip -qq protoc.zip && \
  cp ./bin/protoc /usr/local/bin/protoc && \
  cp -r ./include /usr/local

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

# Dart
RUN apt-get install apt-transport-https
RUN sh -c 'curl https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -'
RUN sh -c 'curl https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list > /etc/apt/sources.list.d/dart_stable.list'
RUN apt-get update
RUN apt-get install dart -y
ENV PATH="${PATH}:/usr/lib/dart/bin/"
ENV PATH="${PATH}:/root/.pub-cache/bin"
RUN pub global activate protoc_plugin

Führen Sie das folgende Skript in diesem Container aus

protoc.sh


#!/bin/sh

set -xe

SERVER_OUTPUT_DIR=/output/server
CLIENT_OUTPUT_DIR=/output/client

protoc --version
protoc -I=/proto/protos hoge.proto fuga.proto\
  --go_out=plugins="grpc:${SERVER_OUTPUT_DIR}" \
  --dart_out="grpc:${CLIENT_OUTPUT_DIR}"

#Zeitstempel in der Protodatei.Erforderlich beim Importieren von Proto usw.
protoc -I=/proto/protos timestamp.proto wrappers.proto\
  --dart_out="grpc:${CLIENT_OUTPUT_DIR}"

Wenn Sie bei Verwendung von Docker-Compose den Befehl festlegen, protoc.sh früher auszuführen, wird der Code beim Start automatisch generiert. Synchronisieren Sie das Verzeichnis mit der Protodatei und protoc.sh mit den Volumes, dem Ausgabeverzeichnis auf der Serverseite und dem Ausgabeverzeichnis auf der Clientseite.

docker-compose.yml


version: '3.8'

services:
  proto:
    build:
      context: .
      dockerfile: docker/proto/Dockerfile
    command: ./protoc.sh
    volumes:
      - ./proto:/proto
      - ./client:/output/client
      - ./server:/output/server

Wenn Sie jedoch beispielsweise das go-Paket auf der Seite der Protodatei angeben

hoge.proto


syntax = "proto3";

package hoge.hoge;

option go_package = "hoge/fuga/foo/bar";

service Hoge{
}

In diesem Fall wird es auf der Containerseite an `` `/ output / server / hoge / fuga / foo``` ausgegeben.

Serverseite (Go)

`` `hoge.pb.go``` wird in den in docker-compose.yml angegebenen Volumes generiert. Da die Inerface-Definition von Clinet darin enthalten ist (es ist leicht zu finden, wenn Sie mit ctx in der Datei suchen), implementieren wir die Methode anhand dieses Teils.

go:hoge.pb.go


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

Erstellen Sie HogeController als Klasse, die HogeClient implementiert. Hierbei ist zu beachten, dass das Argument mit variabler Länge nach dem dritten Argument empfangen wird, es jedoch nicht erforderlich ist, Optionen in die Methode auf der Implementierungsseite zu schreiben.

hoge_controller.go


type HogeController struct{
}

func (ctrl HogeController) CreateHoge(ctx context.Context, in *CreateHogeMessage) (*CreateHogeResponse, error){
	// TODO: return *CreateHogeResponse, error
}

Registrieren Sie die oben erstellte HogeController-Instanz bei der gRPC-Serverinstanz bei RegisterHogeServer ().

main.go


func main() {
	listenPort, err := net.Listen("tcp", ":8000")
	if err != nil {
		log.Fatalln(err)
	}
	server := grpc.NewServer()

	hogeCtrl := NewHogeController()
	pb.RegisterHogeServer(server, &hogeCtrl)

	if err := server.Serve(listenPort); err != nil {
		log.Fatalf("failed to serve: %v", err)
	}
}

Client-Seite (Dart)

Der Client ist `hoge.pb.dart```,` hoge.pbgrpc.dart, `` `hoge.pbjson.dart,` `` hoge. Wenn Sie enum verwenden. pbenum.dart``` wird generiert.

Wenn Sie timestamp.dart auf der Seite der Protodatei verwenden, tritt ein Fehler im generierten Pfad auf. Ändern Sie daher einfach die Importanweisung in `hoge.pb.dart``` in` import'timestamp.pb.dart '. Sie können es verwenden, indem Sie es wie folgt ändern: $ 1; `` `. Bei unären Anrufen können Sie mit den folgenden Funktionen kommunizieren.

hoge.dart


Future<void> createHoge(dartSideParam1, dartSideParam2, dartSideParam3) async {
    final channel = ClientChannel('localhost',
        port: 8000,
        options:
            const ChannelOptions(credentials: ChannelCredentials.insecure()));
    final grpcClient = KitchenClient(channel,
        options: CallOptions(timeout: Duration(seconds: 10)));
    try {
      await grpcClient.createHoge(CreateHogerMessage()
        ..param1 = dartSideParam1
        ..param2 = dartSideParam2
        ..param3 = dartSideParam3;
      await channel.shutdown();
    } catch (error) {
      developer.log('Caught error: $error');
      await channel.shutdown();
      return Future.error(error);
    }
}

Zusammenfassung

Es war eine Möglichkeit, mit gRPC zwischen Go und Dart zu kommunizieren. In einigen Unternehmen implementieren wir die Kommunikation mit der Server-Streaming-Methode. Daher möchte ich diese Informationen zu einem späteren Zeitpunkt weitergeben.

Recommended Posts

GRPC beginnend mit Go-Server und Dart-Client
Versuchen wir es mit gRPC mit Go und Docker
GRPC beginnend mit Python
Authentifizierungsprozess mit gRPC- und Firebase-Authentifizierung
Kommunizieren Sie mit gRPC zwischen Elixir und Python
Code-Server x Dart mit ffi x Go x Clang
"Erste elastische Suche" beginnend mit einem Python-Client
Vergleichen Sie die XML-Parsing-Geschwindigkeiten mit Python und Go
Starten Sie einen Webserver mit Python und Flask
Musikwiedergabeserver mit NanoPi-NEO, MPD und OLED
Systemhandel ab Python 3: Investition und Risiko
Python mit Go
Erstellen einer verteilten Umgebung mit der Raspberry PI-Serie (Teil 4: Erstellen eines NFS-Servers und Importieren eines Client-Betriebssystems)
Deep Learning Bildanalyse beginnend mit Kaggle und Keras
Einfache Einstellungen für HTTP-Server und Systemd-Autostart in Go
Holen Sie sich swagger.json mit Flask-RESTX (Flask-RESTPlus), ohne den Server zu starten
So erstellen Sie einen HTTPS-Server mit Go / Gin
Testautomatisierung beginnend mit L-Chika (5) Embedded Web Camera und OCR
HTTP-Server und HTTP-Client mit Socket (+ Webbrowser) - Python3
Rufen Sie die C-Funktion mit dart: ffi auf und rufen Sie die Dart-Funktion zurück