TA的每日心情 | 开心 2015-7-28 20:04 |
---|
签到天数: 2 天 连续签到: 1 天 [LV.1]初来乍到
|
本帖最后由 小菜儿 于 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方式才算成功
这样,整个系统的方案也就是这样
(我的初步打算是做一个能自主行走、壁障,又能用手机网页遥控的机器人,所以硬件部分是直流电机控制芯片、超声测距、红外感应) 下面就来分享一下nodejs与python基于thrift做互联的代码,根据这个方案,对于不熟悉python又想在树莓派上实现较复杂业务逻辑的人,完全可以将nodejs换成自己更熟悉的语言,对于thrift不熟悉的朋友,可以自己学习:http://thrift.apache.org
和一般的thrift的思路不同,为了简化代码逻辑,这里其实类似http接口,action类似url,post一坨键值对,然会返回一坨信息,之所以这么设计,是因为一直觉得thrift太啰嗦,每次添加新接口还要替换定义文件 。。。。。。
thrift定义文件:- /**
- * 统一的返回值
- */
- struct Retu{
- 1: i32 code, //返回码
- 2: string msg, //返回错误时的详细信息
- 3: map<string, string> data//map/字典 类型的返回值
- }
-
- /**
- * 异常信息
- */
- exception UException{
- 1:i32 errorCode, //错误码 1=参数错误,2=没有结果 99=系统异常
- 2:string errorMessage //错误描述
- }
-
- service PiMessService{
- Retu c(1:string action, 2:map<string, string> params) throws (1:UException ex),
- }
复制代码 python端:- #coding:utf-8
- import sys, glob, os
- import event #这里是自己封装的python事件中心,可以订阅、触发事件,以后有机会单独给大家分享
- rootPath = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
- sys.path.append(rootPath + '/lib/gen-py') #thrift库文件位置
-
- from thrift.transport import TSocket
- from thrift.transport import TTransport
- from thrift.protocol import TBinaryProtocol
- from thrift.server import TServer
-
- import piMess.PiMessService as PiMessService
- import piMess.ttypes as ttypes
-
- #####server start#####
- class PiMessHandler:
- def __init__(self):
- self.log = {}
- #会被client调用的方法
- def c(self, action, params):
- #收到一次调用,其实是触发一次特定事件,程序其他部分可以去订阅这个事件,返回给出返回值
- rets = event.trigger('tele_' + action, params)
- msg = ''
- data = {}
- if(len(rets) > 0): #以第一个绑定的返回值为准,后续可以根据实际需求在扩展
- if(type(rets[0]) == type('')):#只使用字符串和字典值
- msg = rets[0]
- elif(type(rets[0]) == type({})):
- data = rets[0]
- return ttypes.Retu(200, msg, data)
- #启动服务
- def serviceStart():
- print 'PiMessService start on 9001 ...'
- handler = PiMessHandler()
- processor = PiMessService.Processor(handler)
- transport = TSocket.TServerSocket(port=9001) #python server端的端口
- tfactory = TTransport.TBufferedTransportFactory()
- pfactory = TBinaryProtocol.TBinaryProtocolFactory()
- server = TServer.TSimpleServer(processor, transport, tfactory, pfactory)
- server.serve()
- print 'done~'
- #####server end#######
-
- #####client start#####
- __transport = TSocket.TSocket('localhost', 9002) #nodejs server端的端口
- __transport = TTransport.TBufferedTransport(__transport)
- __protocol = TBinaryProtocol.TBinaryProtocol(__transport)
- __client = PiMessService.Client(__protocol)
- def clientOpen():
- __transport.open()
-
- #供外部调用的向nodejs端发送消息的方法
- def send(action, params):
- r = __client.c(action, params)
- print('call nodejs:', action, params, r)
- return r
-
- def clientClose():
- __transport.close()
- #####client end#######
-
- if __name__ == "__main__":
- clientOpen()
- send('py-client', {'QQQ': 'ZZZ', 'abc':'PPP'})
- serviceStart()
复制代码 nodejs端:- var thrift = require('thrift');
- var Thrift = thrift.Thrift;
-
- var piMessService = require('../gen-nodejs/PiMessService'),
- ttypes = require('../gen-nodejs/piMess_types');
-
-
- /***server start***/
- var server = thrift.createServer(piMessService, {
- c: function(action, params, result){
- //server,可以根据action值,调用对应的外部方法
- console.log('piMessService.c:', action, params);
- retu = new ttypes.Retu({code:200, msg:'ok', data:null});
- result(null, retu);
- }
- }, {});
- server.listen(9002);
- /***server end*****/
-
- /***client start***/
- var connection = thrift.createConnection('localhost', 9001),
- client = thrift.createClient(piMessService, connection);
-
- //对外暴漏一个send方法
- exports.send = function(action, params, callback){
- console.log('exports.send:', action, params);
- client.c(action, params, function(err, response){
- if(response){
- console.log('response:', response);
- }
- callback && callback(err, response);
- });
- };
-
- exports.clientEnd = function(){
- connection.end();
- };
- /***client end*****/
复制代码 (Discuz!不好贴代码,感兴趣的请移步我的blog:http://www.jiangkunlun.com/2015/09/python_nodejs_thrift/)
|
|