protobuf
syntax = "proto3"; // 这是个proto3的文件
message HelloRequest{ // 创建数据对象
string name = 1; // name表示名称,编号是1
}
生成python文件
安装grpcio和grpcio-tools库
shell
pip install grpcio #安装grpc
pip install grpcio-tools #安装grpc tools
生成proto的python文件
shell
python -m grpc_tools.protoc --python_out=. --grpc_python_out=. -I. helloworld.proto
python -m grpc_tools.protoc
:使用grpc_tools包中的protoc命令进行代码生成。--python_out=.
:指定生成的Python代码的存放位置为当前目录。--grpc_python_out=.
:指定生成的gRPC代码的存放位置为当前目录。-I.
:指定搜索.proto文件的路径为当前目录
总结起来,该命令的作用是将当前目录下的helloworld.proto文件生成对应的Python代码,并将生成的代码存放在当前目录中
python使用grpc
protobuf
syntax = "proto3";
// The greeting service definition.
service Greeter {
// Sends a greeting 下面就是暴露出来的一些方法
rpc SayHello (HelloRequest) returns (HelloReply) {} // 定义返回什么类型就要返回什么类型
rpc SayHelloStreamReply (HelloRequest) returns (stream HelloReply) {}
rpc SayHelloBidiStream (stream HelloRequest) returns (stream 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;
}
生成出来的文件就直接使用他
go使用grpc
生成指令:
shell
#好像是版本不兼容了 protoc -I . helloworld.proto --go_out=plugins=grpc:.
protoc -I . --go_out=. --go-grpc_out=. ./hello.proto
样例:
protobuf
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;
}
https://blog.csdn.net/neve_give_up_dan/article/details/126920398
https://github.com/grpc/grpc-go/issues/3794
https://blog.csdn.net/Mirale/article/details/122736894
UnimplementedXxxServer的作用:https://blog.csdn.net/Canon_in_D_Major/article/details/108135724
流模式
grpc的流模式主要有三种:
- 客户端流模式
- 服务端流模式
- 双向流模式
proto文件:stream_proto.proto
protobuf
syntax = "proto3";
option go_package = ".;proto";
service Greeter {
// 服务端流模式:客户端是流,服务端不是流
rpc GetStream(StreamReqData) returns (stream StreamResData); // 服务端流模式
rpc PostStream(stream StreamReqData) returns (StreamResData); // 客户端流模式
rpc AllStream(stream StreamReqData) returns (stream StreamResData); // 双向流模式
}
message StreamReqData{
string data = 1;
}
message StreamResData{
string data = 1;
}
server.go
go
package main
import (
"GoRpc_quick/stream_grpc_test/proto"
"fmt"
"google.golang.org/grpc"
"net"
"sync"
"time"
)
const PORT = ":8080"
type server struct {
proto.UnimplementedGreeterServer
}
// 服务端流模式
func (s *server) GetStream(req *proto.StreamReqData, streamServer proto.Greeter_GetStreamServer) error {
i := 0
for true {
streamServer.Send(&proto.StreamResData{
Data: fmt.Sprintf("%v\n + %v", time.Now().Unix(), req.Data),
})
time.Sleep(time.Second)
if i++; i > 10 {
break
}
}
return nil
}
// 客户端流模式
func (s *server) PostStream(streamServer proto.Greeter_PostStreamServer) error {
for {
recv, err := streamServer.Recv()
if err != nil {
fmt.Println(err)
break
}
fmt.Println(recv.Data)
}
return nil
}
// 双向流模式
func (s *server) AllStream(streamServer proto.Greeter_AllStreamServer) error {
wg := sync.WaitGroup{}
wg.Add(2)
go func() { // 负责receive
defer wg.Done()
for {
recv, _ := streamServer.Recv()
fmt.Println("收到客户端消息:", recv.Data)
}
}()
go func() {
defer wg.Done()
for i := 0; i < 10; i++ {
streamServer.Send(&proto.StreamResData{Data: "我是服务器"})
time.Sleep(time.Second)
}
}()
wg.Wait()
return nil
}
func main() {
listener, err := net.Listen("tcp", PORT)
if err != nil {
panic(err)
}
s := grpc.NewServer()
proto.RegisterGreeterServer(s, &server{})
err = s.Serve(listener)
if err != nil {
panic("failed to start grpc")
}
}
client.go
go
package main
import (
"GoRpc_quick/stream_grpc_test/proto"
"context"
"fmt"
"google.golang.org/grpc"
"sync"
"time"
)
func main() {
conn, err := grpc.Dial("localhost:8080", grpc.WithInsecure())
if err != nil {
panic(err)
}
defer conn.Close()
// 服务端流模式(客户端接收流)
c := proto.NewGreeterClient(conn)
stream, _ := c.GetStream(context.Background(), &proto.StreamReqData{Data: "alice"})
for {
recv, err := stream.Recv() // 实际上就是socket编程
if err != nil {
fmt.Println(err.Error())
break
}
fmt.Println(recv)
}
// 客户端流模式,客户端发送流
postStream, err := c.PostStream(context.Background())
for i := 0; i < 10; i++ {
_ = postStream.Send(&proto.StreamReqData{Data: fmt.Sprintf("客户端流模式 + %d", i)})
time.Sleep(time.Second)
}
// 双向流模式
allStream, _ := c.AllStream(context.Background())
wg := sync.WaitGroup{}
wg.Add(2)
go func() { // 负责receive
defer wg.Done()
for {
recv, _ := allStream.Recv()
fmt.Println("收到服务器消息:", recv.Data)
}
}()
go func() {
defer wg.Done()
for i := 0; i < 10; i++ {
allStream.Send(&proto.StreamReqData{Data: "我是客户端"})
time.Sleep(time.Second)
}
}()
wg.Wait()
}