2012-04-06 19 views
18

¿Cómo enviar mensajes de php a node.js? Tengo un servidor Linux ejecutando php y node.js.Enviando mensajes de PHP a Node.js

Cuando un usuario completa una transacción (a través de php), me gustaría enviar un mensaje de php a node.js. Nodo luego actualizará el cliente a través de una conexión de socket.

¿Cuál es una buena manera de enviar una pequeña cantidad de datos de php a node.js sin dañar el rendimiento de node.js?

Respuesta

22

La sugerencia parece ser hablar con el nodo a través de la interfaz HTTP, al igual que cualquier otro cliente. Usted puede hablar con el nodo a través de HTTP usando cURL en PHP

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

En particular, vea esta entrada de Matt Pardee

me enfrentaba a un problema similar con el deseo de mantener informados a los usuarios de un nueva nota agregada a un error, y notificaciones similares que realmente podrían realmente ser enviadas efectivamente desde PHP a mi servidor Node. Lo que hice a continuación (disculpas si esto se distorsiona y no está formateado en enviando, si lo hace, estaría feliz de pegar el código en otro lugar): Primero, necesitarás usar cURL de PHP. Escribí una función para mi clase así:

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); 
} 

Se dará cuenta de que puedo enviar la solicitud cURL en el mismo servidor desde tanto PHP y NodeJS está ejecutando allí, su experiencia puede variar. El puerto donde configuré este código para conectarme es 8001 (este es el puerto en el que se ejecuta mi servidor Node y el puerto al que se conecta el servidor socket.io). Este envía una solicitud HTTP POST con el campo de publicación codificado. Esto es todo bastante cURL estándar.

En su aplicación Nodo es probable que tenga algo como:

var server = http.createServer(function(req, res) {}); 
server.listen(8001); 
var io = io.listen(server, { transports: ['websocket', 'flashsocket', 'xhr-polling'] }); 

... 

bien lo que vamos a hacer aquí es ampliar en la parte http.createServer, a escuchar las conexiones que vienen de nuestro host local ("127,0 .0.1 "). El código createServer entonces es:

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);     
      }); 
     } 
    } 
}); 

Desde allí se puede poner en práctica su función handleServerNotice ..

function handleServerNotice(data) { 
     ... 
} 

, etc, etc no he probado esto en un tiempo, y en el hecho de que el bloque de código se comentó en mi servidor de nodo, así que espero que lo que he pegado aquí funcione - en general este concepto está probado y creo que funcionará para usted . De todas formas, solo quería asegurarme de que sabían que habían pasado unos meses, así que No estoy seguro de por qué lo comenté. El código que escribí tomó una pequeña investigación de , como configurar el encabezado 'Expect:' en cURL, y I estaba muy emocionado cuando finalmente funcionó. Avíseme si necesita alguna ayuda adicional de .

mejor,

Matt Pardee

+0

¡Buen enlace! Muchas gracias por su ayuda. – Sparky1

+2

Si bien esto puede responder teóricamente a la pregunta, nos gustaría que incluya las partes esenciales del artículo vinculado en su respuesta, y proporcione el [enlace de referencia] (http://meta.stackexchange.com/q/8259). Si no se hace eso, la respuesta corre peligro a causa de la podredumbre del enlace. – Kev

+0

de acuerdo. La información importante ahora reside en la respuesta. No más riesgo de putrefacción. –

15

Un poco tarde, pero se puede comunicar con su cliente mediante el nodo Redis Pub/Sub mecanismo de una manera muy sencilla y eficaz. Todo lo que necesita hacer es instalar redis en su servidor.

En el lado php, inicializar Redis luego publicar un mensaje

$purchase_info = json_encode(array('user_id' =>$user_id, 
     'purchase_information'=>array('item'=>'book','price'=>'2$')); 

$this->redis->publish('transaction_completed', $purchase_info); 

En el lado 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 
}) 

Es esto escalable? (En respuesta a @ Mohan-Singh)

Cuando se habla de escalabilidad que necesita para pensar en la arquitectura de su infraestructura y sus necesidades particulares, pero esto es una respuesta rápida: He estado usando una variante de este mecanismo en un alto el tráfico de aplicaciones en tiempo real y sin problemas, pero esto es lo que debe tener cuidado con:

  1. Redis PUB/SUB no es un sistema de colas, que significa que si su proceso de nodo se desactiva todos los mensajes que se enviaron Si bien es abajo se perderá.

  2. Si tiene más de 1 suscriptor del editor, todos recibirán el mismo mensaje y lo manejarán, tenga cuidado al respecto si tiene más de un proceso de nodo escuchando el mismo redis db manejando su lógica en tiempo real (Hay maneras fáciles para dar la vuelta esto, sin embargo)

lo bueno de este sistema es que no es necesario añadir nada a su infraestructura existente y puede comenzar de inmediato, es muy rápido y se comporta exactamente como un servidor HTTP.

Éstos son sus alternativas para las opciones más escalables:

  1. Uso de un servidor de cola de mensajería rápida auto-organizada (ActiveMQ, RabbitMQ, beanstalkd ...) servidor para manejar la lógica de mensajería entre php y nodo, estos tienden a ser rápidos, pero a medida que aumenta la carga, pierde un poco de rendimiento y tiene que mantener/escalar sus servidores de mensajería y ocuparse de la duplicación entre regiones, lo que no es fácil ni agradable (dependiendo de lo que disfrute).
  2. Uso de un servidor de cola de mensajería alojado (IronMQ, SQS ...) Algunos de estos (IronMQ) son bastante rápidos y serán geniales para su caso de uso pero presentarán una complejidad (menor) a su base de código.
  3. Creación de una cola de mensajes con Redis con servidores de nodos en clúster: https://davidmarquis.wordpress.com/2013/01/03/reliable-delivery-message-queues-with-redis/
  4. Uso de HTTP dentro de una VPN para comunicarse con los servidores de nodo. Una vez que vea el aumento de tráfico, solo tendrá que equilibrar la carga de los servidores de su nodo y agregar tantos servidores sin estado como necesite y enviar mensajes POST a ese equilibrador de carga.

El objetivo de esta larga edición es que no existe una solución escalable mágica, debe sopesar sus opciones y ver cuál funciona mejor para su caso de uso. En mi opinión, si está comenzando a construir su primera iteración ahora, elija cualquier opción con la que se sienta cómodo, escriba un código muy limpio y cuando empiece a escalar será muy fácil cambiarlo, esto es lo que hice hecho :)

+2

Gracias, muy útil – Eric

+0

¿Qué pasa con la aplicación de alto tráfico. ¿Este mecanismo es vendible? Me gustaría usar redis y laravel para mi aplicación en tiempo real. Por favor, hágame saber si es exitoso. –

+1

He editado mi respuesta para responder a su pregunta. – user1128896

1

Paso 1. Obtener el PHP Emisor: 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>'); 

Agregar a su 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); 
    }); 
}); 

añadir algo como esto a su index.html

socket.on('new question', function(msg) { 
    $('body').append(msg); 
}); 
2

Encontré que tal problema se puede resolver simplemente usando el marco Express . Supongamos que php envía un mensaje json al servidor de nodo y el servidor responde con ok.

En 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); 
}); 

En prueba.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); 

?> 

Aquí también tenemos un ejemplo más detallado, donde un script php podría caer un mensaje a los usuarios de una sala de chat específica .

https://github.com/lteu/chat


Mi impresión personal sobre el enfoque Redis: engorroso. Necesita ejecutar Apache, nodeJS y Redis, tres servidores juntos en el mismo. Y el mecanismo de PubSub es bastante diferente del de socket.io, por lo que necesita ver si es compatible con su código existente.