1. 程式人生 > 其它 >Go/Python gRPC實踐

Go/Python gRPC實踐

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呼叫,反之亦然