gRPC - 使用 Python 的 Hello World 應用



現在讓我們建立一個基本的“Hello World”型別的應用,它將使用 gRPC 以及 Python。

.proto 檔案

首先讓我們在 **common_proto_files** 中定義 **greeting.proto** 檔案 -

syntax = "proto3";

service Greeter {
   rpc greet (ClientInput) returns (ServerOutput) {}
}
message ClientInput {
   string greeting = 1;
   string name = 2;
}
message ServerOutput {
   string message = 1;
}

現在讓我們仔細看看上面程式碼塊中的每一行 -

syntax = "proto3";

這裡的 **"syntax"** 表示我們使用的 Protobuf 版本。因此,我們使用最新的版本 3,並且該模式因此可以使用對版本 3 有效的所有語法。

package tutorial;

這裡的 **package** 用於衝突解決,例如,如果我們有多個具有相同名稱的類/成員。

service Greeter {
   rpc greet(ClientInput) returns (ServerOutput) {}
}

此塊表示服務“**Greeter**”的名稱和可以呼叫的函式名稱“**greet**”。**"greet"** 函式接收型別為 **"ClientInput"** 的輸入並返回型別為 **"ServerOutput"** 的輸出。現在讓我們看看這些型別。

message ClientInput {
   string greeting = 1;
   string name = 2;
}

在上面的程式碼塊中,我們定義了 **ClientInput**,它包含兩個屬性“**greeting**”和“**name**”,它們都是字串。客戶端應該將型別為“**ClientInput**”的物件傳送到伺服器。

message ServerOutput {
   string message = 1;
}

在這裡,我們還定義了,給定一個“**ClientInput**”,伺服器將返回一個帶有單個屬性“**message**”的“**ServerOutput**”。伺服器應該將型別為“**ServerOutput**”的物件傳送到客戶端。

現在,讓我們為 Protobuf 類和 gRPC 類生成底層程式碼。為此,我們需要執行以下命令 -

python -m grpc_tools.protoc -I ..\common_proto_files\ --
python_out=../python --grpc_python_out=. greeting.proto

但是,請注意,要執行該命令,我們需要安裝教程的 **設定** 部分中提到的正確依賴項。

這應該會自動生成我們使用 gRPC 所需的原始碼。原始碼將放置在 -

Protobuf class code: python/greeting_pb2.py
Protobuf gRPC code: python/greeting_pb2_grpcpb2.py

設定 gRPC 伺服器

現在我們已經定義了包含函式定義的 proto 檔案,讓我們設定一個可以呼叫這些函式的伺服器。

讓我們編寫伺服器程式碼來服務上述函式並將其儲存在 **server.py** 中 -

示例

from concurrent import futures

import grpc
import greeting_pb2
import greeting_pb2_grpc

class Greeter(greeting_pb2_grpc.GreeterServicer):
   def greet(self, request, context):
      print("Got request " + str(request))
      return greeting_pb2.ServerOutput(message='{0} {1}!'.format(request.greeting, request.name))
	  
def server():
   server = grpc.server(futures.ThreadPoolExecutor(max_workers=2))
   greeting_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server)
   server.add_insecure_port('[::]:50051')
   print("gRPC starting")
   server.start()
   server.wait_for_termination()
server()

上面的程式碼在指定的埠啟動一個 gRPC 伺服器,併為我們在 proto 檔案中編寫的函式和服務提供服務。讓我們遍歷上面的程式碼 -

  • 從 **main** 方法開始,我們在指定的埠建立一個 gRPC 伺服器。

  • 但在啟動伺服器之前,我們將要執行的服務分配給伺服器,即在我們的例子中,是 **Greeter** 服務。

  • 為此,我們需要將服務例項傳遞給伺服器,因此我們繼續建立服務例項,即在我們的例子中,是 **Greeter**。

  • 服務例項需要提供 **.proto** 檔案中存在的 method/function 的實現,即在我們的例子中,是 **greet** 方法。

  • 該方法期望一個與 .proto 檔案中定義的型別相同的物件,即對我們來說,是 **request**。

  • 該方法處理上述輸入,進行計算,然後應該在 **.proto** 檔案中返回提到的輸出,即在我們的例子中,是 **ServerOutput**。

設定 gRPC 客戶端

現在我們已經編寫了伺服器的程式碼,讓我們設定一個可以呼叫這些函式的客戶端。

讓我們編寫客戶端程式碼來呼叫上述函式並將其儲存在 **client.py** 中 -

示例

import grpc

import greeting_pb2
import greeting_pb2_grpc

def run():
   with grpc.insecure_channel('localhost:50051') as channel:
      stub = greeting_pb2_grpc.GreeterStub(channel)
      response = stub.greet(greeting_pb2.ClientInput(name='John', greeting = "Yo"))
   print("Greeter client received following from server: " + response.message)   
run()

上面的程式碼在指定的埠啟動一個 gRPC 伺服器,併為我們在 proto 檔案中編寫的函式和服務提供服務。讓我們遍歷上面的程式碼 -

  • 從 **main** 方法開始,我們為與伺服器的 gRPC 通訊設定了一個 Channel。

  • 然後,我們使用 channel 建立一個 **stub**。在這裡,我們使用計劃呼叫的函式的服務“**Greeter**”。stub 只不過是一個包裝器,它隱藏了遠端呼叫對呼叫者的複雜性。

  • 然後,我們簡單地建立 proto 檔案中定義的預期輸入,即在我們的例子中,是 **ClientInput**。我們硬編碼了兩個引數,即 **name** 和 **greeting**。

  • 我們最終進行呼叫並等待伺服器的結果。

所以,這就是我們的客戶端程式碼。

客戶端伺服器呼叫

現在,我們已經定義了我們的 **proto** 檔案,編寫了我們的伺服器和客戶端程式碼,讓我們繼續執行此程式碼並檢視實際情況。

要執行程式碼,請啟動兩個 shell。透過執行以下命令在第一個 shell 中啟動伺服器 -

python .\server.py

輸出

我們將得到以下輸出 -

gRPC starting

上述輸出表示伺服器已啟動。

現在,讓我們啟動客戶端。

python .\client.py

我們將看到以下輸出 -

輸出

Greeter client received following from server: Yo John!

現在,如果我們開啟伺服器日誌,我們將看到以下資料 -

gRPC starting
Got request greeting: "Yo"
name: "John"

因此,正如我們所看到的,客戶端能夠按預期呼叫伺服器,並且伺服器透過向客戶端回送問候來響應。

廣告

© . All rights reserved.