grpc裏的客戶端可以像調用本地對象一樣,直接調用另一臺機器上服務端的應用
一、什麼是gRPC
- 在服務端實現一個接口,定義一個服務,指定能被遠程調用的方法,並運行一個gRPC服務來處理客戶端調用
- 用proto files創建gRPC服務,用protocol buffers消息類型定義方法參數和返回類型。
1. 支持的語言:
- Go、python、ruby、C++、Java、node.js、C#、PHP、Android Java、Objective-C
2. protocol buffers
- 默認消息類型:protocol buffers(Google開源的一套結構數據序列化機制)
- 也可用json
- 現在常用proto3,因爲proto3可以使用grpc支持的全部範圍的語言,並且能避免proto2客戶端與proto3服務端交互時出現的兼容問題
二、使用
1. 分爲三步
- 通過protocol buffers定義一個RPC服務
- 創建一個實現這個接口的服務端
- 訪問服務端
2. python實現
1) 定義一個服務
- helloworld.proto
}
2) 生成grpc代碼
- 用定義的服務,使用protocol buffer編譯器protoc生成創建應用所需的特定客戶端和服務端代碼
python
protoc -I …/…/protos --python_out=. --grpc_out=. --plugin=protoc-gen-grpc=
which grpc_python_plugin
…/…/protos/helloworld.proto
- 生成了helloworld_pb2.py
Go
protoc -I …/protos …/protos/helloworld.proto
--go_out=plugins=grpc:helloworld
- 生成了helloworld.pb.go
3)寫服務來訪問
python
-
greeter_server.py
class Greeter(helloworld_pb2.BetaGreeterServicer): def SayHello(self, request, context): return helloworld_pb2.HelloReply(message='Hello, %s!' % request.name)
-
爲了返回給客戶端應答並且完成調用:
- 用我們的激動人心的消息構建並填充一個在我們接口定義的 HelloReply 應答對象。
- 將 HelloReply 返回給客戶端。
Go
- greeter_server/main.go 實現了 Greeter 服務所需要的行爲。
- 正如你所見,服務器有一個 server 結構。它通過實現 sayHello 方法,實現了從 proto 服務定義生成的GreeterServer 接口:
// server is used to implement helloworld.GreeterServer.
type server struct{}
// SayHello implements helloworld.GreeterServer
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
return &pb.HelloReply{Message: "Hello " + in.Name}, nil
}
- 爲了返回給客戶端應答並且完成調用:
- 用我們的激動人心的消息構建並填充一個在我們接口定義的 HelloReply 應答對象。
- 將 HelloReply 返回給客戶端。
4) 服務端實現
- 在這裏我們創建了合理的 gRPC 服務器,將我們實現的 Greeter 服務綁定到一個端口。
- 然後我們啓動服務器:服務器準備好從 Greeter 服務客戶端接收請求
python
- greeter_server.py
```python
server = helloworld_pb2.beta_create_Greeter_server(Greeter())
server.add_insecure_port('[::]:50051')
server.start()
try:
while True:
time.sleep(_ONE_DAY_IN_SECONDS)
except KeyboardInterrupt:
server.stop()
```
go
- greeter_server/main.go
const ( port = ":50051" ) ... func main() { lis, err := net.Listen("tcp", port) if err != nil { log.Fatalf("failed to listen: %v", err) } s := grpc.NewServer() pb.RegisterGreeterServer(s, &server{}) s.Serve(lis) }
5) 寫一個客戶端
- 用生成的代碼寫一個簡單的客戶程序來訪問我們在上邊創建的 Greeter 服務器
- 連接服務器:
- 需要創建一個 gRPC 頻道,指定我們要連接的主機名和服務器端口。然後我們用這個頻道創建存根實例
Python
- 生成的 Python 代碼有一個根據頻道創建存根的幫助方法。
channel = implementations.insecure_channel('localhost', 50051) stub = helloworld_pb2.beta_create_Greeter_stub(channel) ...
Go
const (
address = "localhost:50051"
defaultName = "world"
)
func main() {
// Set up a connection to the server.
conn, err := grpc.Dial(address)
if err != nil {
log.Fatalf("did not connect: %v", err)
}
defer conn.Close()
c := pb.NewGreeterClient(conn)
...
}
- 在 gRPC Go 你是使用一個特殊的 Dial() 方法來創建頻道。
6) 調用RPC
- 聯繫服務並獲得一個 greeting
- 創建並填充一個 HelloRequest 發送給服務。
- 我們用請求調用存根的 SayHello(),如果 RPC 成功,會得到一個填充的 HelloReply ,從其中我們可以獲得 greeting
python
response = stub.SayHello(helloworld_pb2.HelloRequest(name='you'), _TIMEOUT_SECONDS)
print "Greeter client received: " + response.message
Go
r, err := c.SayHello(context.Background(), &pb.HelloRequest{Name: name})
if err != nil {
log.Fatalf("could not greet: %v", err)
}
log.Printf("Greeting: %s", r.Message)