Подтвердить что ты не робот

Отправка сообщений с PHP на Node.js

Как отправлять сообщения с php на node.js? У меня есть сервер linux, на котором запущены php и node.js.

Когда пользователь завершает транзакцию (через php), я хотел бы отправить сообщение от php до node.js. Node затем обновит клиент через соединение сокета.

Какой хороший способ отправить небольшой объем данных с php на node.js, не нарушая производительность node.js?

4b9b3361

Ответ 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).