查看: 3795|回复: 4

[原创] 让python和nodejs一起玩耍

[复制链接]
  • TA的每日心情
    开心
    2015-7-28 20:04
  • 签到天数: 2 天

    连续签到: 1 天

    [LV.1]初来乍到

    发表于 2015-9-30 15:04:17 | 显示全部楼层 |阅读模式
    分享到:
    本帖最后由 小菜儿 于 2015-9-30 15:42 编辑

    做树莓派,为什么还要用nodejs?
    没啥特别原因,主要是自己对nodejs+webscoket这套玩的比较熟,而对python的web开发没啥研究
    所以,定下这样一个技术方案:python负责硬件驱动和底层逻辑,nodejs负责上面的“好玩”的东西,也就是一般说的“业务逻辑”,web/webscoket服务服务由nodejs提供~
    那么问题来了,如何让python和nodejs可以方便的互相调用哪?
    按照自己的知识储备,大概有三个方案,按照优先级:
    1. 双向的webscoket
    2. 单向的thrift,python和nodejs各建一个server端和一个client端,实现双向通信
    3. 单向的http,和上面的思路类似,但是速度会比thrift慢一个数量级
    webscoket最好用,可以和页面通讯实现极速统一,而且一个连接就可以实现双向通讯,~~但是协议相对复杂,本来想使用nodejs的socket.io,让nodejs做server,python做client,但是试了几种方案都连不上,如果手动实现webscoket通讯协议。。。算了吧,还是下一个吧
    第2个方案其实也不顺利,由于对python不熟悉,thrift的库文件导了几次总是失败,拖了几天仔细研究了python的import方式才算成功
    这样,整个系统的方案也就是这样
    np.png
    (我的初步打算是做一个能自主行走、壁障,又能用手机网页遥控的机器人,所以硬件部分是直流电机控制芯片、超声测距、红外感应)
    下面就来分享一下nodejs与python基于thrift做互联的代码,根据这个方案,对于不熟悉python又想在树莓派上实现较复杂业务逻辑的人,完全可以将nodejs换成自己更熟悉的语言,对于thrift不熟悉的朋友,可以自己学习:http://thrift.apache.org
    和一般的thrift的思路不同,为了简化代码逻辑,这里其实类似http接口,action类似url,post一坨键值对,然会返回一坨信息,之所以这么设计,是因为一直觉得thrift太啰嗦,每次添加新接口还要替换定义文件
    。。。。。。
    thrift定义文件:
    1. /**
    2. * 统一的返回值
    3. */
    4. struct Retu{
    5.     1: i32 code, //返回码
    6.     2: string msg, //返回错误时的详细信息
    7.     3: map<string, string> data//map/字典 类型的返回值
    8. }

    9. /**
    10. * 异常信息
    11. */
    12. exception UException{
    13.     1:i32 errorCode,      //错误码      1=参数错误,2=没有结果 99=系统异常
    14.     2:string errorMessage    //错误描述
    15. }

    16. service PiMessService{
    17.         Retu c(1:string action, 2:map<string, string> params) throws (1:UException ex),
    18. }
    复制代码
    python端:
    1. #coding:utf-8
    2. import sys, glob, os
    3. import event  #这里是自己封装的python事件中心,可以订阅、触发事件,以后有机会单独给大家分享
    4. rootPath = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    5. sys.path.append(rootPath + '/lib/gen-py')  #thrift库文件位置

    6. from thrift.transport import TSocket
    7. from thrift.transport import TTransport
    8. from thrift.protocol import TBinaryProtocol
    9. from thrift.server import TServer

    10. import piMess.PiMessService as PiMessService
    11. import piMess.ttypes as ttypes

    12. #####server start#####
    13. class PiMessHandler:
    14.     def __init__(self):
    15.         self.log = {}
    16.     #会被client调用的方法
    17.     def c(self, action, params):
    18.         #收到一次调用,其实是触发一次特定事件,程序其他部分可以去订阅这个事件,返回给出返回值
    19.         rets    = event.trigger('tele_' + action, params)  
    20.         msg     = ''
    21.         data    = {}
    22.         if(len(rets) > 0): #以第一个绑定的返回值为准,后续可以根据实际需求在扩展
    23.             if(type(rets[0]) == type('')):#只使用字符串和字典值
    24.                 msg     = rets[0]
    25.             elif(type(rets[0]) == type({})):
    26.                 data    = rets[0]
    27.         return ttypes.Retu(200, msg, data)
    28. #启动服务
    29. def serviceStart():
    30.     print 'PiMessService start on 9001 ...'
    31.     handler     = PiMessHandler()
    32.     processor   = PiMessService.Processor(handler)
    33.     transport   = TSocket.TServerSocket(port=9001) #python server端的端口
    34.     tfactory    = TTransport.TBufferedTransportFactory()
    35.     pfactory    = TBinaryProtocol.TBinaryProtocolFactory()
    36.     server      = TServer.TSimpleServer(processor, transport, tfactory, pfactory)
    37.     server.serve()
    38.     print 'done~'
    39. #####server end#######

    40. #####client start#####
    41. __transport = TSocket.TSocket('localhost', 9002)   #nodejs server端的端口
    42. __transport = TTransport.TBufferedTransport(__transport)
    43. __protocol  = TBinaryProtocol.TBinaryProtocol(__transport)
    44. __client    = PiMessService.Client(__protocol)
    45. def clientOpen():
    46.     __transport.open()

    47. #供外部调用的向nodejs端发送消息的方法
    48. def send(action, params):
    49.     r = __client.c(action, params)
    50.     print('call nodejs:', action, params, r)
    51.     return r

    52. def clientClose():
    53.     __transport.close()
    54. #####client end#######

    55. if __name__ == "__main__":
    56.     clientOpen()
    57.     send('py-client', {'QQQ': 'ZZZ', 'abc':'PPP'})
    58.     serviceStart()
    复制代码
    nodejs端:
    1. var thrift          = require('thrift');
    2. var Thrift          = thrift.Thrift;

    3. var piMessService   = require('../gen-nodejs/PiMessService'),
    4.   ttypes            = require('../gen-nodejs/piMess_types');


    5. /***server start***/
    6. var server          = thrift.createServer(piMessService, {
    7.   c: function(action, params, result){  
    8.     //server,可以根据action值,调用对应的外部方法
    9.     console.log('piMessService.c:', action, params);
    10.     retu            = new ttypes.Retu({code:200, msg:'ok', data:null});
    11.     result(null, retu);
    12.   }
    13. }, {});
    14. server.listen(9002);
    15. /***server end*****/

    16. /***client start***/
    17. var connection      = thrift.createConnection('localhost', 9001),
    18.   client            = thrift.createClient(piMessService, connection);

    19. //对外暴漏一个send方法
    20. exports.send = function(action, params, callback){
    21.   console.log('exports.send:', action, params);
    22.   client.c(action, params, function(err, response){
    23.     if(response){
    24.       console.log('response:', response);
    25.     }
    26.     callback && callback(err, response);
    27.   });
    28. };

    29. exports.clientEnd = function(){
    30.   connection.end();
    31. };
    32. /***client end*****/
    复制代码
    Discuz!不好贴代码,感兴趣的请移步我的bloghttp://www.jiangkunlun.com/2015/09/python_nodejs_thrift/)


    回复

    使用道具 举报

  • TA的每日心情
    奋斗
    2020-9-28 10:10
  • 签到天数: 1018 天

    连续签到: 1 天

    [LV.10]以坛为家III

    发表于 2015-9-30 15:43:01 | 显示全部楼层
    我觉得Discuz 代码很好贴
    回复 支持 反对

    使用道具 举报

  • TA的每日心情

    2023-7-25 22:49
  • 签到天数: 385 天

    连续签到: 1 天

    [LV.9]以坛为家II

    发表于 2015-10-1 09:08:48 | 显示全部楼层
    学习,学习。。。
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    慵懒
    2016-10-17 12:07
  • 签到天数: 306 天

    连续签到: 1 天

    [LV.8]以坛为家I

    发表于 2015-10-1 09:11:49 | 显示全部楼层
    不错呦。。。。
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2015-7-28 20:04
  • 签到天数: 2 天

    连续签到: 1 天

    [LV.1]初来乍到

     楼主| 发表于 2015-10-1 14:43:06 | 显示全部楼层
    小菜儿 发表于 2015-9-30 15:43
    我觉得Discuz 代码很好贴

    好吧...可以顺道贴个教程
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /4 下一条



    手机版|小黑屋|与非网

    GMT+8, 2024-11-19 11:34 , Processed in 0.167738 second(s), 24 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.