python与golang通过grpc进行通信

python与golang通过grpc进行通信,第1张

pythongolang通过grpc进行通信 - 博客 - 编程圈

golang 使用 gRPC - 知乎

grpc做了什么:

1.客户端client发送一个请求(Request)2.服务端server接收请求,并返回一个响应(Response)

1.编写proto文件:

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

syntax = "proto3" 指定了使用 protocol buffers的版本 。

2.python编译proto:

首先安装grpcio-tools和grpcio

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

然后python3编译proto :

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

会生成两个文件

rpc_pb2.py 用来和 protobuf 数据进行交互rpc_pb2_grpc 用来和 grpc 进行交互 3.golang编译proto:

首先安装grpc

go get -u google.golang.org/grpc

然后编译proto

protoc -I pb/ pb/rpc.proto --go_out=plugins=grpc:service

-I 后面指定proto文件存放目录,和proto文件

--go_out=plugins=grpc:后面指定生成go代码存放的目录

检查在service目录下是否成功生成一个名为rpc.pb.go的文件

注:编译遇到的问题

① 报错 protoc-gen-go: program not found or is not executable

解决方法:
找到protoc-gen-go 文件(该文件通过go get安装时会安装在$GOPATH/go/bin目录下),执行命令 cp protoc-gen-go /usr/local/bin/  , 然后执行 vim ~/.bash_profile ,
添加 export GOPATH=$HOME/go PATH=$PATH:$GOPATH/bin ,

最后执行source ~/.bash_profile即可。

其中,查看$GOPATH路径的方法见 Go语言之讲解GOROOT、GOPATH、GOBIN - py鱼 - 博客园

② 报错 protoc-gen-go: unable to determine Go import path

解决方法:

proto文件添加  option go_package = ; 

4. python做服务端,go做客户端

server.py

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('localhost:9000')
server.start()

# 长期监听
try:
    while True:
        time.sleep(60 * 60 * 24)
except KeyboardInterrupt:
    server.stop(0)

client.go

package main

import (
	"context"
	"fmt"
	go_protoc "hello_test/service" // 通过添加go.mod解决其引用问题
	"log"

	"google.golang.org/grpc"
)

func main() {
	// 连接服务端接口
	conn, err := grpc.Dial("localhost:9000", 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())
}

先启动服务端:

再运行客户端:

得到输出:hello test

注:

① 运行go报错 Error while dialing dial tcp 0.0.0.0:8181: connect: connection refused

解决:先启动服务端,再运行客户端

想要引用由go编译proto生成的文件rpc.pb.go,需要在根目录添加go.mod文件

hello_test是项目文件名

5. go做服务端,python做客户端

server.go

package main

import (
	"context"
	"fmt"
	go_protoc "hello_test/service" // 通过添加go.mod解决其引用问题
	"net"

	"google.golang.org/grpc"
)

// 定义一个对象来处理接收到的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: "server:" + 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", ":8080")
	if err != nil {
		fmt.Printf("监听端口失败: %s", err)
		return
	} else {
		fmt.Printf("监听端口: 8080\n")
	}

	// 开启监听
	err = grpcServer.Serve(lis)
	if err != nil {
		fmt.Printf("开启服务失败: %s", err)
		return
	} else {
		fmt.Printf("服务已开启")
	}
}

client.py

import rpc_pb2
import grpc
import rpc_pb2_grpc

# 连接 rpc 服务器
channel = grpc.insecure_channel('localhost:8080')
# 调用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)

 

输出得:server:test 

例1

server.py

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))
        
        # return rpc_pb2.Data(value1 = 'hello:  {msg1} {msg2}'.format(
        #     msg1 = request.value1, msg2 = request.value2))
        
        return rpc_pb2.Data(value1 = 'hello1:  {msg1} {msg2}'.format(msg1 = request.value1, msg2 = request.value2), 
                            value2 = 'hello2:  {msg2} {msg1}'.format(msg1 = request.value1, msg2 = request.value2))

# 定义开启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('localhost:9000')
server.start()

# 长期监听
try:
    while True:
        time.sleep(60 * 60 * 24)
except KeyboardInterrupt:
    server.stop(0)

 client.go

package main

import (
	"context"
	"fmt"
	go_protoc "hello_test3/service" // 通过添加go.mod解决其引用问题
	"log"

	"google.golang.org/grpc"
)

func main() {
	// 连接服务端接口
	conn, err := grpc.Dial("localhost:9000", 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.Data{Value1: "test1", Value2: "test2"})
	// reply, err := client.Hello(context.Background(), &go_protoc.Data{Value1: "test1"})
	// reply, err := client.Hello(context.Background(), &go_protoc.Data{Value2: "test2"})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(reply.GetValue1())
	fmt.Println("------------------------")
	fmt.Println(reply.GetValue2())
}

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/996002.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-21
下一篇 2022-05-21

发表评论

登录后才能评论

评论列表(0条)

保存