欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Go中的gRPC入門教程詳解

 更新時間:2022年03月30日 12:01:49   作者:癡者工良  
本文詳細(xì)講解了Go中的gRPC入門教程,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

Go GRPC 入門

1,安裝包

grpc

golang-grpc 包提供了 gRPC 相關(guān)的代碼庫,通過這個庫我們可以創(chuàng)建 gRPC 服務(wù)或客戶端,首先需要安裝他。

go get -u google.golang.org/grpc

協(xié)議插件

要玩 gRPC,自然離不開 proto 文件,需要安裝兩個包,用于支持 protobuf 文件的處理。

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

注:GOPATH/bin 下有個 protoc-gen-go.exe 文件,然而這個只是 protoc 的插件,他本身不是 protoc 工具。。。

Protocol Buffers

Protocol Buffers 是一個與編程語言無關(guān)、與平臺無關(guān)的可拓展機制,用于序列化結(jié)構(gòu)數(shù)據(jù),是一種數(shù)據(jù)交換格式,gRPC 使用 protoc 作為協(xié)議處理工具。

學(xué)習(xí) Go 的 gRPC 時,有個坑,很多文章里面都沒有說到要安裝這個,執(zhí)行命令提示不存在 protoc 命令。

首先到 https://github.com/protocolbuffers/protobuf/releases 下載 相應(yīng)的包,例如筆者下載的是 protoc-3.15.6-win64.zip。

解壓后,復(fù)制里面的 bin\protoc.exe 文件,復(fù)制到 GOPATH\bin 命令,跟 protoc-gen-go.exe 放一起。

測試

以上都妥當(dāng)后,我們在一個新的目錄,創(chuàng)建一個 test.proto 文件,其內(nèi)容示例如下如下:

注:protoc-3.15.6-win64\include\google\protobuf 目錄也有很多示例。

syntax = "proto3";

// 包名
package  test;

// 指定輸出 go 語言的源碼到哪個目錄以及文件名稱
// 最終在 test.proto 目錄生成 test.pb.go
// 也可以只填寫 "./"
option go_package = "./;test";

// 如果要輸出其它語言的話
// option csharp_package="MyTest";

service Tester{
  rpc MyTest(Request) returns (Response){}
}

// 函數(shù)參數(shù)
message  Request{
  string  jsonStr = 1;
}

// 函數(shù)返回值
message  Response{
  string  backJson = 1;
}

然后在 proto 所在目錄,執(zhí)行命令將 proto 轉(zhuǎn)換為相應(yīng)的編程語言文件。

protoc --go_out=plugins=grpc:. *.proto

會發(fā)現(xiàn)在當(dāng)前目錄輸出了 test.pb.go 文件。

2,gRPC 服務(wù)端

創(chuàng)建一個 go 程序,把 test.pb.go 復(fù)制放到在 main.go 目錄,在 main.go 引入 grpc:

import (
	"context"
	"fmt"
	"google.golang.org/grpc"
        // test.pb.go 默認(rèn)包名是 package 為 main,不需要在這里引入
	"google.golang.org/grpc/reflection"
	"log"
	"net"
)

在 test.pb.go 中,生成了兩個個 Tester 的接口,我們來看一下這兩個接口的定義:

type TesterServer interface {
	MyTest(context.Context, *Request) (*Response, error)
}

type TesterClient interface {
	MyTest(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error)
}

要實現(xiàn) proto 中的服務(wù),則需要我們實現(xiàn) TesterServer 接口,要編寫 客戶端,則需要實現(xiàn) TesterClient 。

這里我們先實現(xiàn) Server。

// 用于實現(xiàn) Tester 服務(wù)
type MyGrpcServer struct{}

func (myserver *MyGrpcServer) MyTest(context context.Context, request *Request) (*Response, error) {
	fmt.Println("收到一個 grpc 請求,請求參數(shù):", request)
	response := Response{BackJson: `{"Code":666}`}
	return &response, nil
}

接著我們創(chuàng)建 gRPC 服務(wù)。

func main() {
	// 創(chuàng)建 Tcp 連接
	listener, err := net.Listen("tcp", ":8028")
	if err != nil {
		log.Fatalf("監(jiān)聽失敗: %v", err)
	}

	// 創(chuàng)建gRPC服務(wù)
	grpcServer := grpc.NewServer()

	// Tester 注冊服務(wù)實現(xiàn)者
	// 此函數(shù)在 test.pb.go 中,自動生成
	RegisterTesterServer(grpcServer, &MyGrpcServer{})

	// 在 gRPC 服務(wù)上注冊反射服務(wù)
	// func Register(s *grpc.Server)
	reflection.Register(grpcServer)

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

3,gRPC 客戶端

創(chuàng)建一個新的 go 項目,把 test.pb.go 復(fù)制放到 main.go 同級目錄,main.go 的代碼:

package main

import (
	"bufio"
	"context"
	"google.golang.org/grpc"
	"log"
	"os"
)

func main() {
	conn, err := grpc.Dial("127.0.0.1:8028", grpc.WithInsecure())
	if err != nil {
		log.Fatal("連接 gPRC 服務(wù)失敗,", err)
	}

	defer conn.Close()

	// 創(chuàng)建 gRPC 客戶端
	grpcClient := NewTesterClient(conn)

	// 創(chuàng)建請求參數(shù)
	request := Request{
		JsonStr: `{"Code":666}`,
	}

	reader := bufio.NewReader(os.Stdin)

	for {
		// 發(fā)送請求,調(diào)用 MyTest 接口
		response, err := grpcClient.MyTest(context.Background(), &request)
		if err != nil {
			log.Fatal("發(fā)送請求失敗,原因是:", err)
		}
		log.Println(response)

		reader.ReadLine()
	}
}

4,編譯運行

由于創(chuàng)建的時候,test.pb.go 使用的包名是 main,所以在編譯時,需要把多個 go 文件一起編譯:

go build .\main.go .\test.pb.go

然后分別啟動 server 和 client,在 client 每按下一次回車鍵,便發(fā)送一次 gRPC 消息。

gRPC請求和響應(yīng)

到這里,我們學(xué)習(xí)了一個完整的 gRPC 從創(chuàng)建協(xié)議到創(chuàng)建服務(wù)和客戶端的過程,下面將接著學(xué)習(xí)一些相關(guān)的知識,了解一些細(xì)節(jié)。

5,其它

proto.Marshal 可以對請求的參數(shù)進(jìn)行序列化,如:

	// 創(chuàng)建請求參數(shù)
	request := Request{
		JsonStr: `{"Code":666}`,
	}

	out,err:= proto.Marshal(&request)
	if err != nil {
		log.Fatalln("Failed to encode address book:", err)
	}
	if err := ioutil.WriteFile("E:/log.txt", out, 0644); err != nil {
		log.Fatalln("Failed to write address book:", err)
	}

而 proto.Unmarshal 則可以反序列化。

我們還可以自定義如何序列化反序列化消息,代碼示例:

b, err := MarshalOptions{Deterministic: true}.Marshal(m)

GRPC

Protobuf buffer

Protobuf buffer 是一種數(shù)據(jù)格式,而 Protobuf 是 gRPC 協(xié)議,這里需要區(qū)分一下。

protobuf buffer 是 Google 用于序列化結(jié)構(gòu)話數(shù)據(jù)的開源機制,要定義一個 protobuf buffer,需要使用 message 定義。

message Person {
  string name = 1;
  int32 id = 2;
  bool has_ponycopter = 3;
}

開源看到,每個字段都有一個 數(shù)字, = 1 這個不是賦值,而是編號。一個 message 中,每個字段都有唯一的編號,這些數(shù)字用于標(biāo)識二進(jìn)制格式的字段(數(shù)據(jù)傳輸時會被壓縮等),當(dāng)編號范圍是 1-15 時,存儲編號需要一個字節(jié),也就是說 message 中的字段盡量不超過 15 個,1-15 編號用來定義頻繁出現(xiàn)的消息元素。當(dāng)然,也可以使用16-2047 之間的數(shù)字作為編號,此時存儲編號需要兩個字節(jié)。

詳細(xì)的說可以參考官方文檔:

https://developers.google.com/protocol-buffers/docs/overview

字段類型

字段類型就不詳細(xì)列表了,讀者可以參考官方文檔,這里列一下常用的數(shù)據(jù)類型:

double、float、int32、int64、bool、string、bytes、枚舉。

由于 gRPC 需要考慮兼容 C 語言、C#、Java、Go 語言等,所以 gRPC 中的類型不等同于編程語言中的相關(guān)類型。這些類型都是 gRPC 中定義的,并且如果要轉(zhuǎn)換為編程語言中的類型,需要一些轉(zhuǎn)換機制,而這有時會十分麻煩。

字段規(guī)則

每個字段都可以指定一個規(guī)則,在定義字段類型的開頭使用規(guī)則標(biāo)識。

有以下三種規(guī)則:

  • required:格式正確的消息必須恰好具有此字段之一,即必填字段。
  • optional:格式正確的消息可以包含零個或一個此字段(但不能超過一個,即值是可選的。
  • repeated:在格式正確的消息中,此字段可以重復(fù)任意次(包括零次),重復(fù)值的順序?qū)⒈A?,表示該字段可以包?~N個元素。

由于歷史原因,repeated標(biāo)量數(shù)字類型的字段編碼效率不高。新代碼應(yīng)使用特殊選項[packed=true]來獲得更有效的編碼。例如:

repeated int32 samples = 4 [packed=true];

在可選字段中 optional 中,我們可以為其設(shè)置一個默認(rèn)值,當(dāng)傳遞消息時如果沒有填寫此字段,則使用其默認(rèn)值:

optional int32 result_per_page = 3 [default = 10];

Protobuf

接下來將介紹 gRPC 的協(xié)議格式(protobuf),下面是官方文檔的一個示例:

syntax = "proto3";
package tutorial;

import "google/protobuf/timestamp.proto";

syntax 指明協(xié)議的版本;

package 指明該 .proto 的名稱;

import 關(guān)鍵字可以在當(dāng)前 .proto 中引入其它 .proto 文件,gRPC 基本數(shù)據(jù)類型中不包含時間格式,可以引入 timestamp.proto。

不同編程語言引入包/庫的方式是不同的,C++ 和 C# 都是使用命名空間區(qū)分代碼位置;Java 以目錄、公共類嚴(yán)格區(qū)別包名;go 則是以一個 .go 文件任意設(shè)置 package 名稱。

前面提到了 protoc,可以將協(xié)議文件轉(zhuǎn)為為具體的代碼。

為了兼容各種編程語言,我們協(xié)議設(shè)置 _package,這樣可以支持生成不同語言代碼時設(shè)置包/庫名稱。

例如 :

option go_package = "Test";					// ...
option csharp_package = "MyGrpc.Protos";	// 生成命名空間 namespace MyGrpc.Protos{}
option java_paclage = "MyJava.Protos";		// ...

gRPC 四種服務(wù)方法

protobuf 中除了可以定義 message,也可以定義流式接口。

gRPC使您可以定義四種服務(wù)方法:

  • 一元 RPC,客戶端向服務(wù)器發(fā)送單個請求并獲得單個響應(yīng),就像普通的函數(shù)調(diào)用一樣。前面我們提到的都是一元 gRPC。

    rpc SayHello(HelloRequest) returns (HelloResponse);
  • 服務(wù)器流式RPC,客戶端在其中向服務(wù)器發(fā)送請求,并獲取流以讀取回一系列消息??蛻舳藦姆祷氐牧髦凶x取,直到?jīng)]有更多消息為止。gRPC保證在單個RPC調(diào)用中對消息進(jìn)行排序。

    客戶端 -> 服務(wù)端 -> 返回流 -> 客戶端 -> 接收流

    rpc LotsOfReplies(HelloRequest) returns (stream HelloResponse);
  • 客戶端流式RPC,客戶端在其中編寫消息序列,然后再次使用提供的流將其發(fā)送到服務(wù)器。客戶端寫完消息后,它將等待服務(wù)器讀取消息并返回其響應(yīng)。gRPC再次保證了在單個RPC調(diào)用中的消息順序。

    客戶端 -> 發(fā)送流 -> 服務(wù)端 -> 接收流 ->

    rpc LotsOfGreetings(stream HelloRequest) returns (HelloResponse);
  • 雙向流式RPC,雙方都使用讀寫流發(fā)送一系列消息。這兩個流獨立運行,因此客戶端和服務(wù)器可以按照自己喜歡的順序進(jìn)行讀寫:例如,服務(wù)器可以在寫響應(yīng)之前等待接收所有客戶端消息,或者可以先讀取消息再寫入消息,或讀寫的其他組合。每個流中的消息順序都會保留。

    rpc BidiHello(stream HelloRequest) returns (stream HelloResponse);

編譯 proto

前面我們用 protoc 來編譯 .proto 文件為 go 語言,為了支持編譯為 go,需要安裝 protoc-gen-go 插件,C# 可以安裝 protoc-gen-zsharp 插件。

需要注意的是,轉(zhuǎn)換 .proto 為編程語言,不一定要安裝 protoc。

例如 C# 只需要把 .proto 文件放到項目中,通過包管理器安裝一個庫,就會自動轉(zhuǎn)換為相應(yīng)的代碼。

回歸正題,聊一下 protoc 編譯 .proto 文件的命令。

protoc 常用的參數(shù)如下:

 --proto_path=.		#指定proto文件的路徑,填寫 . 表示就在當(dāng)前目錄下
 --go_out=.			#表示編譯后的文件存放路徑;如果編譯的是 csharp,則 --csharp_out
 --go_opt={xxx.proto}={xxx.proto的路徑}	
 # 示例:--go_opt=Mprotos/bar.proto=example.com/project/protos/foo

最簡單的編譯命令:

protoc --go_out=.  *.proto

--{xxx}_out 指令是必須的,因為要輸出具體的編程語言代碼。

這個輸出文件的路徑是執(zhí)行命令的路徑,如果我們不在 .proto 文件目錄下執(zhí)行命令,則輸出的代碼便不是相同位置了。為了解決這個問題,我們可以使用:

--go_opt=paths=source_relative

這樣在別的地方執(zhí)行命令,生成的代碼會跟 .proto 文件放在相同的位置。

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Go語言快速入門指針Map使用示例教程

    Go語言快速入門指針Map使用示例教程

    這篇文章主要為大家介紹了Go語言快速入門指針Map示例教程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • Go中sync?包Cond使用場景分析

    Go中sync?包Cond使用場景分析

    Cond?是和某個條件相關(guān),在條件還沒有滿足的時候,所有等待這個條件的協(xié)程都會被阻塞住,只有這個條件滿足的時候,等待的協(xié)程才可能繼續(xù)進(jìn)行下去,這篇文章主要介紹了Go中sync?包的Cond使用場景分析,需要的朋友可以參考下
    2023-03-03
  • 一篇文章搞懂Go語言中的Context

    一篇文章搞懂Go語言中的Context

    這篇文章主要介紹了一篇文章搞懂Go語言中的Context,Context攜帶一個截止日期、一個取消信號和其他跨越API邊界的值。上下文的方法可以被多個gor例程同時調(diào)用
    2022-07-07
  • Golang import本地包和導(dǎo)入問題相關(guān)詳解

    Golang import本地包和導(dǎo)入問題相關(guān)詳解

    這篇文章主要介紹了Golang import本地包和導(dǎo)入問題相關(guān)詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-02-02
  • go 原生http web 服務(wù)跨域restful api的寫法介紹

    go 原生http web 服務(wù)跨域restful api的寫法介紹

    這篇文章主要介紹了go 原生http web 服務(wù)跨域restful api的寫法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04
  • Go語言入門exec的基本使用示例

    Go語言入門exec的基本使用示例

    這篇文章主要為大家介紹了Go語言入門exec在go語言中的基本使用示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-05-05
  • 一文帶你了解Go語言中的指針和結(jié)構(gòu)體

    一文帶你了解Go語言中的指針和結(jié)構(gòu)體

    前面的兩篇文章對?Go?語言的基礎(chǔ)語法和基本數(shù)據(jù)類型以及幾個復(fù)合數(shù)據(jù)類型進(jìn)行介紹,本文將對?Go?里面的指針和結(jié)構(gòu)體進(jìn)行介紹,也為后續(xù)文章做鋪墊,感興趣的可以了解一下
    2022-11-11
  • Golang定時器Timer與Ticker的使用詳解

    Golang定時器Timer與Ticker的使用詳解

    在 Go 里有很多種定時器的使用方法,像常規(guī)的 Timer、Ticker 對象,本文主要為大家介紹了Timer與Ticker的使用,感興趣的小伙伴可以了解一下
    2023-05-05
  • 詳解Go語言中的內(nèi)存對齊

    詳解Go語言中的內(nèi)存對齊

    前面我們學(xué)習(xí)了Go語言空結(jié)構(gòu)體詳解,最近又在看unsafe包的知識,在查閱相關(guān)資料時不免會看到內(nèi)存對齊相關(guān)的內(nèi)容。雖然不會,但可以學(xué)呀,那么這篇文章,我們就一起來看下什么是內(nèi)存對齊吧
    2022-10-10
  • Go語言對JSON進(jìn)行編碼和解碼的方法

    Go語言對JSON進(jìn)行編碼和解碼的方法

    這篇文章主要介紹了Go語言對JSON進(jìn)行編碼和解碼的方法,涉及Go語言操作json的技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-02-02

最新評論