Python 中的代码,在 Node.js 和 Socket.IO 中通信,在 HTML 中呈现
Posted
技术标签:
【中文标题】Python 中的代码,在 Node.js 和 Socket.IO 中通信,在 HTML 中呈现【英文标题】:Code in Python, communicate in Node.js and Socket.IO, present in HTML 【发布时间】:2012-11-30 16:46:57 【问题描述】:您有一个 python 脚本diagnosis.py
,它可以生成基于事件的实时数据。使用 Node.js,您可以将其作为子进程启动并捕获其输出,然后使用 Socket.IO 将其发送到客户端并使用 html 呈现。
服务器
var util = require('util'),
spawn = require('child_process').spawn,
ls = spawn('python', ['diagnosis.py']);
var app = require('http').createServer(handler)
, io = require('socket.io').listen(app)
, fs = require('fs')
app.listen(80);
function handler (req, res)
fs.readFile(__dirname + '/index.html',
function (err, data)
if (err)
res.writeHead(500);
return res.end('Error loading index.html');
res.writeHead(200);
res.end(data);
);
io.sockets.on('connection', function (socket)
ls.stdout.on('data', function (gdata)
socket.emit('news', gdata.toString());
);
);
客户
<html>
<head>
<script src="/socket.io/socket.io.js"></script>
<script>
var d = "";
var socket = io.connect('http://localhost');
socket.on('news', function (data)
d += data;
document.getElementById('data').innerHTML = d;
console.log(data);
);
</script>
</head>
<body>
<div id="data"></div>
</body>
</html>
问题
这很好,但如果您正在寻找与 Socket.IO 相同的 HTML-Node.js 通信能力,但在 Node.js 和 Python 之间寻找呢?你会怎么做?那里没有 Web 服务器,因此 Socket.IO 没有多大意义,并且通过裸 TCP 进行通信并不能提供相同的功能/优雅。 Node.js和Python如何实现全双工通信?
更新我回答了我自己的问题,但我愿意接受另一种方法。 RPC 并不能完全满足我的要求。
【问题讨论】:
如果这就是你所做的一切,为什么不直接使用 python 呢? SimpleHTTPServer 和/或 WSGI 可能会有所帮助 我同意@JonasWielicki。这是你的 node.js 所做的一切,还是只是这个问题的一个简化示例? 好吧,他想在浏览器端使用 WebSockets,所以SimpleHTTPServer
和/或WSGI
无济于事。但是pypi.python.org/… 会。
@abarnert:OP 实际上特别想要 socket.io。但是也有针对 python 的 socket.io 解决方案,这意味着如果需要,整个服务器都可以在 python 中。
可以理解。我认为问题的根源实际上只是关于您是否仅将 node.js 用于示例中列出的简单目的,以及是否需要 node 和 python 之间的通信层。但我认为答案是你确实在 node.js 上做了比这里列出的更多的事情。
【参考方案1】:
Apache Thrift 是在所有主要语言之间编写 RPC 代码的一种非常棒的方式。你编写一个通用的 Thrift 规范来声明类型和服务,然后代码生成器为你想要的语言创建绑定。您可以拥有用于在您的节点和 python 代码库之间调用方法的 api。
在更通用的低级方法中,ZeroMQ 是一个消息队列库,它也支持所有主要语言。有了这个,你可以设计你自己的解决方案来实现你想要的通信方式(不仅仅是纯粹的 RPC)。它具有请求/回复、推送/拉取、发布/订阅和配对的模式。它为您提供了足够的工具来构建任何类型的可扩展系统。
我都用过,它们都是很好的解决方案。
作为一个非常粗略的例子,Thrift 规范可能是这样的。假设您想将事件从 python 传递到 node.js,对其进行处理并返回一些响应:
myspec.thrift
struct Event
1: string message;
service RpcService
string eventOccurred(1:Event e)
这定义了一个名为Event
的数据结构,其中包含一个字符串成员来保存消息。然后一个名为 RpcService
的服务定义了一个名为 eventOccured
的函数,它需要一个 Event
作为参数,并将返回一个字符串。
当您为 python 和 node.js 生成此代码时,您可以使用 python 的客户端代码和 node.js 的服务器端代码
蟒蛇
from myrpc import RpcService, ttypes
# create a connection somewhere in your code
CONN = connect_to_node(port=9000)
def someoneClickedSomething():
event = ttypes.Event("Someone Clicked!")
resp = CONN.eventOccurred(event)
print "Got reply:", resp
node.js
// I don't know node.js, so this is just pseudo-code
var thrift = require('thrift');
var myrpc = require('myrpc.js');
var server = thrift.createServer(myrpc.RpcService,
eventOccurred: function(event)
console.log("event occured:", event.message);
success("Event Processed.");
,
);
server.listen(9000);
【讨论】:
但它是否支持基于事件的实时通信?我可以从 Python 服务器发出数据并在发出数据时在 Node.js 客户端上做一些事情吗? 如果你这样使用它是基于事件的。例如,Thrift 会为您提供两个系统之间的方法调用。假设您编写了一个名为eventOccured(event)
的节俭服务。当您的事件发生在 python 端时,您只需使用您的事件对象调用eventOccured()
,然后 node.js 端将接收该调用,就好像它是本地的一样,并且可以发送返回值,如果它想要(如果它是在您的节俭规范中设置它返回结果)。使用 Thrift,您只需定义特定服务的处理程序是什么。在 node.js 中,这基本上是每个服务的回调。【参考方案2】:
您可以查看一些消息传递系统,例如 0mq http://www.zeromq.org/
【讨论】:
【参考方案3】:如果您只是在寻找在套接字之上为您提供简单协议的东西,那么您不必处理缓冲和分隔消息以及所有这些东西,两个明显的选择(取决于什么样的您尝试发送的数据)是网络字符串和 JSON-RPC。两种语言都有多种库可供选择,但您最终可以得到这样简单的代码:
class MyService(Service):
# … code to set up the newsdb
def getnews(self, category, item):
return self.newsdb.get(category, item)
myService = MyService(6000)
myService = Service(6000)
// … code to set up the newsdb
myService.getnews = function(category, item, callback)
callback(this.newsdb.get(category, item);
【讨论】:
【参考方案4】:我使用受question 启发的库将diagnosis.py
转换为 Socket.IO 客户端。这样我可以将实时数据发送到 Node.js Socket.IO 服务器:
socketIO.emit('gaze', ...)
然后让它执行 socket.broadcast.emit
将数据发送到所有 Socket.IO 客户端(浏览器和 diagnosis.py
)。
RPC 可能是跨语言开发更标准的方法,但我发现当目标是交换数据时这样做有点过头了。它也不支持开箱即用的事件 IO。
2013 年 1 月更新 由于socket.broadcast.emit
会产生大量不必要的流量,因此我试图找到一种更好的方法。我想出的解决方案是使用我提到的基本 python Socket.IO 客户端库支持的命名空间。
Python
self.mainSocket = SocketIO('localhost', 80)
self.gazeSocket = self.mainSocket.connect('/gaze')
self.gazeSocket.emit('gaze', ...)
连接到注视命名空间。
Node.js
var gaze = io.of('/gaze').on('connection', function (socket)
socket.on('gaze', function (gdata)
gaze.emit('gaze', gdata.toString());
);
);
这只会将接收到的数据发送给连接到凝视命名空间的客户端。
浏览器
var socket = io.connect('http://localhost/gaze');
socket.on('gaze', function (data)
console.log(data);
);
【讨论】:
以上是关于Python 中的代码,在 Node.js 和 Socket.IO 中通信,在 HTML 中呈现的主要内容,如果未能解决你的问题,请参考以下文章
如何清理 Node.js 和 Typescript 中的响应正文