如何将消息从 php 发送到 node.js?我有一个运行 php 和 node.js 的 linux 服务器。
当用户完成交易(通过 php)时,我想从 php 向 node.js 发送一条消息。然后节点将通过套接字连接更新客户端。
在不破坏node.js性能的情况下,将少量数据从php发送到node.js的好方法是什么?
该建议似乎是通过 HTTP 接口与节点对话,就像任何其他客户端一样。您可以在 php 中使用 cURL 通过 HTTP 与节点通信
特别是,请参阅 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(这是我的 Node 服务器正在运行的端口,也是 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) { ... }
等等等等。我已经有一段时间没有测试过了,事实上,我的节点服务器上的代码块被注释掉了,所以我希望我在这里粘贴的内容有效——总的来说,这个概念得到了证明,我认为它会为你工作。无论如何,只是想确定你知道这已经几个月了,所以我不确定我为什么要评论出来。我编写的代码进行了一些研究——比如在 cURL 中设置 'Expect:' 标头——当它终于奏效时我非常兴奋。如果您需要任何其他帮助,请告诉我。
最好的,
马特·帕迪
有点晚了,但是您可以使用 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 不是一个排队系统,这意味着如果你的节点进程宕机,所有在宕机时发送的消息都会丢失。
如果您有超过 1 个发布者的订阅者,他们都会收到相同的消息并处理它,如果您有多个节点进程侦听同一个 redis db 处理您的实时逻辑,请注意这一点(有简单的方法不过要绕过这个)
这个系统的好处是你不需要在你现有的基础设施中添加任何东西,并且可以立即开始,它非常快,它的行为就像一个 HTTP 服务器。
以下是更多可扩展选项的替代方案:
这个冗长编辑的要点是,没有神奇的可扩展解决方案,您需要权衡您的选择,看看哪一个最适合您的用例。在我看来,如果你现在开始构建你的第一个迭代,选择任何你喜欢的选项,编写非常干净的代码,当你开始扩展时,它会很容易改变,这就是我所做的:)
我发现这样的问题可以简单地通过使用 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 脚本可以向特定聊天室的用户发送消息。
我个人对 Redis 方法的印象:繁琐。您需要同时运行 Apache、nodeJS 和 Redis,三台服务器一起运行。而且PubSub机制和socket.io的emit有很大的不同,所以你需要看看它是否和你现有的代码兼容。
我一直在寻找一种非常简单的方法来让 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"));
这是一种“信任”您的客户端从服务器获取合法消息的有用方法。
您还可以让 PHP 传递数据库更新,而无需数百个客户端查询数据库。
我希望我能早点找到这个 - 希望这会有所帮助!
我们通过使用消息队列来做到这一点。有很多解决方案,例如 radis ( https://github.com/mranney/node_redis ) 或 0mq ( http://zeromq.org/ )。它允许向订阅者发送消息(例如从 php 到 nodejs)。
步骤 1. 获取 PHP Emitter: 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 );
});