python版gRPC快速入门一

最近花钱买了一些课程讲述了关于RPC的一些知识,觉得还不错,空余时间研究了点gRPC这个框架,觉得还是不做的,然后记录一下留作以后参考。
在网上http://doc.oschina.net/grpc找到了gRPC官网的中文文档说明,这里面介绍了gRPC以及一些安全认证,通讯协议和简单的例子。
刚开始还以为gPRC这个框架能够完成分布式部署的,后来才发现gRPC只能够完成服务器的部分,想要真正的完成分布式部署服务器还要借助一些其他的工具,也就是所谓的服务发现,例如zookeeper, etcd或者是consul等。常见的RPC一般包含三部分:
1.注册中心(用于服务端注册远程服务以及客户端发现服务)
2.服务端(对外提供后台服务,将自己的服务信息注册到注册中心)
3.客户端(从注册中心获取远程服务的注册信息,然后进行远程过程调用)
gRPC这里只是实现了服务端和客户端这两个功能,要实现注册中心还需要借助一些其他的工具。
本篇之讲述gPRC服务端和客户端的功能,关于注册中心的后续有机会在进行补充。
首先是安装gRPC在官方文档上有完整的介绍,这里不多赘述了。
第一步:定义服务
一个 RPC 服务通过参数和返回类型来指定可以远程调用的方法,gRPC 通过 protocol buffers 来实现。使用 protocol buffers 接口定义语言来定义服务方法,用 protocol buffer 来定义参数和返回类型。客户端和服务端均使用服务定义生成的接口代码。
下面是demo1.proto具体定于:

syntax = "proto3";
option java_package = "io.grpc.examples";
package demo1;
// 定义服务
service ImageRecognition {
	rpc Ping (PingRequest) returns (PongReply){};
	rpc ClientToServerImg (stream ImgRequest) returns (ImgSize) {};
}

// 客户端传的名字
message PingRequest{
	string ping = 1;
}
// 服务端返回的消息
message PongReply{
	string pong = 1;
}

message ImgRequest{
	string filename = 1;//文件名
	string filetype = 2;//文件类型
	bytes img = 3;//以二进制传方式送文件(也可以是string的形式:字符串形式传送)
}

message ImgSize{
	int32 imgzise = 1;//返回文件的大小(字节数)
}

说明:这里定义了两个服务。一个Ping(简单 RPC),一个是客户端上传一个文件到服务器上(请求流式 RPC);
第二步:生成客户端和服务端代码
执行这一步需要安装好一些工具如下:

sudo apt-get install protobuf-compiler-grpc 
sudo apt-get install protobuf-compiler

然后执行命令(我的环境是ubuntu18上,python3.6):

protoc -I ./protos --python_out=./protos --grpc_out=./protos --plugin=protoc-gen-grpc=`which grpc_python_plugin` ./protos/demo1.proto

在对应的目录下回生成两个文件demo1_pb2_grpc.py和demo1_pb2.py。
第三步:实现服务端代码
如下(server.py):

# -*- coding:utf-8 -*-
import demo1_pb2
import demo1_pb2_grpc
import time
import os

_ONE_DAY_IN_SECONDS = 60*60*24

class ImageRecognition(demo1_pb2.BetaImageRecognitionServicer):
	def Ping(self, request, context):
		if request.ping == 'ping':
			return demo1_pb2.PongReply(pong="pong")
		else:
			return demo1_pb2.PongReply(pong="sorry")

	def ClientToServerImg(self, request_iterator, context):
		count = 0
		with open("./image/img_file", "wb") as f:
			for line in request_iterator:
				num = f.write(line.img)
				count += num
				filename = line.filename
				filetype = line.filetype

		tmp_file = "./image/" + filename + filetype
		os.rename("./image/img_file", tmp_file)
		return demo1_pb2.ImgSize(imgzise=count)


server = demo1_pb2.beta_create_ImageRecognition_server(ImageRecognition())
server.add_insecure_port('[::]:50051')
server.start()

try:
	while True:
		time.sleep(_ONE_DAY_IN_SECONDS)
except KeyboardInterrupt:
	server.stop()

第四步:实现客户端代码
如下(client.py)

# -*- coding:utf-8 -*-
from __future__ import print_function

import grpc

import demo1_pb2
import demo1_pb2_grpc
import os

def get_img_data(filepath):
	(filename, filetype) = os.path.splitext(os.path.basename(os.path.realpath(filepath)))
	with open(filepath, "rb") as f:
		for line in f.readlines():
			yield demo1_pb2.ImgRequest(filename=filename,filetype=filetype,img=line) 

def run():
	with grpc.insecure_channel('localhost:50051') as channel:
		stub = demo1_pb2_grpc.ImageRecognitionStub(channel)

		response = stub.Ping(demo1_pb2.PingRequest(ping='ping'))
		print(response.pong)
		print('--------------------------------')
		retsize = stub.ClientToServerImg(get_img_data("./demo1_pb2.py"))
		print(retsize.imgzise)


if __name__ == '__main__':
	run()

特别说明:有些人可能会疑惑为什么传送文件的参数使用yield进行返回,因为使用了请求流式RPC,对应的参数需要是个迭代器。
然后运行server.py
在运行client.py
会看到运行在server端会有个文件生成,客户端打印出文件的大小。

你可能感兴趣的:(python)