Код в Python, обмениваться данными в Node.js и Socket.IO, присутствующих в HTML
У вас есть python script 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());
});
});
Client
<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>
Вопрос
Это здорово и все, но что, если вы ищете ту же коммуникационную мощь HTML- Node.js, которую предоставляет Socket.IO, но вместо этого между Node.js и Python? Как бы Вы это сделали? Там нет веб-сервера, поэтому Socket.IO не имеет большого смысла, и общение по голым TCP не обеспечивает такую же мощность/элегантность. Как достичь полнодуплексной связи между Node.js и Python?
![enter image description here]()
Обновление Я ответил на свой вопрос, но я открыт для альтернативного подхода. RPC не совсем делает то, что я хочу.
Ответы
Ответ 1
Я использовал библиотеку, вдохновленную этим question, чтобы превратить diagnosis.py
в клиент Socket.IO. Таким образом, я могу передавать данные реального времени на сервер Node.js Socket.IO:
socketIO.emit('gaze', ...)
И затем запустите socket.broadcast.emit
, чтобы передать данные всем клиентам Socket.IO(браузер и diagnosis.py
).
RPC, вероятно, является более стандартным подходом к кросс-языковой разработке, но я считаю, что это слишком сложно сделать, когда цель заключается в обмене данными. Он также не поддерживает выведенный из строя ввод-вывод из коробки.
Обновление в январе 2013 года Поскольку socket.broadcast.emit
генерирует много ненужного трафика, я попытался найти лучший способ сделать это. Решение, которое я придумал, заключается в использовании пространств имен, поддерживаемых базовой клиентской библиотекой python Socket.IO, о которой я упоминал.
Python
self.mainSocket = SocketIO('localhost', 80)
self.gazeSocket = self.mainSocket.connect('/gaze')
self.gazeSocket.emit('gaze', ...)
Чтобы подключиться к пространству имен gaze.
Node.js
var gaze = io.of('/gaze').on('connection', function (socket) {
socket.on('gaze', function (gdata) {
gaze.emit('gaze', gdata.toString());
});
});
Это испускает данные, полученные только для клиентов, подключенных к пространству имен gaze.
Браузер
var socket = io.connect('http://localhost/gaze');
socket.on('gaze', function (data) {
console.log(data);
});
Ответ 2
Apache Thrift - довольно классный способ написать код RPC между всеми основными языками. Вы пишете общую спецификацию Thrift, объявляющую типы и службы, а затем генератор кода создает привязки для ваших желаемых языков. Вы можете использовать apis для вызова методов между вашими базами node и python.
В более общем подходе низкого уровня ZeroMQ является библиотекой очереди сообщений, которая также поддерживает все основные языки. При этом вы можете создать собственное решение для того, как вы хотите общаться (а не только просто RPC). Он имеет шаблоны для запроса/ответа, push/pull, pub/sub и пары. Это дает вам достаточно инструментов для создания масштабируемой системы любого типа.
Я использовал оба варианта, и они являются отличными решениями.
Как очень грубый пример, спецификация 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
Python
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);
Ответ 3
Вы можете посмотреть на некоторые системы обмена сообщениями, такие как 0mq http://www.zeromq.org/
Ответ 4
Если вы просто ищете что-то, что дает вам простой протокол поверх сокетов, вам не нужно иметь дело с буферизацией и разграничением сообщений и всего этого, двумя очевидными выборами (в зависимости от того, данные, которые вы пытаетесь отправить) являются netstrings и 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);
}