Отправка сообщений с PHP на Node.js
Как отправлять сообщения с php на node.js? У меня есть сервер linux, на котором запущены php и node.js.
Когда пользователь завершает транзакцию (через php), я хотел бы отправить сообщение от php до node.js. Node затем обновит клиент через соединение сокета.
Какой хороший способ отправить небольшой объем данных с php на node.js, не нарушая производительность node.js?
Ответы
Ответ 1
Похоже, что это предложение поговорить с node через HTTP-интерфейс, как это делает любой другой клиент. Вы можете поговорить с node через HTTP, используя cURL в php
Смотрите: http://groups.google.com/group/socket_io/browse_thread/thread/74a76896d2b72ccc/216933a076ac2595?pli=1
В частности, см. этот пост от Matt Pardee
Я столкнулся с аналогичной проблемой, желая, чтобы пользователи информировали о новом примечание, добавленное к ошибке, и аналогичные уведомления, которые могут действительно только эффективно отправляется из PHP на мой сервер node. Что я сделал (извинения, если это все искажается и не форматируется в отправка, если это так, я был бы счастлив вставить код в другое место): Во-первых, вам нужно будет использовать cURL из PHP. Я написал функцию для моего класс следующим образом:
function notifyNode($type, $project_id, $from_user, $data) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http://127.0.0.1');
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect:'));
curl_setopt($ch, CURLOPT_PORT, 8001);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 2);
curl_setopt($ch, CURLOPT_POST, true);
$pf = array('f' => $type, 'pid' => $project_id, 'user_from' => $from_user,
'data' => array());
foreach($data as $k => $v) {
$pf['data'][$k] = $v;
}
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($pf));
curl_exec($ch);
curl_close($ch);
}
Вы заметите, что я отправляю запрос cURL на тот же сервер, поскольку и PHP, и NodeJS работают там, ваш пробег может отличаться. Порт Я установил этот код для подключения к 8001 (это порт my node server и порт, к которому подключен сервер socket.io). Эта отправляет HTTP-запрос POST с полем после поля. Это все довольно стандартный материал cURL.
В вашем приложении node у вас есть что-то вроде:
var server = http.createServer(function(req, res) {});
server.listen(8001);
var io = io.listen(server, { transports: ['websocket', 'flashsocket', 'xhr-polling'] });
...
Хорошо, что мы сделаем здесь, мы расширим часть http.createServer, чтобы прослушивать соединения, поступающие с нашего локального хоста ( "127.0.0.1" ). Затем создается код createServer:
var server = http.createServer(function(req, res) {
// Check for notices from PHP
if(res.socket.remoteAddress == '127.0.0.1') {
if(req.method == 'POST') {
// The server is trying to send us an activity message
var form = new formidable.IncomingForm();
form.parse(req, function(err, fields, files) {
res.writeHead(200, [[ "Content-Type", "text/plain"]
, ["Content-Length", 0]
]);
res.write('');
res.end();
//sys.puts(sys.inspect({fields: fields}, true, 4));
handleServerNotice(fields);
});
}
}
});
Оттуда вы можете реализовать свою функцию handleServerNotice.
function handleServerNotice(data) {
...
}
и т.д. Я не тестировал это некоторое время, и на самом деле этот блок кода был прокомментирован на моем сервере node, поэтому я надеюсь, что я здесь вставил работает - в целом эта концепция доказана, и я думаю, что она будет работать для вы. В любом случае, просто хотелось убедиться, что вы знали, что это было несколько месяцев, поэтому Я точно не знаю, почему я прокомментировал это. Код, который я написал, небольшое исследование - например, настройка заголовка "Ожидание:" в cURL - и я был очень взволнован, когда он, наконец, работал. Дайте мне знать, если вам нужно дополнительная помощь.
Бест,
Мэтт Парди
Ответ 2
Немного поздно, но вы можете общаться с вашим клиентом node, используя механизм Redis Pub/Sub очень простым и эффективным способом. Все, что вам нужно сделать, это установить redis на свой сервер.
На стороне php инициализируйте Redis, затем опубликуйте сообщение
$purchase_info = json_encode(array('user_id' =>$user_id,
'purchase_information'=>array('item'=>'book','price'=>'2$'));
$this->redis->publish('transaction_completed', $purchase_info);
На стороне node.js
var redis = require('redis');
var purchase_listener = redis.createClient();
purchase_listener.subscribe('transaction_completed');
purchase_listener.on('message', function(channel, message){
var purchase_data = JSON.parse(message);
user_id = purchase_data.user_id;
purchase_info = purchase_data.purchase_information;
// Process the data
// And send confirmation to your client via a socket connection
})
Является ли это масштабируемым? (В ответ на @mohan-singh)
Говоря о масштабируемости, вам нужно подумать о своей инфраструктурной архитектуре и ваших конкретных потребностях, но здесь быстрый ответ:
Я использую вариант этого механизма для приложения с высоким трафиком в реальном времени без проблем, но здесь вы должны быть осторожны:
-
Redis PUB/SUB не является системой очередей, это означает, что если ваш node процесс опускается, все сообщения, которые были отправлены WHILE, будут потеряны.
-
Если у вас более одного подписчика издателя, они все получат одно и то же сообщение и обработают его, будьте осторожны, если у вас есть более чем node процесс, прослушивающий тот же redis db, обрабатывающий ваш реальный (есть простые способы обойти это, хотя)
Приятная вещь в этой системе заключается в том, что вам не нужно добавлять что-либо в существующую инфраструктуру и ее можно начать сразу, очень быстро и вести себя точно так же, как HTTP-сервер.
Вот ваши альтернативы для более масштабируемых параметров:
- Используя сервер собственной очереди быстрого обмена сообщениями (ActiveMQ, RabbitMQ, beanstalkd...) для обработки вашей логики обмена сообщениями между php и node, они имеют тенденцию быть быстрыми, но по мере увеличения нагрузки вы теряете немного производительности, а также поддерживать/масштабировать серверы обмена сообщениями и заботиться о дублировании в регионах, что нелегко и приятно (в зависимости от того, что вам нравится делать).
- Использование сервера очереди размещенных сообщений (IronMQ, SQS...) Некоторые из них (IronMQ) довольно быстр и будут полезны для вашего варианта использования, но вносят некоторую (небольшую) сложность в вашу кодовую базу.
- Создание очереди сообщений с помощью Redis с кластерными серверами node: https://davidmarquis.wordpress.com/2013/01/03/reliable-delivery-message-queues-with-redis/
- Использование HTTP внутри VPN для связи с серверами node. После того, как вы увидели свой трафик, вам нужно будет только балансировать ваши серверы node и добавить столько серверов без сохранения состояния, сколько вам нужно, и отправлять сообщения POST этому балансировщику нагрузки.
Точка этого длинного редактирования заключается в том, что нет такой вещи, как волшебное масштабируемое решение, вам нужно взвесить свои варианты и посмотреть, какой из них лучше всего подходит для вашего случая использования.
На мой взгляд, если вы сейчас начинаете строить свою первую итерацию, выберите любой вариант, с которым вам удобно, напишите очень чистый код, и когда вы начнете масштабирование, это будет очень легко изменить, вот что я сделал:)
Ответ 3
Я нашел, что такая проблема может быть решена просто с помощью платформы Express.
Предположим, что php отправляет json-сообщение серверу node, и сервер отвечает с помощью ok.
В app.js
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var bodyParser = require('body-parser')
app.use(bodyParser.json());
app.post('/phpcallback', function(req, res) {
var content = req.body;
console.log('message received from php: ' + content.msg);
//to-do: forward the message to the connected nodes.
res.end('ok');
});
http.listen(8080, function(){
var addr = http.address();
console.log('app listening on ' + addr.address + ':' + addr.port);
});
В test.php
<?php
$data = array("name" => "Robot", "msg" => "Hi guys, I'm a PHP bot !");
$data_string = json_encode($data);
$ch = curl_init('http://localhost:8080/phpcallback');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json',
'Content-Length: ' . strlen($data_string))
);
echo curl_exec($ch)."\n";
curl_close($ch);
?>
Здесь также приведен более подробный пример, в котором php script может отбросить сообщение пользователям определенной комнаты чата.
https://github.com/lteu/chat
Мое личное впечатление о подходе Редиса: громоздко. Вам нужно запустить Apache, nodeJS и Redis, три сервера вместе. Механизм PubSub сильно отличается от источника socket.io, поэтому вам нужно убедиться, что он совместим с вашим существующим кодом.
Ответ 4
Шаг 1. Получить PHP-эмиттер:
https://github.com/rase-/socket.io-php-emitter
$redis = new \Redis(); // Using the Redis extension provided client
$redis->connect('127.0.0.1', '6379');
$emitter = new SocketIO\Emitter($redis);
$emitter->emit('new question', '<b>h<br/>tml</b>');
добавьте это в свой index.js:
var redis = require('socket.io-redis');
io.adapter(redis({ host: 'localhost', port: 6379 }));
io.on('connection', function(socket){
socket.on('new question', function(msg) {
io.emit('new question', msg);
});
});
добавьте что-то подобное в ваш index.html
socket.on('new question', function(msg) {
$('body').append( msg );
});
Ответ 5
Мы делаем это, используя очередь сообщений. Существует множество решений, таких как radis (https://github.com/mranney/node_redis) или 0mq (http://zeromq.org/). Он позволяет отправлять сообщения подписчикам (например, от php до nodejs).