1 reco.proto

  1. syntax = "proto3";
  2. // 使用message定义数据类型, 类似于 struct
  3. // 必须指定参数的序号
  4. message UserRequest {
  5. string user_id=1;
  6. int32 channel_id=2;
  7. int32 article_num=3;
  8. int64 time_stamp=4;
  9. }
  10. message Track {
  11. string click=1;
  12. string collect=2;
  13. string share=3;
  14. string read=4;
  15. }
  16. message Article {
  17. int64 article_id=1;
  18. Track track=2;
  19. }
  20. message ArticleResponse {
  21. string exposure=1;
  22. int64 time_stamp=2;
  23. // repeated表示Article可能会出现多次
  24. repeated Article recommends=3;
  25. }
  26. // 使用service定义一个服务, 相当于类
  27. service UserRecommend {
  28. // 使用rpc定义被调用的方法
  29. rpc user_recommend(UserRequest) returns(ArticleResponse) {}
  30. }

2 根据proto文件生成py文件

(1) 安装protobuf编译器和grpc库

pip install grpcio-tools

(2) 编译生成代码

python -m grpc_tools.protoc -I . —python_out=. —grpc_python_out=. reco.proto python -m grpc_tools.protoc -I . —python_out=. —grpc_python_out=. restartDocker.proto

  • -I表示搜索proto文件中被导入文件的目录
  • —python_out表示保存生成Python文件的目录,生成的文件中包含接口定义中的数据类型
  • —grpc_python_out表示保存生成Python文件的目录,生成的文件中包含接口定义中的服务类型

运行后会生成两个新文件
image.png

  • reco_pb2.py 保存接口定义文件中的数据类型(给python调用)
  • reco_pb2_grpc.py 保存接口定义文件中的RPC方法(给grpc调用)

    3 server.py

    ```python import time from concurrent.futures.thread import ThreadPoolExecutor

import grpc

import reco_pb2 import reco_pb2_grpc

class UserRecommandServicer(reco_pb2_grpc.UserRecommendServicer): ‘’’通过子类继承重写的方式’’’ def user_recommend(self, request, context): user_id = request.user_id channel_id = request.channel_id article_num = request.article_num time_stamp = request.time_stamp

  1. resp = reco_pb2.ArticleResponse()
  2. resp.exposure = 'exposure param'
  3. resp.time_stamp = round(time.time() * 1000) # 以毫秒为单位
  4. _recommands = []
  5. for i in range(article_num):
  6. article = reco_pb2.Article()
  7. article.article_id = i + 1
  8. article.track.click = 'click param'
  9. article.track.collect = 'collect param'
  10. article.track.share = 'share param'
  11. article.track.read = 'read param'
  12. _recommands.append(article)
  13. resp.recommends.extend(_recommands)
  14. return resp

if name == ‘main‘:

  1. # 创建一个rpc服务器
  2. server = grpc.server(ThreadPoolExecutor(max_workers=10))
  3. # 将自己实现的被调用方法与服务器绑定
  4. reco_pb2_grpc.add_UserRecommendServicer_to_server(UserRecommandServicer(), server)
  5. # 绑定IP地址和端口
  6. server.add_insecure_port('127.0.0.1:8888')
  7. # 开启服务器运行, 注意start()方法是非阻塞
  8. server.start()
  9. server.wait_for_termination()
  1. > nohup python3 -u server.py > out.log 2>&1 &
  2. - nohup: 不挂断地运行命令,忽略所有挂断信号(SIGNUP信号)
  3. - -u: python的输出是有缓冲的,即使在py脚本中每次遍历都有打印输出,但是因为缓冲的作用,我们不能在nohup.out日志中立即看到打印的输出。加上-u参数,使得python不使用缓冲。
  4. - > out.log: > 表示覆盖式重定向。正常输出是把内容输出到显示器上,重定向是把内容输出到文件中。 command > out.log,将输出重定向到xxx文件中。
  5. - 2 > &1: 2是标准错误输出,1是标准输出,这里的&表示引用的意思,对标准输出的引用, 将标准错误输出也重定向到标准输出指向的文件中。
  6. - 最后的&: 表示后台运行。
  7. <a name="qUrME"></a>
  8. # 4 client.py
  9. ```python
  10. import time
  11. import grpc
  12. import reco_pb2_grpc
  13. import reco_pb2
  14. def feed_articles():
  15. with grpc.insecure_channel('127.0.0.1:8888') as channel:
  16. # 创建调用的辅助工具对象 stub
  17. stub = reco_pb2_grpc.UserRecommendStub(channel)
  18. # 创建请求对象, 并设置请求参数
  19. user_request = reco_pb2.UserRequest()
  20. user_request.user_id = '1'
  21. user_request.channel_id = 1
  22. user_request.article_num = 10
  23. user_request.time_stamp = round(time.time())
  24. # 通过stub进行rpc调用
  25. ret = stub.user_recommend(user_request)
  26. return ret
  27. if __name__ == '__main__':
  28. ret = feed_articles()
  29. print(ret)

python server.py python client.py

image.png