[gRPC實現go調用go]

1什么是RPC

RPC:Remote Procedure Call,遠程過程調用。簡單來說就是兩個進程之間的數據交互。正常服務端的接口服務是提供給用戶端(在Web開發中就是瀏覽器)或者自身調用的,也就是本地過程調用。和本地過程調用相對的就是:假如兩個服務端不在一個進程內怎么進行數據交互?使用RPC。尤其是現在微服務的大量實踐,服務與服務之間的調用不可避免,RPC更顯得尤為重要

在這里插入圖片描述

上圖描述了一個RPC的完整調用流程:
1:client向client stub發起方法調用請求。
2:client stub接收到請求后,將方法名,請求參數等信息進行編碼序列化。
3:client stub通過配置的ip和端口使用socket通過網絡向遠程服務器server發起請求。
4:遠程服務器server接收到請求,解碼反序列化請求信息。
5:server將請求信息交給server stub,server stub找到對應的本地真實方法實現。
6:本地方法處理調用請求并將返回的數據交給server stub。
7:server stub 將數據編碼序列化交給操作系統內核,使用socket將數據返回。
8:client端socket接收到遠程服務器的返回信息。
9:client stub將信息進行解碼反序列化。
10:client收到遠程服務器返回的信息。

上圖中有一個stub(存根)的概念。stub負責接收本地方法調用,并將它們委托給各自的具體實現對象。server端stub又被稱為skeleton(骨架)。可以理解為代理類。而實際上基于Java的RPC框架stub基本上也都是使用動態代理。我們所說的client端和server端在RPC中一般也都是相對的概念。
而所謂的RPC框架也就是封裝了上述流程中2-9的過程,讓開發者調用遠程方法就像調用本地方法一樣。

2. gRPC的原理

gRPC是Google的開源產品,是跨語言的通用型RPC框架,使用Go語言編寫。 Java語言的應用同樣使用了Netty做網絡通信,Go采用了Goroutine做網絡通信。序列化方式采用了Google自己開源的Protobuf。請求的調用和返回使用HTTP2的Stream。

一個RPC框架必須有兩個基礎的組成部分:數據的序列化和進程數據通信的交互方式。

對于序列化gRPC采用了自家公司開源的Protobuf。Google Protocol Buffer(簡稱 Protobuf)是一種輕便高效的結構化數據存儲格式,平臺無關、語言無關、可擴展,可用于通訊協議和數據存儲等領域。似乎和我們熟悉的JSON類似,但其實著重點有些本質的區別。JSON主要是用于數據的傳輸,因為它輕量級,可讀性好,解析簡單。Protobuf主要是用于跨語言的IDL,它除了和JSON、XML一樣能定義結構體之外,還可以使用自描述格式定于出接口的特性,并可以使用針對不同語言的protocol編譯器產生不同語言的stub類。所以天然的適用于跨語言的RPC框架中(非常重要)

而關于進程間的通訊,無疑是Socket。Java方面gRPC同樣使用了成熟的開源框架Netty。使用Netty Channel作為數據通道。傳輸協議使用了HTTP2。
通過以上的分析,我們可以將一個完整的gRPC流程總結為以下幾步:

● 通過.proto文件定義傳輸的接口和消息體。
● 通過protocol編譯器生成server端和client端的stub程序。
● 將請求封裝成HTTP2的Stream。
● 通過Channel作為數據通信通道使用Socket進行數據傳輸。

3 實踐開始

下面我們使用代碼基于以上的步驟來實現一個簡單gRPC。我們用Go實現server端,Java作為client端來實現。

3.1 安裝Protocol Buffers,定義.proto文件

下載Protocol Buffers:https://github.com/protocolbuffers/protobuf/releases
檢查安裝

protoc --version

定義一個simple.proto,這也是后續實現gRPC的基礎:

syntax = "proto3"; //定義了我們使用的Protocol Buffers版本。option go_package = "./;simple";//***在java端請注釋本行***//表明我們定義了一個命名為Simple的服務(接口),內部有一個遠程rpc方法,名字為SayHello。//我們只要在server端實現這個接口,在實現類中書寫我們的業務代碼。在client端調用這個接口。service Simple{rpc SayHello(HelloRequest) returns (HelloReplay){}}//請求的結構體message HelloRequest{string name = 1;}//返回的結構體message HelloReplay{string message = 1;}

3.2 在Go端實現server

根據官方文檔使用如下命令安裝針對Go的gRPC:

go get -u google.golang.org/grpc

建立Go的project:go-server-grpc,然后將前面寫的simple.proto放入項目proto的package中。
cd到proto目錄執行如下命令:

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

這樣就將simple.proto編譯成了Go語言對應的stub程序了。
在這里插入圖片描述

隨后我們就可以寫我們server端的代碼了:main.go。
以下的代碼都是模板代碼,main函數是socket使用Go的標準實現。作為開發者我們只關注遠程服務提供的具體接口實現即可。
我們可以在生成的simple.pb.go中發現需要實現的接口:

// 客戶端調用的接口
type SimpleClient interface {SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReplay, error)
}type simpleClient struct {cc grpc.ClientConnInterface
}func NewSimpleClient(cc grpc.ClientConnInterface) SimpleClient {return &simpleClient{cc}
}func (c *simpleClient) SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReplay, error) {out := new(HelloReplay)err := c.cc.Invoke(ctx, "/Simple/SayHello", in, out, opts...)if err != nil {return nil, err}return out, nil
}// 服務端需要實現的接口
type SimpleServer interface {SayHello(context.Context, *HelloRequest) (*HelloReplay, error)
}

之后我們在main.go中實現接口:

package mainimport ("context""grpc-server/proto"//引入對應的包"fmt""net""log""google.golang.org/grpc""google.golang.org/grpc/reflection"
)
//定義接下來要開放的socket的端口
const(port = ":50051"
)type server struct{}func (s *server) SayHello(ctx context.Context,req *simple.HelloRequest) (*simple.HelloReplay, error){fmt.Println(req.Name)return &simple.HelloReplay{Message:"hello =======> " + req.Name},nil
}

之后填寫main方法:

func main() {//創建一個socket監聽lis, err := net.Listen("tcp", port)if err != nil {log.Fatal("fail to listen")}//新建一個grpc服務器s := grpc.NewServer()//使用 simple.RegisterSimpleServer 函數將實現了 SimpleServer 接口的 server 對象注冊到 gRPC 服務器(s)上simple.RegisterSimpleServer(s, &server{})//使用 reflection.Register 函數將 gRPC 服務器(s)注冊到反射服務中。這樣,可以通過 gRPC 提供的工具來動態地查看和調用服務器上的服務。reflection.Register(s)//使用 s.Serve 方法啟動 gRPC 服務器(s),開始接受來自客戶端的連接請求并提供服務。如果啟動過程中出現錯誤,程序會輸出一條錯誤信息并終止運行。if err := s.Serve(lis); err != nil {log.Fatal("fail to server")}
}

目前服務端已經完成了。

3.3 在Go端實現client

package mainimport ("context""fmt"simple "go-server-grpc/proto""log""google.golang.org/grpc"
)const (address = "localhost:50051"
)func main() {// 創建與服務器的連接conn, err := grpc.Dial(address, grpc.WithInsecure())if err != nil {log.Fatalf("無法連接到服務器:%v", err)}defer conn.Close()// 創建一個新的 gRPC 客戶端client := simple.NewSimpleClient(conn)// 構建請求request := &simple.HelloRequest{Name: "John",}// 調用 gRPC 方法response, err := client.SayHello(context.Background(), request)if err != nil {log.Fatalf("調用 gRPC 方法失敗:%v", err)}// 打印響應fmt.Println(response.Message)
}

需要先啟動服務端,再啟動客戶端就可以看到效果。
輸出:hello=======>John

4.下次預告

實現Java作為客戶端調用go服務端的服務

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/212045.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/212045.shtml
英文地址,請注明出處:http://en.pswp.cn/news/212045.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

深度優先遍歷(DFS)

時間復雜度與深搜一致;

STM32 定時器總結

縮寫 ARR: Auto-Reload Register(保存定時器的計數范圍) PSC: Prescaler register(預分頻器寄存器,根據設置的分頻因子N,計數N個定時器時鐘脈沖后,產生一個CNT計數,以此實現分頻功能&#xff0…

LeetCode 2048. 下一個更大的數值平衡數

一、題目 1、題目描述 如果整數 x 滿足&#xff1a;對于每個數位 d &#xff0c;這個數位 恰好 在 x 中出現 d 次。那么整數 x 就是一個 數值平衡數 。 給你一個整數 n &#xff0c;請你返回 嚴格大于 n 的 最小數值平衡數。 0 < n < 1e6 2、接口描述 public:int nextB…

Android渲染-AHardwareBuffer

本文主要從應用的角度介紹android的native層AHardwareBuffer創建紋理以及保存渲染數據。 HardwareBuffer 要介紹native層的AHardwareBuffer&#xff0c;就需要先從Java層的HardwareBuffer說起。Android官方對于HardwareBuffer介紹如下&#xff1a; HardwareBuffer wraps a na…

HttpURLConnection OOM問題記錄

使用HttpURLConnection 上傳大文件&#xff0c;會出現內存溢出問題&#xff1a; 觀察HttpURLConnection 源碼&#xff1a; Overridepublic synchronized OutputStream getOutputStream() throws IOException {connecting true;SocketPermission p URLtoSocketPermission(th…

【接口分享】熱門好用的API,含免費次數

語音驗證碼短信&#xff1a;撥打電話告知用戶驗證碼&#xff0c;實現信息驗證。短信驗證碼&#xff1a;可用于登錄、注冊、找回密碼、支付認證等等應用場景。支持三大運營商&#xff0c;3秒可達&#xff0c;99.99&#xff05;到達率&#xff0c;支持大容量高并發。通知短信&…

基于SSM的點餐系統的設計與實現

末尾獲取源碼 開發語言&#xff1a;Java Java開發工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;Vue 數據庫&#xff1a;MySQL5.7和Navicat管理工具結合 服務器&#xff1a;Tomcat8.5 開發軟件&#xff1a;IDEA / Eclipse 是否Maven項目&#xff1a;是 目錄…

mysql設置為密碼登錄

要設置Ubuntu上的MySQL需要密碼登錄&#xff0c;你可以使用以下步驟&#xff1a; 打開終端。 輸入以下命令登錄到 MySQL 服務器&#xff1a; sudo mysql -u root -p按Enter后&#xff0c;系統會要求輸入密碼。如果是第一次登錄&#xff0c;你可能需要直接按Enter鍵&#xff08…

【已解決】解決UbuntuKali無法進行SSH遠程連接

目錄 Ubuntu20.04配置SSH遠程連接Kali Linux配置SSH遠程連接 Ubuntu20.04配置SSH遠程連接 首先更新安裝包 sudo apt-get update 下載SSH服務 sudo apt install openssh-server 查看SSH服務 service ssh status 打開 /etc/ssh/sshd_config文件修改配置文件 將PermitRootLog…

知識筆記(五十二)———MySQL 刪除數據表

MySQL中刪除數據表是非常容易操作的&#xff0c;但是你在進行刪除表操作時要非常小心&#xff0c;因為執行刪除命令后所有數據都會消失。 語法 以下為刪除 MySQL 數據表的通用語法&#xff1a; DROP TABLE table_name ; -- 直接刪除表&#xff0c;不檢查是否存在 或 DROP…

基于Debain安裝 Docker 和 Docker Compose

一、安裝Docker # 先升級一下系統 (Ubuntu / Debian 系) sudo apt-get update sudo apt-get upgrade# 如果你是 CentOS、紅帽系列則使用&#xff1a; yum update yum upgrade# 安裝 Docker curl -fsSL https://get.docker.com -o get-docker.sh sudo sh get-docker.sh二、Dock…

LeetCode 0070. 爬樓梯:動態規劃(遞推)

【LetMeFly】70.爬樓梯&#xff1a;動態規劃&#xff08;遞推&#xff09; 力扣題目鏈接&#xff1a;https://leetcode.cn/problems/climbing-stairs/ 假設你正在爬樓梯。需要 n 階你才能到達樓頂。 每次你可以爬 1 或 2 個臺階。你有多少種不同的方法可以爬到樓頂呢&#x…

NVIDIA Jetson NX ubuntu20.04刪除多余版本沖突的Boost庫

參考Ubuntu16.04 卸載舊版本Boost庫并安裝新版本 卸載 刪除/usr/local/include/boost文件夾&#xff0c;刪除/usr/local/lib中和boost有關的文件,以及/usr/local/lib/cmake/中boost的cmake文件 cd /usr/local/lib/ ls | grep boost sudo rm -rf /usr/local/include/boost su…

藍橋杯 day01 奇怪的數列 特殊日期

奇怪的數列 題目描述 奇怪的數列 從 X 星截獲一份電碼&#xff0c;是一些數字&#xff0c;如下&#xff1a; 13 1113 3113 132113 1113122113 ?? YY 博士經徹夜研究&#xff0c;發現了規律&#xff1a; 第一行的數字隨便是什么&#xff0c;以后每一行都是對上一行…

redis+springsecurity+mybtais-plus+JWT

redisspringsecuritymybtais-plusJWT 01 引入依賴 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>com.mysql</groupId&g…

12.視圖

目錄 1.視圖的含義與作用 2.視圖的創建與查看 1.創建視圖的語法形式 2、查看視圖&#xff1a; 1.使用DESCRIBE語句查看視圖基本信息 2.使用SHOW TABLE STATUS語查看視圖基本信息查看視圖的信息 3.使用SHOW CREATE VIEW語查看視圖詳細信息 4.在views表中查看視圖詳細信息…

【DP】Yarik and Array—CF1899C

Yarik and Array—CF1899C 一道不難的DP&#xff0c;根據代碼就能看出思路。 C o d e Code Code #include <bits/stdc.h> #define int long long #define sz(a) ((int)a.size()) #define all(a) a.begin(), a.end() using namespace std; using PII pair<int, int&…

codeforces

分析 刪去 k k k 個之后要是回文串&#xff0c;不過題目會給字符串rearrange&#xff0c;所以對于奇數個數的字符最多留一個&#xff0c;偶數的不用管。 Think Twice, Code Once #include<bits/stdc.h> #define il inline #define get getchar #define put putchar #…

SAP-PP:PP模塊新手顧問入門尋找解決方案途徑

在學習PP模塊時我們可以參考一下部分資源: SAP Help SAP Help SAP 幫助門戶是了解任何功能基礎知識的起點。在這里&#xff0c;您將了解每個功能可以做什么&#xff0c;以及如何使用每個功能的一些基本示例 F1 Help 每個事務中的每個字段都有自己的文檔&#xff0c;您可以通過…

案例015:基于微信小程序的校園防疫系統

文末獲取源碼 開發語言&#xff1a;Java 框架&#xff1a;SSM JDK版本&#xff1a;JDK1.8 數據庫&#xff1a;mysql 5.7 開發軟件&#xff1a;eclipse/myeclipse/idea Maven包&#xff1a;Maven3.5.4 小程序框架&#xff1a;uniapp 小程序開發軟件&#xff1a;HBuilder X 小程序…