1. 簡介
在本程式碼研究室中,您將使用 gRPC-Python 建立用戶端和伺服器,做為以 Python 編寫的路線對應應用程式基礎。
完成本教學課程後,您將擁有一個用戶端,可使用 gRPC 連線至遠端伺服器,取得地圖上特定座標位置的名稱或郵寄地址。完整的應用程式可能會使用這種用戶端/伺服器設計,列舉或摘要說明路線上的興趣點。
服務定義於 Protocol Buffers 檔案中,用於產生用戶端和伺服器的樣板程式碼,以便彼此通訊,節省您實作該功能的時間和精力。
這段產生的程式碼不僅會處理伺服器與用戶端之間複雜的通訊,也會處理資料序列化和還原序列化。
課程內容
- 如何使用通訊協定緩衝區定義服務 API。
 - 如何使用自動程式碼生成功能,從通訊協定緩衝區定義建構以 gRPC 為基礎的用戶端和伺服器。
 - 瞭解如何透過 gRPC 進行用戶端與伺服器之間的通訊。
 
這個程式碼研究室適用於剛接觸 gRPC 或想複習 gRPC 的 Python 開發人員,以及有興趣建構分散式系統的任何人。不需要有 gRPC 相關經驗。
2. 事前準備
軟硬體需求
- Python 3.9 以上版本。建議使用 Python 3.13。如需特定平台的安裝說明,請參閱「Python 設定和使用方式」。或者,您也可以使用 uv 或 pyenv 等工具,安裝非系統 Python。
 - pip 安裝 Python 套件。
 - venv 建立 Python 虛擬環境。
 
ensurepip 和 venv 套件是 Python 標準程式庫的一部分,通常預設會提供。
不過,部分以 Debian 為基礎的發行版本 (包括 Ubuntu) 會選擇在重新發布 Python 時排除這些檔案。如要安裝套件,請執行:
sudo apt install python3-pip python3-venv
取得程式碼
為簡化學習過程,本程式碼研究室提供預先建構的原始碼架構,協助您踏出第一步。下列步驟將引導您完成應用程式,包括使用 grpc_tools.protoc Protocol Buffer 編譯器外掛程式產生 gRPC 程式碼。
grpc-codelabs
本程式碼研究室的架構原始碼位於 codelabs/grpc-python-getting-started/start_here 目錄。如果您不想自行導入程式碼,完成的原始碼會放在 completed 目錄中。
首先,請建立程式碼研究室工作目錄,然後 cd 到該目錄:
mkdir grpc-python-getting-started && cd grpc-python-getting-started
下載並擷取程式碼研究室:
curl -sL https://github.com/grpc-ecosystem/grpc-codelabs/archive/refs/heads/v1.tar.gz \
  | tar xvz --strip-components=4 \
  grpc-codelabs-1/codelabs/grpc-python-getting-started/start_here
或者,您也可以下載只包含 Codelab 目錄的 .zip 檔案,然後手動解壓縮。
3. 定義服務
首先,請使用通訊協定緩衝區介面定義語言,定義應用程式的 gRPC 服務、RPC 方法,以及要求和回應訊息類型。你的服務將提供:
- 伺服器實作且用戶端呼叫的 RPC 方法,稱為 
GetFeature。 - 使用 
GetFeature方法時,訊息類型Point和Feature是用戶端與伺服器之間交換的資料結構。用戶端會在傳送至伺服器的GetFeature要求中,以Point形式提供地圖座標,而伺服器會回覆相應的Feature,說明這些座標所指的位置。 
這個 RPC 方法及其訊息型別都會在提供的原始碼 protos/route_guide.proto 檔案中定義。
通訊協定緩衝區通常稱為 protobuf。如要進一步瞭解 gRPC 術語,請參閱 gRPC 的「核心概念、架構和生命週期」。
訊息類型
在原始碼的 protos/route_guide.proto 檔案中,請先定義 Point 訊息型別。Point 代表地圖上的經緯度座標組合。在本程式碼研究室中,請使用整數做為座標:
message Point {
  int32 latitude = 1;
  int32 longitude = 2;
}
數字 1 和 2 是 message 結構中每個欄位的專屬 ID 編號。
接著,定義 Feature 訊息類型。Feature 會使用 string 欄位,指定 Point 所指定位置的名稱或郵寄地址:
message Feature {
  // The name or address of the feature.
  string name = 1;
  // The point where the feature is located.
  Point location = 2;
}
服務方法
route_guide.proto 檔案具有名為 RouteGuide 的 service 結構,可定義應用程式服務提供的一或多個方法。
在 RouteGuide 定義中新增 rpc 方法 GetFeature。如先前所述,這個方法會根據一組指定座標查閱地點名稱或地址,因此請讓 GetFeature 針對指定 Point 傳回 Feature:
service RouteGuide {
  // Definition of the service goes here
  // Obtains the feature at a given position.
  rpc GetFeature(Point) returns (Feature) {}
}
這是 unary RPC 方法:簡單的 RPC,用戶端會將要求傳送至伺服器,並等待伺服器傳回回應,就像呼叫本機函式一樣。
4. 產生用戶端和伺服器程式碼
接著,使用通訊協定緩衝區編譯器,從 .proto 檔案產生用戶端和伺服器的樣板 gRPC 程式碼。
我們建立了 grpcio-tools,用於生成 gRPC Python 程式碼。It includes:
- 可從 
message定義產生 Python 程式碼的標準 protoc 編譯器。 - gRPC protobuf 外掛程式,可從 
service定義產生 Python 程式碼 (用戶端和伺服器存根)。 
我們將使用 pip 安裝 grpcio-tools Python 套件。讓我們建立新的 Python 虛擬環境 (venv),將專案的依附元件與系統套件區隔開來:
python3 -m venv --upgrade-deps .venv
如要在 bash/zsh 殼層中啟動虛擬環境,請執行下列指令:
source .venv/bin/activate
如為 Windows 和非標準殼層,請參閱 https://docs.python.org/3/library/venv.html#how-venvs-work 中的表格。
接著,請安裝 grpcio-tools (這也會安裝 grpcio 套件):
pip install grpcio-tools
使用下列指令產生 Python 樣板程式碼:
python -m grpc_tools.protoc --proto_path=./protos  \
 --python_out=. --pyi_out=. --grpc_python_out=. \
 ./protos/route_guide.proto
這會為我們在 route_guide.proto 中定義的介面產生下列檔案:
route_guide_pb2.py包含動態建立類別的程式碼,這些類別是從message定義產生。route_guide_pb2.pyi是從message定義產生的「存根檔案」或「型別提示檔案」。其中只包含沒有實作的簽章。IDE 可使用 Stub 檔案,提供更完善的自動完成和錯誤偵測功能。route_guide_pb2_grpc.py是從service定義產生,包含 gRPC 專屬的類別和函式。
gRPC 專屬程式碼包含:
5. 建立服務
首先,我們來看看如何建立 RouteGuide 伺服器。建立及執行 RouteGuide 伺服器可分為兩項工作:
- 實作從服務定義產生的服務介面,並使用可執行服務實際「工作」的函式。
 - 在特定通訊埠執行 gRPC 伺服器,監聽來自用戶端的要求並傳輸回應。
 
您可以在 start_here/route_guide_server.py 中找到初始 RouteGuide 伺服器。
實作 RouteGuide
route_guide_server.py 具有 RouteGuideServicer 類別,可將產生的類別 route_guide_pb2_grpc.RouteGuideServicer 子類別化:
# RouteGuideServicer provides an implementation
# of the methods of the RouteGuide service.
class RouteGuideServicer(route_guide_pb2_grpc.RouteGuideServicer):
RouteGuideServicer 會實作所有 RouteGuide 服務方法。
現在來詳細瞭解簡單的 RPC 實作方式。方法 GetFeature 會從用戶端取得 Point,並從資料庫中傳回 Feature 的對應功能資訊。
def GetFeature(self, request, context):
    feature = get_feature(self.db, request)
    if feature is None:
        return route_guide_pb2.Feature(name="", location=request)
    else:
        return feature
這個方法會傳遞 RPC 的 route_guide_pb2.Point 請求,以及提供 RPC 專屬資訊 (例如逾時限制) 的 grpc.ServicerContext 物件。系統會傳回 route_guide_pb2.Feature 回應。
啟動伺服器
實作所有 RouteGuide 方法後,下一步是啟動 gRPC 伺服器,讓用戶端實際使用您的服務:
def serve():
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
    route_guide_pb2_grpc.add_RouteGuideServicer_to_server(
        RouteGuideServicer(),
        server,
    )
    listen_addr = "localhost:50051"
    server.add_insecure_port(listen_addr)
    print(f"Starting server on {listen_addr}")
    server.start()
    server.wait_for_termination()
伺服器 start() 方法不會封鎖。系統會例項化新執行緒來處理要求。呼叫 server.start() 的執行緒通常不會有其他工作要做。在這種情況下,您可以呼叫 server.wait_for_termination(),乾淨地封鎖呼叫執行緒,直到伺服器終止為止。
6. 建立用戶端
在本節中,我們將說明如何為 RouteGuide 服務建立用戶端。您可以在 start_here/route_guide_client.py 中查看初始用戶端程式碼。
建立存根
如要呼叫服務方法,我們必須先建立 stub。
我們會在 route_guide_client.py 檔案中,從 .proto 內例項化 route_guide_pb2_grpc 模組的 RouteGuideStub 類別。
channel = grpc.insecure_channel("localhost:50051")
stub = route_guide_pb2_grpc.RouteGuideStub(channel)
呼叫服務方法
對於傳回單一回應的 RPC 方法 (稱為「回應一元」方法),gRPC Python 同時支援同步 (封鎖) 和非同步 (非封鎖) 控制流程語意。
簡單 RPC
首先,請定義要用來呼叫服務的 Point。這應該很簡單,只要從 route_guide_pb2 套件例項化物件,並提供一些屬性即可:
point = route_guide_pb2.Point(latitude=412346009, longitude=-744026814)
同步呼叫簡單的 RPC GetFeature,幾乎與呼叫本機方法一樣簡單。RPC 呼叫會等待伺服器回應,並傳回回應或引發例外狀況。我們可以呼叫方法並查看回應,如下所示:
feature = stub.GetFeature(point)
print(feature)
您可以檢查 Feature 物件的欄位,並輸出要求的結果:
if feature.name:
    print(f"Feature called '{feature.name}' at {format_point(feature.location)}")
else:
    print(f"Found no feature at at {format_point(feature.location)}")
7. 立即試用
執行伺服器:
python route_guide_server.py
在其他終端機中再次啟動虛擬環境,然後執行用戶端:
python route_guide_client.py
您會看到類似以下的輸出內容,為求清楚起見,時間戳記已省略:
name: "16 Old Brook Lane, Warwick, NY 10990, USA"
location {
  latitude: 412346009
  longitude: -744026814
}
Feature called '16 Old Brook Lane, Warwick, NY 10990, USA' at latitude: 412346009, longitude: -744026814
8. 後續步驟
- 請參閱「gRPC 簡介」和「核心概念」,瞭解 gRPC 的運作方式
 - 逐步完成基礎教學課程
 - 探索 Python API 參考資料