Go/Python gRPC實踐
阿新 • • 發佈:2022-12-12
gRPC框架 & ProtoBuf
安裝相關工具:
pip3 install grpcio
pip3 install grpcio-tools
protobuf3有自己專門的定義的格式,基於此可以生成不同的指令碼
編寫示例的protobuf3:
syntax = "proto3";
message HelloRequest {
string name = 1;
}
生成程式碼:
python3 -m grpc_tools.protoc --python_out=. --grpc_python_out=. -I. hello.proto
生成檔案:
hello_pb2_grpc.py hello_pb2.py
呼叫示例:
import hello_pb2
request = hello_pb2.HelloRequest()
request.name = "David"
# 物件生成字串
res = request.SerializeToString()
print(res)
# 通過字串反向生成物件
request2 = hello_pb2.HelloRequest()
request2.ParseFromString(res)
print(request2.name)
定義proto檔案
syntax = "proto3"; service Greeter { rpc SayHello(HelloRequest) returns (HelloReply) {} } message HelloRequest { string name = 1; } message HelloReply { string message = 1; }
生成檔案:
python3 -m grpc_tools.protoc --python_out=. --grpc_python_out=. -I. hello.proto
示例程式碼
伺服器端:
import hello_pb2 import hello_pb2_grpc import grpc from concurrent import futures class Greeter(hello_pb2_grpc.GreeterServicer): def SayHello(self, request, context): return hello_pb2.HelloReply(message=f"Hello, {request.name}") if __name__ == "__main__": # 例項化server server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) # 註冊邏輯到server hello_pb2_grpc.add_GreeterServicer_to_server(Greeter(),server) server.add_insecure_port('localhost:50051') server.start() server.wait_for_termination()
客戶端:
import grpc
import hello_pb2,hello_pb2_grpc
if __name__ == "__main__":
with grpc.insecure_channel("localhost:50051") as channel:
stub = hello_pb2_grpc.GreeterStub(channel)
rsp: hello_pb2.HelloReply = stub.SayHello(hello_pb2.HelloRequest(name="David"))
print(rsp.message)
客戶端直接如同呼叫本地函式一樣呼叫遠端函式SayHello,只要寫好規則就能自動生成程式碼
在Go語言中也是同理,將以上proto檔案放到一個目錄下,使用protoc生成:
protoc -I=. --go_out=plugins=grpc:. hello.proto
生成了hello.pb.go檔案
服務端程式碼:
type Server struct{}
func (s *Server) SayHello(ctx context.Context, request *proto.HelloRequest) (*proto.HelloReply, error) {
return &proto.HelloReply{
Message: "hello " + request.Name,
}, nil
}
func main() {
s := grpc.NewServer()
proto.RegisterGreeterServer(s, &Server{})
lis, err := net.Listen("tcp", "0.0.0.0:8080")
if err != nil {
panic("failed to listen:" + err.Error())
}
err = s.Serve(lis)
if err != nil {
panic("failed to start grpc:" + err.Error())
}
}
客戶端程式碼:
func main() {
conn, err := grpc.Dial("127.0.0.1:8080", grpc.WithInsecure())
if err != nil {
panic(err)
}
defer conn.Close()
c := proto.NewGreeterClient(conn)
r, err := c.SayHello(context.Background(), &proto.HelloRequest{Name: "David"})
if err != nil {
panic(err)
}
fmt.Println(r.Message)
}
同時Python和Go是可以互相呼叫的
也就是說,Python開啟伺服器時,Go的客戶端可以使用RPC呼叫,反之亦然