python与golang通过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())
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)