将消息从PHP发送到Node.js

时间:2012-04-06 20:37:40

标签: php node.js

如何从php发送消息到node.js?我有一个运行php和node.js的linux服务器。

当用户完成一个事务(通过php)时,我想从php向node.js发送一条消息。然后,节点将通过套接字连接更新客户端。

在不破坏node.js性能的情况下,从php向node.js发送少量数据的好方法是什么?

6 个答案:

答案 0 :(得分:24)

建议似乎是通过HTTP接口与节点通信,就像任何其他客户端一样。您可以使用php中的cURL通过HTTP与节点通信

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

特别参见Matt Pardee的这篇文章

  

我遇到了一个类似的问题,希望让用户知道一个新的   注意添加到一个错误,以及可能真的类似的通知   只能从PHP有效地发送到我的节点服务器。我做了什么   如果这一切都变成了乱码并且未格式化,那就道歉了   发送,如果是的话,我很乐意将代码粘贴到其他地方):   首先,您需要使用PHP中的cURL。我为我写了一个函数   像这样的课:

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(这是我的节点服务器的端口   正在运行,socket.io服务器连接的端口)。这个   发送带有post字段编码的HTTP POST请求。这是所有的了   相当标准的cURL东西。

     

在您的节点应用中,您可能会遇到以下内容:

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

等等我有一段时间没有测试过这个,实际上是代码块   在我的节点服务器上被注释掉了,所以我希望我在这里粘贴了什么   工作 - 一般来说,这个概念已得到证实,我认为它会起作用   您。无论如何只是想确定你知道它已经有几个月了   我不确定为什么我评论出来。我写的代码拿了一个   很少的研究 - 比如在cURL中设置'Expect:'标题 - 和我一样   当它终于奏效时非常兴奋。如果您需要,请告诉我   额外的帮助。

     

最佳,

     

Matt Pardee

答案 1 :(得分: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数据库处理您的实时,请注意这一点逻辑(尽管有很简单的方法可以解决这个问题)

  3. 这个系统的优点在于,您不需要在现有基础架构中添加任何内容,并且可以立即启动,速度非常快,而且行为与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. 在VPN中使用HTTP与节点服务器通信。一旦看到流量激增,您只需要对节点服务器进行负载平衡,并根据需要添加尽可能多的无状态服务器,并将POST消息发送到该负载均衡器。
    5. 这个冗长的编辑的重点是没有神奇的可扩展解决方案,你需要权衡你的选项,看看哪一个最适合你的用例。 在我看来,如果你现在开始构建你的第一个迭代,选择你喜欢的任何选项,编写非常干净的代码,当你开始扩展它将很容易改变,这就是什么我已经完成了:)

答案 2 :(得分:3)

我发现只需使用Express框架就可以解决这样的问题。 假设php向节点服务器发送json消息,服务器回复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脚本可以将消息发送给特定聊天室的用户。

https://github.com/lteu/chat

我对Redis方法的个人印象:繁琐。您需要同时运行Apache,nodeJS和Redis,三台服务器。并且PubSub机制与socket.io的发出完全不同,因此您需要查看它是否与您现有的代码兼容。

答案 3 :(得分:1)

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

答案 4 :(得分:0)

我们通过使用消息队列来实现。有许多解决方案,如radis(https://github.com/mranney/node_redis)或0mq(http://zeromq.org/)。它允许向订阅者发送消息(例如从php到nodejs)。

答案 5 :(得分:0)

我一直在寻找一种让PHP向客户端发送socket.io消息的简单方法。

这不需要任何额外的PHP库 - 它只使用套接字。

不要像许多其他解决方案那样尝试连接到websocket接口,只需连接到node.js服务器并使用.on('data')接收消息。

然后,socket.io可以将它转发给客户。

在Node.js中检测来自PHP服务器的连接,如下所示:

//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"));

这是一种有用的方式来信任&#34;您的客户从服务器获取合法消息。

您还可以让PHP传递数据库更新,而无需数百个客户端查询数据库。

我希望我能早点发现这一点 - 希望这有帮助!