開始食用grpc(之一)

来源:https://www.cnblogs.com/funnyzpc/archive/2018/08/26/9501353.html
-Advertisement-
Play Games

開始食用grpc(之一) 轉載請註明出處:https://www.cnblogs.com/funnyzpc/p/9501353.html ``` 記一次和一鍋們壓馬路,路過一咖啡廳(某巴克),隨口就問隨行的鍋門:你能從那咖啡廳看到什麼? 當時的那家某巴克處於鬧市,也正值周末,屋外屋內喝咖啡的人幾近乎 ...


開始食用grpc(之一)

轉載請註明出處:https://www.cnblogs.com/funnyzpc/p/9501353.html

 

```

   記一次和一鍋們壓馬路,路過一咖啡廳(某巴克),隨口就問隨行的鍋門:你能從那咖啡廳看到什麼?

     當時的那家某巴克處於鬧市,也正值周末,屋外屋內喝咖啡的人幾近乎十分的安靜,使用電腦的,刷手機的、做作業的。。。而且大都是年輕人和中年人。

   鍋門撂了句:一群屌絲唄 (;¬_¬) 

  。。。白了他一眼(¬_¬)

     ( ...其實想教唆他進去看看美女,歇歇腳來著 ๑乛◡乛๑ )

  .......

     許久之後,也就是最近看到詩人餘秀華的一句話後忽有所感,原句是:

    “反正是背負慢慢凋殘的孤獨,耀眼的孤獨,義無反顧的孤獨

  這才明白他們是在消費孤獨,也為孤獨所消費; 他們是,周圍的人是,還有 ( ∙̆ .̯ ∙̆ )

  那~ 孤獨的結果是什麼呢 ?

```

  這次講下大系統通訊必備的一項組件:rpc,rpc有很多 如 dubbo、thirft、feign、motan、grpc 等~,這其中有字元串方式的也有二進位流方式的;整體來說二進位方式的一般會較字元串方式的快許多,字元形式的的慢,但是簡單;而二進位方式的 序列化和跨平臺較為麻煩些;我個人選取rpc時一般綜合考慮一下幾點:

  A>傳輸方式是否是二進位

  B>是否長期支持

  C>是否支持跨平臺,開源組件是否豐富

  C+>是否支持非同步調用

  D>有無明顯的bug或缺點

  E>維護和開發是否有好

    綜合下來,個人堅定之選擇grpc,這個初出茅廬(2015年發佈)的東東,十分強大:

      >> http2流方式

  >> 自帶非同步特性

  >> 跨平臺(支持11種語言)

  >> 無需zookeeper這類單獨的服務中心

  >> 對開發人員比較友好

      >> 服務調用方可設置請求頭

當然缺點也是存在的:需要單獨寫proto文件(生成目標語言的一套語法定義)、變數為null時會賦予預設初始值、鏈式調用(還好調用介面較為單一,只是語法較為怪異)...

  如果您在意以上缺點,可繞過本文哈~

      ok,現在開始我開始講grpc,內容大致有四:

    A->grpc的簡單配置 (本節)

    A>簡單grpc編寫 (本節)

    B>複雜grpc proto服務文件編寫 (本節)

    C>雙向流式調用方法及註意事項 (之二)

    D>grpc安全問題及攔截器 (之二)

 

grpc的配置:

       這裡我的工程是基於springboot,同時為簡化開發起見,我使用 grpc-spring-boot-starter ,開始之前先感謝這位開發者為簡化grpc的java平臺簡化了太多的開發,同時也為springcloud融合做了太多共用,非常感謝~! 

   這裡,首先得準備三個springboot模塊,這三個模塊包含:grpc proto3文件生成模塊、grpc 客戶端、grpc 服務端,我的工程結構大致是這樣子的(工程是多模塊的):

這裡面的三個模塊一看就懂,就不細講啦~,準備好這三個模塊後,依次配置依賴包及參數:

服務端(preview-grpc-server):

  pom.xml中依賴包配置>

        <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-autoconfigure</artifactId>
         </dependency>
         <dependency>
             <groupId>net.devh</groupId>
             <artifactId>grpc-client-spring-boot-autoconfigure</artifactId>
             <version>RELEASE</version>
         </dependency>
    <!-- 由於我的工程是多模塊的,若不作為jar包引入,也可以將preview-grpc-lib中的java文件拷貝到當前工程內也可 -->
     <dependency>
     <groupId>com.github.carvechris</groupId>
     <artifactId>preview-grpc-lib</artifactId>
     <version>1.0-SNAPSHOT</version>
     </dependency>
 

  配置文件yml(如果是properties文件也可參照此配置)

1 grpc:
2   server:
3     port: 2804
4 
5 spring:
6     application:
7         name: preview-grpc-server

 

(註意:一定要定義應用名稱,在調用的時候會用到應用名稱的,這裡是:preview-grpc-server)

 客戶端(preview-grpc-client):

  pom.xml文件依賴包配置>

<dependency>
        <groupId>net.devh</groupId>
        <artifactId>grpc-client-spring-boot-starter</artifactId>
        <version>1.4.0.RELEASE</version>
</dependency>

<!-- 由於我的工程是多模塊的,若不作為jar包引入,也可以將preview-grpc-lib中的java文件拷貝到當前工程內也可 -->
<dependency>
 <groupId>com.github.carvechris</groupId>
 <artifactId>preview-grpc-lib</artifactId>
 <version>1.0-SNAPSHOT</version>
</dependency>
 

 

  yml配置文件參數:

1 grpc:
2   client:
3     preview-grpc-server:
4       host:
5         - 127.0.0.1
6       port:
7         - 2804
8       enableKeepAlive: true
9       keepAliveWithoutCalls: true

 

proto文件生成模塊(preview-grpc-lib)配置:

  pom.xml文件依賴包配置:

 1 <!--依賴配置-->
 2 <dependencies>
 3         <dependency>
 4             <groupId>io.grpc</groupId>
 5             <artifactId>grpc-netty</artifactId>
 6             <version>${grpc.version}</version>
 7         </dependency>
 8         <dependency>
 9             <groupId>io.grpc</groupId>
10             <artifactId>grpc-protobuf</artifactId>
11             <version>${grpc.version}</version>
12         </dependency>
13         <dependency>
14             <groupId>io.grpc</groupId>
15             <artifactId>grpc-stub</artifactId>
16             <version>${grpc.version}</version>
17         </dependency>
18  </dependencies>
19 
20 <!--proto3文件生成java代碼插件配置-->
21     <build>
22         <extensions>
23             <extension>
24                 <groupId>kr.motd.maven</groupId>
25                 <artifactId>os-maven-plugin</artifactId>
26                 <version>${os.plugin.version}</version>
27             </extension>
28         </extensions>
29         <plugins>
30             <plugin>
31                 <groupId>org.xolstice.maven.plugins</groupId>
32                 <artifactId>protobuf-maven-plugin</artifactId>
33                 <version>${protobuf.plugin.version}</version>
34                 <configuration>
35                     <protocArtifact>com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier}</protocArtifact>
36                     <pluginId>grpc-java</pluginId>
37                     <pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}</pluginArtifact>
38                 </configuration>
39             </plugin>
40         </plugins>
41     </build>

 

  配置完成,這裡需要特別說明一下:server模塊和client模塊的web服務各占一個埠,另外,server模塊還會給grpc單獨分配一個埠,就我的preview-grpc-server來說:

    服務名稱(name)是:preview-grpc-server

    服務占用的埠是:2804

  切記,不論是web服務還是grpc服務的埠都不能重覆,同時一定要理清楚web服務和grpc服務所占用的埠和ip

 

簡單grpc服務(helloworld.proto)編寫

  這裡我先展示下我的生成模塊的大致樣子

 

  需要說明的是:編寫的proto文件均在proto目錄下java目錄下是proto文件生成的java代碼,這裡的java文件是從target目錄總複製到java目錄下的,包名一定要與proto裡面聲明的包名一致!

  java代碼生成模塊proto3服務文件(helloworld.proto)的編寫

 1 syntax = "proto3";
 2 
 3 // 是否拆分類文件
 4 option java_multiple_files = true;
 5 // 生成的文件所在的包
 6 option java_package = "com.funnyzpc.xxx.grpc.lib.hello";
 7 //  輸出類主文件(此配置可選)
 8 option java_outer_classname = "HelloWorldProto";
 9 
10 // 定義一個服務
11 service Simple {
12     // Sends a greeting
13     rpc SayHello (HelloRequest) returns (HelloReply) {
14     }
15 }
16 
17 // 請求體定義
18 message HelloRequest {
19     string name = 1;
20 }
21 
22 // 響應體定義
23 message HelloReply {
24     string message = 1;
25 }

  現在開始使用idea提供的快捷功能生成客戶端和服務端java文件(當然也可以使用mvn命令手動生成)

  將生成的java文件複製到應用目錄

  (註意:複製後一定要清理target目錄,不然文件重覆會報錯!)

  在客戶端(preview-grpc-client)編寫一個grpc服務請求類(GrpcSimpleService.java):

 1 @Service
 2 public class GrpcSimpleService {
 3 
 4     @GrpcClient("preview-grpc-server")
 5     private Channel serverChannel;
 6 
 7     public String sendMessage(String name) {
 8         SimpleGrpc.SimpleBlockingStub stub = SimpleGrpc.newBlockingStub(serverChannel);
 9         HelloReply response = stub.sayHello(HelloRequest.newBuilder().setName(name).build());
10         return response.getMessage();
11     }
12 }

  在服務端(preview-grpc-server)編寫對應的grpc的服務類:

 1 /**
 2  * 簡單grpc服務類
 3  */
 4 @GrpcService(SimpleGrpc.class)
 5 public class GrpcServerService extends SimpleGrpc.SimpleImplBase {
 6     private  static final Logger LOG=LoggerFactory.getLogger(GrpcServerService.class);
 7 
 8    @Override
 9     public void sayHello(HelloRequest req, StreamObserver<HelloReply> responseObserver) {
10         HelloReply reply = HelloReply.newBuilder().setMessage("Hello ===> " + req.getName()).build();
11         responseObserver.onNext(reply);
12         responseObserver.onCompleted();
13     }
14 
15 }

  上面的@GrpcService是grpc組件的註解,註解中必須聲明所使用的grpc(生成的類中的)服務類,同時還可以聲明所使用的攔截器(可選) 

 OK,現在添加一個控制器(在preview-grpc-client中編寫一個控制器),試試看

  完美,。。。可能有人proto文件一知半解,接下來進入下一節。

 

複雜grpc proto服務文件編寫:

   首先,我先推薦兩個官方網站,若能理解官網內容,可繞過本節

     grpc java平臺api及樣例>

      https://grpc.io/docs/quickstart/java.html

         protocol buffers,proto3文件語法>

      https://developers.google.com/protocol-buffers/docs/proto3?hl=zh-cn

  一般在跨應用調用時,所傳遞的參數有時候為複雜對象,比如這樣{page_no:1,page_size:20,data:{name:XXX,type:2}},這裡就寫好的複雜層級對象講解下

(MultiObject.proto)

 1 syntax = "proto3";
 2 
 3 // option java_multiple_files = true;
 4 option java_package = "com.github.carvechris.security.grpc.lib.multi";
 5 
 6 service MultiObjService{
 7     rpc queryObj (MultiObjReq) returns (MultiObjResp) {
 8 
 9     }
10 
11 }
12 
13 message MultiObjReq{
14     int32 page_no=1;
15     int32 page_size=2;
16     MultiObjDataReq data=3;
17 }
18 
19 message MultiObjDataReq{
20     string name=1;
21     int32 type=2;
22 }
23 
24 message MultiObjResp{
25     string req_str=1;
26     MultiObjFirstResp first=2;
27 }
28 message MultiObjFirstResp{
29     string f_content=1;
30     MultiObjNextResp next=2;
31 
32 }
33 message MultiObjNextResp{
34     string n_content =1;
35 }

文件中定義一個服務 必須以關鍵字 service 開始,上面的 MultiObjReq 與 MultiObjResp 分別為服務的請求和響應對象,這兩個對象在生成java文件後,每個請求對象都是一個單獨的類(可在一個java中也可不在,若不在需要定義:option java_multiple_files = true;),不管是請求對象還是響應對象,都需要單獨聲明這個對象以及對象中的變數類型及所處的位置,就像這樣

1 message MultiObjReq{
2     int32 page_no=1;
3     int32 page_size=2;
4     MultiObjDataReq data=3;
5 }

自定義類型需要在單獨定義,比如"MultiObjDataReq";在上面這個例子中,定義的請求對象MultiObjReq的第一個欄位為 page_no,第一個為page_size,第三個為定義的一個對象,每個參數開始需標明當前欄位類型,如果這個欄位是自定義類型時無需定義數據類型(但是一定要有參數序號,當然也可以定義一個map類型);另外,通用欄位類型同go語言的數據類型(參照以上鏈接);註意,請求或響應對象定義時必須以關鍵字message開始。

另外,請註意,如果某個欄位是個列表(java中的List),需要在欄位或者對象前添加關鍵字 repeated ,這樣:

//返回體數據定義
message GrpcResp {

    string sign=3;

    string msg=4;

    repeated datas detail=5;
}

message datas{

    uint64 id=1;

    string address=2;

    double isadmin=3;
}

  現在展示上面的MultiObject.proto文件 所編寫的客戶端和服務端類:

  客戶端(preview-grpc-client):

  (GrpcMultiObjClientService.java)

 1 @Service
 2 public class GrpcMultiObjClientService {
 3 
 4     @GrpcClient("preview-grpc-service")
 5     private Channel serverChannel;
 6 
 7     public  Object testMultiObj() {
 8 
 9         MultiObject.MultiObjDataReq reqData=MultiObject.MultiObjDataReq.newBuilder()
10                 .setName("queryName")
11                 .setType(33)
12                 .build();
13 
14         MultiObject.MultiObjReq req=MultiObject.MultiObjReq.newBuilder()
15                 .setPageNo(11)
16                 .setPageSize(22)
17                 .setData(reqData)
18                 .build();
19 
20         MultiObjServiceGrpc.MultiObjServiceBlockingStub stb=MultiObjServiceGrpc.newBlockingStub(serverChannel);
21         MultiObject.MultiObjResp resp=stb.queryObj(req);
22 
23         Map<String,Object> reMap=new HashMap<>();
24         reMap.put("getFContent",resp.getFirst().getFContent());
25         reMap.put("getNContent",resp.getFirst().getNext().getNContent());
26         reMap.put("getReqStr",resp.getReqStr());
27         return reMap;
28     }
29 
30 }

  服務端(preview-grpc-server):

  (GrpcMultiObjService.java)

 1 @GrpcService(MultiObjServiceGrpc.class)
 2 public class GrpcMultiObjService extends MultiObjServiceGrpc.MultiObjServiceImplBase{
 3     private static final Logger LOG=LoggerFactory.getLogger(GrpcMultiObjService.class);
 4 
 5     @Override
 6     public void queryObj(MultiObject.MultiObjReq request,StreamObserver<MultiObject.MultiObjResp> responseObserver) {
 7 
 8         LOG.info("MultiObjServiceGrpc>start");
 9         Map<String,Object> reqData=new HashMap<String,Object>();
10         reqData.put("getPageNo",request.getPageNo());
11         reqData.put("getPageSize",request.getPageSize());
12         reqData.put("getName",request.getData().getName());
13         reqData.put("getType",request.getData().getType());
14 
15         MultiObject.MultiObjNextResp next=MultiObject.MultiObjNextResp.newBuilder().setNContent("n_content").build();
16         MultiObject.MultiObjFirstResp first=MultiObject.MultiObjFirstResp.newBuilder().setFContent("f_content").setNext(next).build();
17         MultiObject.MultiObjResp resp=MultiObject.MultiObjResp.newBuilder().setReqStr(JSON.toJSONString(reqData)).setFirst(first).build();
18 
19         responseObserver.onNext(resp);
20         responseObserver.onCompleted();
21         LOG.info("MultiObjServiceGrpc>end");
22     }
23 
24 }

 

現在是 2018-08-26 02:13:42 

  由於在雙向流編寫及測試環節碰到些問題,耽擱了許久,此次會將雙向流和安全及攔截器放在下一篇講,各位,晚安 (=。=)  


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一,實現拼圖的搭建: <div class="box"> <table id="table1" class="mytable"> <tr> <td id="1"><img src="Files/01.gif" /></td> <td id="2"><img src="Files/02.gif" /> ...
  • 1、jQuery中的prop()和attr()的區別 prop()是在jQuery1.6版本之後才有的,在之前一直都是使用attr(), prop()修複了attr()的一些小bug。 2、推薦用法: prop() :在HTML元素固有屬性的時候用prop() attr() : 推薦在HTML非固有 ...
  • 這是設計模式的最後一篇,最近事還是挺多,自己的東西還是沒進步。其實我這個人不用和領導套近乎,我有自己的職業素養,工匠精神。我喜歡獨處,喜歡自由,也喜歡女人,我訂婚後也很幸福。 今年我31周歲了,現在不是回想以前的時候,但是還是我應該努力的時候,不停的上進,堅持最後一定會成功!最怕傻逼式的堅持! 朋友 ...
  • 概述 面向消息的中間件(message-oriented middleware 簡稱 MOM)支持在分散式系統之間發送和接收消息的軟體或硬體基礎橋梁。MOM允許應用程式模塊分佈在各個平臺上,並減少了跨多個操作系統和網路協議的開發應用程式的複雜性。中間件創建了一個分散式通信層,將應用程式開發人員與各種 ...
  • 1、自定義類型的定義及使用 2、自定義類的記憶體圖 3、ArrayList集合的基本功能 4、隨機點名器案例及庫存案例代碼優化 ...
  • Asp.Net MVC EF之一:使用Database類在EF框架中執行Sql語句 ...
  • Flask簡介 Flask是用 Python 語言基於 Werkzeug 工具箱編寫的輕量級Web開發框架。 其 WSGI 工具箱採用 Werkzeug(路由模塊),模板引擎則使用 Jinja2。這兩個也是 Flask 框架的核心。 搭建虛擬環境(Ubuntu) 一、安裝虛擬環境命令: 二、創建虛擬 ...
  • 今日內容介紹 1、介面 2、多態 01介面的概念 A:介面的概念 介面是功能的集合,同樣可看做是一種數據類型,是比抽象類更為抽象的”類”。 介面只描述所應該具備的方法,並沒有具體實現,具體的實現由介面的 實現類(相當於介面的子類)來完成。這樣將功能的定義與實現分離,優化了程式設計。 請記住:一切事物 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...