python grpc官方文档
go grpc官方文档
grpc是基于http2.0的,http2.0掘金文章
python demo
helloworld.proto
syntax = "proto3";
// The greeting service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
// The request message containing the user's name.
message HelloRequest {
string name = 1;
}
// The response message containing the greetings
message HelloReply {
string message = 1;
}
同路径下:
python -m grpc_tools.protoc --python_out=. --grpc_python_out=. -I. helloworld.proto
命令会生成两个文件,一个是 helloworld_pb2.py 和helloworld_pb2_grpc.py 文件。
-I 代表 proto的路径,后面的helloworld.proto代表指定的proto文件
简单来说,就是如果多个proto文件之间有互相依赖,生成某个proto文件时,需要import其他几个proto文件,这时候就要用-I来指定搜索目录。
如果没有指定 –I 参数,则在当前目录进行搜索。
demo
server.py
from concurrent import futures
import grpc
import helloworld_pb2
import helloworld_pb2_grpc
class Greeter(helloworld_pb2_grpc.GreeterServicer):
def SayHello(self, request, context):
return helloworld_pb2.HelloReply(message="你好,{}".format(request.name))
if __name__ == '__main__':
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
helloworld_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server)
server.add_insecure_port('0.0.0.0:50051')
server.start()
server.wait_for_termination()
client.py
import grpc
import helloworld_pb2
import helloworld_pb2_grpc
if __name__ == '__main__':
with grpc.insecure_channel("localhost:50051") as channel:
stub = helloworld_pb2_grpc.GreeterStub(channel)
rsp: helloworld_pb2.HelloReply = stub.SayHello(helloworld_pb2.HelloRequest(name="booby"))
print(rsp.message)
go demo
helloworld.proto
注意第二行的go_package 是指当前的包名
目录结构:
syntax = "proto3";
option go_package = "./;proto";
// The greeting service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
// The request message containing the user's name.
message HelloRequest {
string name = 1;
}
// The response message containing the greetings
message HelloReply {
string message = 1;
}
安装好protoc之后,在当前目录下:
protoc -I . helloworld.proto --go_out=plugins=grpc:.
在proto文件中添加go_package可以把输出的文件导出到指定目录,并且go_package不影响python输出的proto文件
server.go
package main
import (
"awesomeGoProject/grpc_test/proto"
"context"
"google.golang.org/grpc"
"net"
)
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() {
g := grpc.NewServer()
proto.RegisterGreeterServer(g, &Server{})
lis, err := net.Listen("tcp", "0.0.0.0:8080")
if err != nil {
panic("failed to listen"+err.Error())
}
err = g.Serve(lis)
if err !=nil {
panic("failed to start grpc:"+err.Error())
}
}
client.go
package main
import (
"awesomeGoProject/grpc_test/proto"
"context"
"fmt"
"google.golang.org/grpc"
)
func main() {
conn, err := grpc.Dial("127.0.0.1:8080", grpc.WithInsecure())
if err != nil {
panic(err.Error())
}
defer conn.Close()
c := proto.NewGreeterClient(conn)
r, err := c.SayHello(context.Background(), &proto.HelloRequest{
Name: "booby",
})
if err != nil {
panic(err.Error())
}
fmt.Println(r.Message)
}
以上go、python demo proto文件相同即可相互调用
message HelloRequest {
string name = 1;
repeated int32 id = 2;
}
如果使用上述的repeated
表示数组,在赋值的时候可以直接func(id = *)
不能使用obj.id = 1
,在python
中数组可以obj.id.append()
并且proto传值与id绑定,而不是与名称绑定
protobuf import 包相关问题
python demo
base.proto
syntax = "proto3";
package base;
message Pong{
string id = 1;
}
helloworld.proto
syntax = "proto3";
import "base.proto";
import "google/protobuf/empty.proto";
option go_package = "./;proto";
service Greeter {
rpc SayHello(HelloRequest) returns (HelloReply);
rpc Ping(google.protobuf.Empty) returns (base.Pong);
}
message HelloRequest {
string name = 1;
repeated int32 id = 2;
}
message HelloReply {
string message = 1;
message Result {
string name = 1;
string url = 2;
}
}
python -m grpc_tools.protoc -I ./proto --python_out=./proto --grpc_python_out=./proto ./proto/base.proto
python -m grpc_tools.protoc -I ./proto --python_out=./proto --grpc_python_out=./proto ./proto/helloworld.proto
go demo
base.proto
syntax = "proto3";
option go_package = "./;proto";
message Pong{
string id = 1;
}
helloworld.proto
syntax = "proto3";
import "base.proto";
//import "QianTaomessage/proto/base.proto";
import "google/protobuf/empty.proto";
option go_package = "./;proto";
service Greeter {
rpc SayHello(HelloRequest) returns (HelloReply);
rpc Ping(google.protobuf.Empty) returns (Pong);
}
message HelloRequest {
string name = 1;
repeated int32 id = 2;
}
message HelloReply {
string message = 1;
message Result {
string name = 1;
string url = 2;
}
}
protoc -I . base.proto --go_out=plugins=grpc:.
protoc -I . helloworld.proto --go_out=plugins=grpc:.
python与go差异点:base.proto:package/option go_package,helloworld.proto:调用import,python是base.Pong,go是Pong
在使用嵌套和外部的proto文件时
在python中,使用类的方法访问,go是使用其他方式
在使用protobuf内置的一些类型时,在实例化传参时,应该查看proto的源码进行实例化
不使用编译,直接使用proto文件创建server
grpc结合asyncio
go 控制metadata
python的grpc官方案例