Go+Python双语言混合开发 第三部分 Go开发学习 第4章 grpc入门 学习笔记

633 阅读4分钟

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, PHPC# 支持.

链接

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

github.com/protocolbuf…

4.5 go下grpc开发体验

1. 下载工具

链接

如果觉得下载较慢可以点击这里下载:

📎protoc-3.14.0-win64.zip

📎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 {
    }

}

在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述