grpc在python与golang中的使用

grpc 在python与golang中的使用

一 Proto中

首先定义data.proto文件

syntax = "proto3";
package example;


service FormatData {   //定义服务,用在rpc传输中
  rpc DoFormat(actionrequest) returns (actionresponse){}   //要使用的函数
}
message actionrequest {   // 定义请求结构
  required string text = 1;
}
message actionresponse{  // 定义返回结构
  required string text=1;
}

其中 DoFormat ,actionrequest与actionresponse 可定义多个,数据类型同样可定义

message actionrequest {   // 定义请求结构
  string text = 1; // tring 代表类型 text 代表字段
  string name = 2; 
  repeated string phones = 3; // repeated 这种字段可以重复任意多次(包括0次)。重复的值的顺序会被保留。表示该值可以重复,相当于Java中的List,python 中的list ,golang 中的slice
}

数据类型除了string外还有

.proto类型Java 类型C++类型备注
doubledoubledouble
floatfloatfloat
int32intint32使用可变长编码方式。编码负数时不够高效——如果你的字段可能含有负数,那么请使用sint32。
int64longint64使用可变长编码方式。编码负数时不够高效——如果你的字段可能含有负数,那么请使用sint64。
uint32int[1]uint32Uses variable-length encoding.
uint64long[1]uint64Uses variable-length encoding.
sint32intint32使用可变长编码方式。有符号的整型值。编码时比通常的int32高效。
sint64longint64使用可变长编码方式。有符号的整型值。编码时比通常的int64高效。
fixed32int[1]uint32总是4个字节。如果数值总是比总是比228大的话,这个类型会比uint32高效。
fixed64long[1]uint64总是8个字节。如果数值总是比总是比256大的话,这个类型会比uint64高效。
sfixed32intint32总是4个字节。
sfixed64longint64总是8个字节。
boolbooleanbool
stringStringstring一个字符串必须是UTF-8编码或者7-bit ASCII编码的文本。
bytesByteStringstring可能包含任意顺序的字节数据。

1 枚举

当需要定义一个消息类型的时候,可能想为一个字段指定某“预定义值序列”中的一个值。例如,假设要为每一个SearchRequest消息添加一个 corpus字段,而corpus的值可能是UNIVERSAL,WEB,IMAGES,LOCAL,NEWS,PRODUCTS或VIDEO中的一个。 其实可以很容易地实现这一点:通过向消息定义中添加一个枚举(enum)就可以了。一个enum类型的字段只能用指定的常量集中的一个值作为其值(如果尝 试指定不同的值,解析器就会把它当作一个未知的字段来对待)。在下面的例子中,在消息格式中添加了一个叫做Corpus的枚举类型——它含有所有可能的值 ——以及一个类型为Corpus的字段:

message SearchRequest {
  required string query = 1;
  int32 page_number = 2;
  int32 result_per_page = 3;
  enum Corpus {
    UNIVERSAL = 0;
    WEB = 1;
    IMAGES = 2;
    LOCAL = 3;
    NEWS = 4;
    PRODUCTS = 5;
    VIDEO = 6;
  }
  Corpus corpus = 4 ;
}

2 嵌套类型

message SearchResponse {
  message Result {
    string url = 1;
    string title = 2;
    string snippets = 3;
  }
  repeated Result result = 1;
}

二 Python 中使用

安装:
  1. gRPC 的安装:

    $ pip install grpcio

  2. 安装 ProtoBuf 相关的 python 依赖库:

    $ pip install protobuf

  3. 安装 python grpc 的 protobuf 编译工具:

    $ pip install grpcio-tools

目录结构

.
├── client
│   ├── __init__.py
│   └── main.py
├── example
│   ├── data_pb2_grpc.py
│   ├── data_pb2.py
│   ├── data.pb.go
│   ├── data.proto
│   ├── __init__.py
│   └── __pycache__
│       ├── data_pb2.cpython-36.pyc
│       └── data_pb2_grpc.cpython-36.pyc
└── service
    ├── __init__.py
    └── main.py

首先定义定义./example/data.proto

syntax = "proto3";
package example;


service FormatData {   //定义服务,用在rpc传输中
  rpc DoFormat(actionrequest) returns (actionresponse){}
}
message actionrequest {
  string text = 1;
  enum Corpus {
    UNIVERSAL = 0;
    WEB = 1;
    IMAGES = 2;
    LOCAL = 3;
    NEWS = 4;
    PRODUCTS = 5;
    VIDEO = 6;
  }
 Corpus corpus = 4;
}
message actionresponse{
  string text=1;
  int32 age = 2;
  message Result {
    string url = 1;
    string title = 2;
    repeated string snippets = 3;
  }
  repeated Result result = 3;
}

编译

在 ./example 文件夹下

python -m grpc_tools.protoc -I . --python_out=. --grpc_python_out=. data.proto

执行后生成了

│   ├── data_pb2_grpc.py
│   ├── data_pb2.py
两个文件

编写服务端 ./service/main.py

#! /usr/bin/env python
# -*- coding: utf-8 -*-
import grpc
import time
from concurrent import futures
import os
import sys


current_fonder_path = os.path.split(os.path.realpath(__file__))[0]
print (current_fonder_path)
protocal_path = os.path.join(current_fonder_path,"..","example")
print (protocal_path)
sys.path.append(protocal_path)
import  data_pb2,data_pb2_grpc


_ONE_DAY_IN_SECONDS = 60 * 60 * 24
_HOST = 'localhost'
_PORT = '8082'

# 实现一个派生类,重写rpc中的接口函数.自动生成的grpc文件中比proto中的服务名称多了一个Servicer
class FormatData(data_pb2_grpc.FormatDataServicer):
    # 重写接口函数.输入和输出都是proto中定义的Data类型
    def DoFormat(self, request, context):
        str = request.text
        print(request.corpus)
        return data_pb2.actionresponse(text=str.upper(),age=12,result=[{"url":"12","title":"12","snippets":["12","12"]},{"url":"12","title":"12","snippets":["12","12"]}])  # 返回一个类实例


def serve():
    # 定义服务器并设置最大连接数,corcurrent.futures是一个并发库,类似于线程池的概念
    grpcServer = grpc.server(futures.ThreadPoolExecutor(max_workers=4))   # 创建一个服务器
    data_pb2_grpc.add_FormatDataServicer_to_server(FormatData(), grpcServer)  # 在服务器中添加派生的接口服务(自己实现了处理函数)
    grpcServer.add_insecure_port(_HOST + ':' + _PORT)    # 添加监听端口
    grpcServer.start()    #  启动服务器
    try:
        while True:
            time.sleep(_ONE_DAY_IN_SECONDS)
    except KeyboardInterrupt:
        grpcServer.stop(0) # 关闭服务器


if __name__ == '__main__':
    serve()

编写客户端代码./client/main.py

#! /usr/bin/env python
# -*- coding: utf-8 -*-
import grpc
import os
import sys
from grpc._channel import _Rendezvous

current_fonder_path = os.path.split(os.path.realpath(__file__))[0]
print (current_fonder_path)
protocal_path = os.path.join(current_fonder_path,"..","example")
print (protocal_path)
sys.path.append(protocal_path)
import data_pb2, data_pb2_grpc

_HOST = 'localhost'
_PORT = '8082'


def run():
    conn = grpc.insecure_channel(_HOST + ':' + _PORT)  # 监听频道
    client = data_pb2_grpc.FormatDataStub(channel=conn)   # 客户端使用Stub类发送请求,参数为频道,为了绑定链接
    response = client.DoFormat(data_pb2.actionrequest(text='hello,world!',corpus="NEWS"))   # 返回的结果就是proto中定义的类
    for i in response.result:
        print(i)


if __name__ == '__main__':
    try:
        run()
    except _Rendezvous as e:
        print("connect error")
三 golang 中使用

由于是使用golang调用python代码,所以golang中未实现service

安装:

首先安装protoc

安装依赖
sudo yum -y install autoconf automake libtool curl make g++ unzip
或
sudo apt-get install -y install autoconf automake libtool curl make g++ unzip
在 https://github.com/protocolbuffers/protobuf/releases 下载最新tar.gz安装包(protobuf-all-3.8.0.tar.gz
)
$ tar xvzf protobuf-all-3.8.0.tar.gz
$ cd protobuf-3.8.0
$ ./configure --prefix=/usr/local/protobuf
$ make (需要很长时间)
$ sudo make check
$ sudo make install
$ sudo ln -s /usr/local/protoc /bin//protoc

然后安装go插件

go get -u github.com/golang/protobuf/protoc-gen-go

然后在在 ./example 文件夹下

$ protoc --go_out=plugins=grpc:. ./data.proto
生成文件
./example/data.pb.go

将data.pb.go文件拷贝到要使用的地方

目录结构

.
└── demo1
    ├── main.go
    └── rpc
        └── data.pb.go

然后安装gorpc库

官网的安装命令:

go get -u google.golang.org/grpc

结果不能下载

# 如果已经安装了proto和protoc-gen-go的话就不用安装了
go get -u github.com/golang/protobuf/{proto,protoc-gen-go}

# 下载grpc-go
git clone https://github.com/grpc/grpc-go.git $GOPATH/src/google.golang.org/grpc

# 下载golang/net
git clone https://github.com/golang/net.git $GOPATH/src/golang.org/x/net

# 下载golang/text
git clone https://github.com/golang/text.git $GOPATH/src/golang.org/x/text

# 下载go-genproto
git clone https://github.com/google/go-genproto.git $GOPATH/src/google.golang.org/genproto

./demo1/main.go文件

package main

//client.go

import (
	"fmt"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	pd "grpcdemo/demo1/rpc"
	"log"
	"reflect"
)

const (
	address     = "localhost:8082"
)

func main() {
	conn, err := grpc.Dial(address, grpc.WithInsecure())
	if err != nil {
		log.Fatal("did not connect: %v", err)
	}
	defer conn.Close()
	c := pd.NewFormatDataClient(conn)

	r, err := c.DoFormat(context.Background(), &pd.Actionrequest{Text:"test",Corpus:pd.Actionrequest_NEWS})
	if err != nil {
		log.Fatal("could not greet: %v", err)
	}
	fmt.Println(r.Age)
	fmt.Println(reflect.TypeOf(r.Result))
	for k,v:= range r.Result{
		fmt.Println(k,v)
		fmt.Println(v.Snippets)
	}
}

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值