python与golang通过grpc进行通信

编程

  1. gRPC通过protobuf来定义接口,从而有更加严格的接口约束条件。2. 同时,通过protobuf可以将数据序列化为二进制编码,这会大幅减少需要传输的数据量,从而大幅提高性能。
  2. gRPC可以方便地支持流式通信

以下将通过例子实现go和python之间的gRPC,实现简单地传输一个字符串

  • python:3.5.9
  • golang:1.13.4
  • protobuf:3.11.3

proto定义规则

ProtoBuf3数据结构定义

message 消息结构类型名{

字段修饰符 数据类型 字段名 = 字段编码值;

}

  1. 字段修饰符

  • singular 默认值,标识成员只有0个或者1个
  • repeated 可以重复0次或多次

  1. 数据类型

  1. 字段编码值

用于通信双方识别对方的字段,通过同一份协议的结构体每个编码值对应的数据字段是一样的。取值范围是 1 ~ 2^32

举例

message String{

string query = 1;

int32 page_number = 2; // Which page number do we want

int32 result_per_page = 3; // Number of results to return per page

enum Corpus {

UNIVERSAL = 0;

WEB = 1;

IMAGES = 2;

LOCAL = 3;

NEWS = 4;

PRODUCTS = 5;

VIDEO = 6;

}

Corpus corpus = 4;

repeated int 32 num = 7;

}

定义服务

  1. 简单rpc

客户端使用 Stub 发送请求到服务器并等待响应返回,就像平常的函数调用一样,这是一个阻塞型的调用

service 服务类型名 {

rpc 服务名 (消息类型) returns (返回值消息类型);

}

  1. 服务器端流式RPC

客户端发送请求到服务器,拿到一个流去读取返回的消息序列。客户端读取返回的流,直到里面没有任何消息。

service 服务类型名 {

rpc 服务名 (消息类型) returns (stream 返回值消息类型);

}

  1. 客户端流式RPC

客户端写入一个消息序列并将其发送到服务器,同样也是使用流。一旦客户端完成写入消息,它等待服务器完成读取返回它的响应。

service 服务类型名 {

rpc 服务名 (stream 消息类型) returns (返回值消息类型);

}

  1. 双向流式

service 服务类型名 {

rpc 服务名 (stream 消息类型) returns (stream 返回值消息类型);

}

引用其他proto

// my.proto

import "first.proto";

golang和python编译proto

python编译proto

首先安装grpcio-tools和grpcio

pip install grpcio -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com

pip install grpcio-tools -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com

然后python编译proto

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

会生成两个文件

  • rpc_pb2.py 用来和 protobuf 数据进行交互
  • rpc_pb2_grpc 用来和 grpc 进行交互

golang编译proto

首先要安装grpc,由于环境的问题许多go的库难以获取,我将库都转移到了码云上,这样下载十分方便

git clone https://gitee.com/daba0007/grpc-go.git $GOPATH/src/google.golang.org/grpc  

git clone https://gitee.com/daba0007/net.git $GOPATH/src/golang.org/x/net

git clone https://gitee.com/daba0007/text.git $GOPATH/src/golang.org/x/text

git clone https://gitee.com/daba0007/sys.git $GOPATH/src/golang.org/x/sys

go get -u github.com/golang/protobuf/{proto,protoc-gen-go}

git clone https://gitee.com/daba0007/go-genproto.git $GOPATH/src/google.golang.org/genproto

cd $GOPATH/src/

go install google.golang.org/grpc

cp $GOPATH/bin/protoc-gen-go /usr/local/bin

然后编译proto

protoc --go_out=plugins=grpc:. rpc.proto

这样会生成一个rpc.pb.go的文件,用来和 protobuf 数据进行交互

Demo

定义proto

通过protobuf定义接口HelloService和数据类型String

// rpc.proto

syntax = "proto3";

package go_protoc;

// 定义数据类型String

message String {

string value = 1;

}

// 定义接口HelloService

service HelloService {

rpc Hello (String) returns (String);

}

Go做服务端,python做客户端

  1. go Server

// 编译出来的proto文件位于$GOPATH/src/go_protoc

package main

import (

"context"

"go_protoc"

"google.golang.org/grpc"

"log"

"net"

)

// 定义一个对象来处理接收到的protobuf

type HelloServiceImpl struct{}

func (p *HelloServiceImpl) Hello(ctx context.Context, args *go_protoc.String,) (*go_protoc.String, error) {

// 通过编译出来的rpc.pb.go解析String类型数据

reply := &go_protoc.String{Value: "hello:" + args.GetValue()}

return reply, nil

}

func main() {

// 定义一个grpc

grpcServer := grpc.NewServer()

// 通过编译出来的rpc.pb.go的HelloService接口定义一个服务RegisterHelloServiceServer

go_protoc.RegisterHelloServiceServer(grpcServer, new(HelloServiceImpl))

// 定义监听端口1234

lis, err := net.Listen("tcp", "192.168.1.146:1234")

if err != nil {

log.Fatal(err)

}

// 开启监听

grpcServer.Serve(lis)

}

  1. python Client

import rpc_pb2

import grpc

import rpc_pb2_grpc

# 连接 rpc 服务器

channel = grpc.insecure_channel("192.168.1.146:1234")

# 调用rpc服务,通过编译出来的rpc_pb2_grpc的HelloService接口定义HelloServiceStub接口,接收来自channel的数据

stub = rpc_pb2_grpc.HelloServiceStub(channel)

# 通过接口的rpc获取String类型数据,并获取值

response = stub.Hello(rpc_pb2.String(value="test"))

print("Greeter client received: " + response.value)

python做服务端,go做客户端

  1. python Server

from concurrent import futures

import time

import rpc_pb2

import grpc

import rpc_pb2_grpc

class Hello(rpc_pb2_grpc.HelloServiceServicer):

# 实现 proto 文件中定义的 rpc 调用

def Hello(self, request, context):

return rpc_pb2.String(value = "hello {msg}".format(msg = request.value))

# 定义开启4个线程处理接收到的请求

server = grpc.server(futures.ThreadPoolExecutor(max_workers=4))

# 将编译出来的rpc_pb2_grpc的add_HelloServiceServicer_to_server函数添加到server中

rpc_pb2_grpc.add_HelloServiceServicer_to_server(Hello(), server)

# 定义服务端端口1234

server.add_insecure_port("192.168.1.146:1234")

server.start()

# 长期监听

try:

while True:

time.sleep(60 * 60 * 24)

except KeyboardInterrupt:

server.stop(0)

  1. go Client

package main

import (

"fmt"

"go_protoc"

"google.golang.org/grpc"

"log"

"golang.org/x/net/context"

)

func main() {

// 连接服务端接口

conn, err := grpc.Dial("192.168.1.146:1234", grpc.WithInsecure())

if err != nil {

log.Fatal(err)

}

defer conn.Close()

// 通过编译rpc.pb.go得到NewHelloServiceClient函数来处理连接

client := go_protoc.NewHelloServiceClient(conn)

// 通过编译rpc.pb.go得到的Hello服务来发送数据类型为String的数据

reply, err := client.Hello(context.Background(), &go_protoc.String{Value: "test"})

if err != nil {

log.Fatal(err)

}

fmt.Println(reply.GetValue())

}

以上是 python与golang通过grpc进行通信 的全部内容, 来源链接: utcz.com/z/514210.html

回到顶部