Go+Python双语言混合开发 第三部分 Go开发学习 第4章 grpc入门 学习笔记
第4章 grpc入门
Go+Python双语言混合开发 最后附上视频下载地址 官网地址:coding.imooc.com/class/469.h… 百度网盘下载地址: 链接: pan.baidu.com/s/1z54qp2yO… 密码: 6dl0 --来自百度网盘超级会员V3的分享
4.1 什么是grpc和protobuf
grpc
gRPC 是一个高性能、开源和通用的 RPC 框架,面向移动和 HTTP/2 设计。目前提供 C、Java 和 Go 语言版本,分别是:grpc, grpc-java, grpc-go. 其中 C 版本支持 C, C++, Node.js, Python, Ruby, Objective-C, PHP 和 C# 支持.
protobuf
java中的dubbo dubbo/rmi/hessian messagepack 如果你懂了协议完全有能力自己去实现一个协议
- 习惯用
Json、XML数据存储格式的你们,相信大多都没听过Protocol Buffer Protocol Buffer其实 是Google出品的一种轻量 & 高效的结构化数据存储格式,性能比Json、XML真的强!太!多!- protobuf经历了protobuf2和protobuf3,pb3比pb2简化了很多,目前主流的版本是pb3
4.2 python下protobuf体验
1. 安装
python -m pip install grpcio #安装grpc
python -m pip install grpcio-tools #安装grpc tools
2. 先体验protobuf3
protobuf3 是有自己专门的定义格式的 - 门槛
syntax = "proto3";
message HelloRequest {
string name = 1;
}
3. 生成proto的python文件
python -m grpc_tools.protoc --python_out=. --grpc_python_out=. -I. helloworld.proto
4. 查看protobuf生成的代码
from grpc_test import helloworld_pb2
request = helloworld_pb2.HelloRequest()
request.name = "bobby"
req_str = request.SerializeToString()
print(req_str)
request2 = helloworld_pb2.HelloRequest()
request2.ParseFromString(req_str)
print(request2.name)
5. 对比一下protobuf生成的效果
from grpc_test import helloworld_pb2
request = helloworld_pb2.HelloRequest()
request.name = "bobby"
req_str = request.SerializeToString()
print(req_str)
import json
req_json = {
"name":"bobby"
}
print(len(json.dumps(req_json)))
print(len(req_str))
4.3 python下的grpc开发体验
1. 官方案例
2. 运行
python greeter_server.py #运行服务器端
python greeter_client.py #运行客户端
4.4 python下解决grpc import路径出错的bug
4.5 go下grpc开发体验
1. 下载工具
如果觉得下载较慢可以点击这里下载:
📎protoc-3.14.0-linux-x86_64.zip
注意:protoc的版本需要和golang/protobuf保持一致 (尽量自己去下载最新的版本)
下载完成后解压后记得将路径添加到环境变量中
2. 下载go的依赖包
go get github.com/golang/protobuf/protoc-gen-go
3. proto文件
syntax = "proto3";
option go_package = ".;proto";
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
4. 生成go文件
goland插件地址: plugins.jetbrains.com/plugin/1400…
protoc -I . goods.proto --go_out=plugins=grpc:.
5. 服务端代码
package main
import (
"context"
"fmt"
"google.golang.org/grpc"
"grpc_demo/hello"
"net"
)
type Server struct {
}
func (s *Server) SayHello(ctx context.Context,request *hello.HelloRequest)(*hello.HelloReply,error){
return &hello.HelloReply{Message:"Hello "+request.Name},nil
}
func main() {
g := grpc.NewServer()
s := Server{}
hello.RegisterGreeterServer(g,&s)
lis, err := net.Listen("tcp", fmt.Sprintf(":8080"))
if err != nil {
panic("failed to listen: "+err.Error())
}
g.Serve(lis)
}
6. 客户端
package main
import (
"context"
"fmt"
"google.golang.org/grpc"
"grpc_demo/proto"
)
func main() {
conn,err := grpc.Dial("127.0.0.1:8080",grpc.WithInsecure())
if err!=nil{
panic(err)
}
defer conn.Close()
c := hello.NewGreeterClient(conn)
r,err := c.SayHello(context.Background(),&hello.HelloRequest{Name:"bobby"})
if err!=nil{
panic(err)
}
fmt.Println(r.Message)
}
4.6 grpc的四种数据流
之前我们讲了 grpc 怎么简单的使用 ,这次讲讲 grpc 中的 stream,srteam 顾名思义 就是 一种 流,可以源源不断的 推送 数据,很适合 传输一些大数据,或者 服务端 和 客户端 长时间 数据交互,比如 客户端 可以向 服务端 订阅 一个数据,服务端 就 可以利用 stream ,源源不断地 推送数据。
proto
syntax = "proto3";//声明proto的版本 只能 是3,才支持 grpc
//声明 包名
option go_package=".;proto";
//声明grpc服务
service Greeter {
/*
以下 分别是 服务端 推送流, 客户端 推送流 ,双向流。
*/
rpc GetStream (StreamReqData) returns (stream StreamResData){}
rpc PutStream (stream StreamReqData) returns (StreamResData){}
rpc AllStream (stream StreamReqData) returns (stream StreamResData){}
}
//stream请求结构
message StreamReqData {
string data = 1;
}
//stream返回结构
message StreamResData {
string data = 1;
}
服务端
package main
import (
"fmt"
"google.golang.org/grpc"
"log"
"net"
"start/new_stream/proto"
"sync"
"time"
)
const PORT = ":50052"
type server struct {
}
//服务端 单向流
func (s *server)GetStream(req *proto.StreamReqData, res proto.Greeter_GetStreamServer) error{
i:= 0
for{
i++
res.Send(&proto.StreamResData{Data:fmt.Sprintf("%v",time.Now().Unix())})
time.Sleep(1*time.Second)
if i >10 {
break
}
}
return nil
}
//客户端 单向流
func (s *server) PutStream(cliStr proto.Greeter_PutStreamServer) error {
for {
if tem, err := cliStr.Recv(); err == nil {
log.Println(tem)
} else {
log.Println("break, err :", err)
break
}
}
return nil
}
//客户端服务端 双向流
func(s *server) AllStream(allStr proto.Greeter_AllStreamServer) error {
wg := sync.WaitGroup{}
wg.Add(2)
go func() {
for {
data, _ := allStr.Recv()
log.Println(data)
}
wg.Done()
}()
go func() {
for {
allStr.Send(&proto.StreamResData{Data:"ssss"})
time.Sleep(time.Second)
}
wg.Done()
}()
wg.Wait()
return nil
}
func main(){
//监听端口
lis,err := net.Listen("tcp",PORT)
if err != nil{
panic(err)
return
}
//创建一个grpc 服务器
s := grpc.NewServer()
//注册事件
proto.RegisterGreeterServer(s,&server{})
//处理链接
err = s.Serve(lis)
if err != nil {
panic(err)
}
}
客户端
package main
import (
"google.golang.org/grpc"
"context"
_ "google.golang.org/grpc/balancer/grpclb"
"log"
"start/new_stream/proto"
"time"
)
const (
ADDRESS = "localhost:50052"
)
func main(){
//通过grpc 库 建立一个连接
conn ,err := grpc.Dial(ADDRESS,grpc.WithInsecure())
if err != nil{
return
}
defer conn.Close()
//通过刚刚的连接 生成一个client对象。
c := proto.NewGreeterClient(conn)
//调用服务端推送流
reqstreamData := &proto.StreamReqData{Data:"aaa"}
res,_ := c.GetStream(context.Background(),reqstreamData)
for {
aa,err := res.Recv()
if err != nil {
log.Println(err)
break
}
log.Println(aa)
}
//客户端 推送 流
putRes, _ := c.PutStream(context.Background())
i := 1
for {
i++
putRes.Send(&proto.StreamReqData{Data:"ss"})
time.Sleep(time.Second)
if i > 10 {
break
}
}
//服务端 客户端 双向流
allStr,_ := c.AllStream(context.Background())
go func() {
for {
data,_ := allStr.Recv()
log.Println(data)
}
}()
go func() {
for {
allStr.Send(&proto.StreamReqData{Data:"ssss"})
time.Sleep(time.Second)
}
}()
select {
}
}