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


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

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

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

 19
Author: jlafay, 2012-04-07

6 answers

Предложение, по-видимому, состоит в том, чтобы общаться с узлом через интерфейс HTTP, как и любой другой клиент. Вы можете общаться с узлом через HTTP, используя cURL в php

См.: http://groups.google.com/group/socket_io/browse_thread/thread/74a76896d2b72ccc/216933a076ac2595?pli=1

В частности, смотрите Этот пост от Мэтта Парди

Я столкнулся с аналогичной проблемой, желая информировать пользователей о новой заметке, добавленной к ошибке, и подобных уведомлениях, которые на самом деле может быть эффективно отправлен только с PHP на мой сервер узла. То, что я сделал , следует (извиняюсь, если при отправке все будет искажено и неформатировано , если это произойдет, я буду рад вставить код в другое место): Во-первых, вам нужно будет использовать 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 (это порт, на котором работает сервер моего узла , а порт - сокет.сервер ввода-вывода подключается к). Это отправляет запрос HTTP POST с закодированным полем post. Это все довольно стандартные завитки.

В вашем узловом приложении у вас, вероятно, есть что-то вроде:

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"). Затем код сервера создания становится:

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) {
        ...
}

И т.д. и т.п. Я не тестировал это некоторое время, и на самом деле этот блок кода был закомментирован на моем узловом сервере, поэтому я надеюсь, что то, что я вставил здесь , работает - в целом эта концепция доказана, и я думаю, что она будет работать для вас. В любом случае, просто хотел убедиться, что ты знаешь, что прошло уже несколько месяцев, так что Я не совсем понимаю, почему я это прокомментировал. Код, который я написал, потребовал небольшого исследования - например, установки заголовка "Ожидать:" в завитке -- и я был очень взволнован, когда это наконец сработало. Дайте мне знать, если вам понадобится какая-либо дополнительная помощь.

Лучший,

Мэтт Парди

 23
Author: Matt Esch, 2012-11-01 12:12:16

Немного поздно, но вы могли бы общаться со своим узловым клиентом с помощью механизма 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)

Когда вы говорите о масштабируемости, вам нужно подумать об архитектуре вашей инфраструктуры и ваших особые потребности, но вот быстрый ответ : Я без проблем использовал вариант этого механизма в приложении с высоким трафиком в режиме реального времени, но вот с чем вам следует быть осторожным:

  1. Redis PUB/SUB не является системой очередей, это означает, что если процесс вашего узла выйдет из строя, все сообщения, которые были отправлены во время его работы, будут потеряны.

  2. Если у вас более 1 подписчика на издателя, все они получат одно и то же сообщение и обработают его, будьте будьте осторожны с этим, если у вас больше, чем процесс узла, прослушивающий одну и ту же базу данных redis, обрабатывающую вашу логику в реальном времени (хотя есть простые способы обойти это)

Самое приятное в этой системе то, что вам не нужно ничего добавлять в существующую инфраструктуру и вы можете начать работу немедленно, она очень быстрая и ведет себя точно так же, как HTTP-сервер.

Вот ваши альтернативы для более масштабируемых вариантов:

  1. Использование автономного быстрого сервер очереди обмена сообщениями (ActiveMQ, RabbitMQ, beanstalkd...) сервер для обработки вашей логики обмена сообщениями между php и узлом, они, как правило, работают быстро, но по мере увеличения нагрузки вы теряете немного производительности и должны поддерживать/масштабировать свои серверы обмена сообщениями и заботиться о дублировании в разных регионах, что нелегко и приятно (в зависимости от того, что вам нравится делать).
  2. Использование размещенного сервера очереди сообщений (IronMQ, SQS...) Некоторые из них (IronMQ) довольно быстры и будут великолепны для вашего варианта использования, но внесите некоторую (незначительную) сложность в вашу кодовую базу.
  3. Построение очереди обмена сообщениями с помощью Redis с серверами кластерных узлов: https://davidmarquis.wordpress.com/2013/01/03/reliable-delivery-message-queues-with-redis/
  4. Использование HTTP внутри VPN для связи с серверами узлов. Как только вы увидите, что ваш трафик растет, вам нужно будет только сбалансировать нагрузку на серверы узлов и добавить столько серверов без состояния, сколько вам нужно, и отправлять почтовые сообщения для этой загрузки балансировщик.

Смысл этого длительного редактирования в том, что волшебного масштабируемого решения не существует, вам нужно взвесить свои варианты и посмотреть, какой из них лучше всего подходит для вашего варианта использования. На мой взгляд, если вы начинаете создавать свою первую итерацию сейчас, выберите любой удобный для вас вариант, напишите очень чистый код, и когда вы начнете масштабировать, его будет очень легко изменить, вот что я сделал:)

 15
Author: user1128896, 2015-08-29 09:41:18

Я обнаружил, что такую проблему можно решить просто с помощью фреймворка Express. Предположим, php отправляет сообщение json на сервер узла, и сервер отвечает "ок".

В 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-скрипт может отправлять сообщения пользователям определенной комнаты чата.

Https://github.com/lteu/chat


Мое личное впечатление о подходе Redis: Громоздкий. Вы нужно запустить Apache, NodeJS и Redis, три сервера вместе в одном. И механизм PubSub сильно отличается от механизма испускания socket.io , поэтому вам нужно посмотреть, совместим ли он с вашим существующим кодом.

 2
Author: tong, 2015-08-19 21:03:07

Шаг 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 );
});
 1
Author: Clay, 2015-08-09 07:20:16

Мы делаем это с помощью очереди сообщений. Существует множество решений, таких как radis (https://github.com/mranney/node_redis ) или 0mq (http://zeromq.org /). Это позволяет отправлять сообщения подписчикам (например, с php на nodejs).

 0
Author: Vazgen Manukyan, 2015-02-20 16:35:52

Я искал действительно простой способ заставить PHP отправлять сокет.сообщение ввода-вывода клиентам.

Для этого не требуется никаких дополнительных библиотек PHP - он просто использует сокеты.

Вместо того, чтобы пытаться подключиться к интерфейсу websocket, как многие другие решения, просто подключитесь к node.js сервер и используйте .on('data') для получения сообщения.

Затем socket.io может переслать его клиентам.

Обнаружьте соединение с вашего PHP-сервера в Node.js как будто это:

//You might have something like this - just included to show object setup
var app = express();
var server = http.createServer(app);
var io = require('socket.io').listen(server);

server.on("connection", function(s) {
    //If connection is from our server (localhost)
    if(s.remoteAddress == "::ffff:127.0.0.1") {
        s.on('data', function(buf) {
            var js = JSON.parse(buf);
            io.emit(js.msg,js.data); //Send the msg to socket.io clients
        });
    }
});

Вот невероятно простой php-код - я завернул его в функцию - вы можете придумать что-нибудь получше.

Обратите внимание, что 8080 является портом для моего Node.js сервер - возможно, вы захотите изменить.

function sio_message($message, $data) {
    $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
    $result = socket_connect($socket, '127.0.0.1', 8080);
    if(!$result) {
        die('cannot connect '.socket_strerror(socket_last_error()).PHP_EOL);
    }
    $bytes = socket_write($socket, json_encode(Array("msg" => $message, "data" => $data)));
    socket_close($socket);
}

Вы можете использовать его следующим образом:

sio_message("chat message","Hello from PHP!");

Вы также можете отправлять массивы, которые преобразуются в json и передаются клиентам.

sio_message("DataUpdate",Array("Data1" => "something", "Data2" => "something else"));

Это полезный способ "доверять" тому, что ваши клиенты получают законные сообщения от сервер.

Вы также можете использовать PHP для передачи обновлений базы данных без того, чтобы сотни клиентов запрашивали базу данных.

Жаль, что я не нашел это раньше - надеюсь, это поможет!

 0
Author: user1274820, 2018-04-17 00:11:08