从 PHP 向 Node.js 发送消息
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10048978/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Sending messages from PHP to Node.js
提问by Sparky1
How to send messages from php to node.js? I have a linux server running php and node.js.
如何将消息从 php 发送到 node.js?我有一个运行 php 和 node.js 的 linux 服务器。
When a user completes a transaction (via php), I'd like send a message from php to node.js. Node will then update the client via a socket connection.
当用户完成交易(通过 php)时,我想从 php 向 node.js 发送一条消息。然后节点将通过套接字连接更新客户端。
What's a good way to send a small amount of data from php to node.js without defeating the performance of node.js?
在不破坏 node.js 性能的情况下,将少量数据从 php 发送到 node.js 的好方法是什么?
回答by Matt Esch
The suggestion seems to be to talk to node through the HTTP interface, just as any other client does. You can talk to node via HTTP using cURL in php
建议似乎是通过 HTTP 接口与节点通信,就像任何其他客户端一样。您可以使用 php 中的 cURL 通过 HTTP 与节点通信
请参阅:http: //groups.google.com/group/socket_io/browse_thread/thread/74a76896d2b72ccc/216933a076ac2595?pli=1
In particular, see this post from Matt Pardee
特别是,请参阅 Matt Pardee 的这篇文章
I faced a similar problem with wanting to keep users informed of a new note added on to a bug, and similar notifications that could really only be effectively sent from PHP to my Node server. What I did follows (apologies if this gets all garbled and unformatted in sending, if it does, I'd be happy to paste the code somewhere else): First, you'll need to use cURL from PHP. I wrote a function for my class like this:
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); }You'll notice that I send the cURL request on the same server since both PHP and NodeJS are running there, your mileage may vary. The port I set this code to connect to is 8001 (this is the port my Node server is running on, and the port the socket.io server connects to). This sends a HTTP POST request with the post field encoded. This is all pretty standard cURL stuff.
In your Node app you probably have something like:
var server = http.createServer(function(req, res) {}); server.listen(8001); var io = io.listen(server, { transports: ['websocket', 'flashsocket', 'xhr-polling'] }); ...well what we'll do here is expand on the http.createServer part, to listen for connections coming from our local host ("127.0.0.1"). The createServer code then becomes:
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); }); } } });From there you can implement your handleServerNotice function..
function handleServerNotice(data) { ... }etc etc. I haven't tested this in a while, and in fact that code block was commented out on my node server, so I hope what I've pasted here works - in general this concept is proven and I think it'll work for you. Anyway just wanted to be sure you knew it's been a few months so I'm not sure exactly why I commented out. The code I wrote took a little research -- like setting the 'Expect:' header in cURL -- and I was pretty excited when it finally worked. Let me know if you need any additional help.
Best,
Matt Pardee
我遇到了类似的问题,希望让用户了解添加到错误中的新注释,以及实际上只能有效地从 PHP 发送到我的 Node 服务器的类似通知。我所做的如下(抱歉,如果发送时出现乱码和未格式化,如果确实如此,我很乐意将代码粘贴到其他地方):首先,您需要使用 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 服务器连接到的端口)。这会发送一个带有 post 字段编码的 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:”标头——当它最终起作用时,我非常兴奋。如果您需要任何其他帮助,请告诉我。
最好的事物,
马特·帕迪
回答by Rakan Nimer
A bit late, but you could communicate with your node client using the Redis Pub/Sub mechanism in a very simple and effective way. All you need to do is install redis on your server.
有点晚了,但是您可以使用 Redis Pub/Sub 机制以一种非常简单有效的方式与您的节点客户端进行通信。您需要做的就是在您的服务器上安装 redis。
On the php side, initialize Redis then publish a message
在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);
On the node.js side
在 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
})
Is this scalable ?(In response to @mohan-singh)
这是可扩展的吗?(回应@mohan-singh)
When talking about scalability you need to think about your infrastructure's architecture and your particular needs but here's a quick answer : I've been using a variant of this mechanism on a high traffic real-time application without problems but here's what you should be careful about:
在谈论可扩展性时,您需要考虑基础设施的架构和您的特定需求,但这里有一个快速答案:我一直在高流量实时应用程序上使用这种机制的变体,没有问题,但这是您应该注意的事项:
Redis PUB/SUB is not a queuing system, that means if your node process goes down all the messages that were sent WHILE it is down will be lost.
If you have more than 1 subscriber to the publisher they will all receive the same message and handle it, be careful about that if you have more than a node process listening to the same redis db handling your real-time logic (There are easy ways to go around this though)
Redis PUB/SUB 不是排队系统,这意味着如果您的节点进程宕机,所有在它宕机时发送的消息都将丢失。
如果您有超过 1 个订阅者订阅发布者,他们都会收到相同的消息并处理它,如果您有多个节点进程在侦听相同的 redis db 处理您的实时逻辑,请注意这一点(有简单的方法不过要解决这个问题)
The nice thing about this system is that you don't need to add anything to your existing infrastructure and can get started immediately, it's very fast and it behaves exactly like an HTTP server.
这个系统的好处是你不需要向现有的基础设施添加任何东西,并且可以立即开始使用,它非常快,而且它的行为与 HTTP 服务器完全一样。
Here are your alternatives for more scalable options:
以下是更多可扩展选项的替代方案:
- Using a self-hosted fast messaging queue server (ActiveMQ, RabbitMQ, beanstalkd ... ) server to handle your messaging logic between php and node, these tend to be fast but as the load increases you lose a bit of performance, and have to maintain/scale your messaging servers, and take care of duplication across regions which is not an easy and enjoyable thing (depending on what you enjoy doing).
- Using a hosted messaging queue server (IronMQ, SQS...) Some of these(IronMQ) are pretty fast and will be great for your use case but introduce some (minor) complexity to your codebase.
- Building a messaging queue with Redis with clustered node servers : https://davidmarquis.wordpress.com/2013/01/03/reliable-delivery-message-queues-with-redis/
- Using HTTP inside a VPN to communicate with node servers. Once you see your traffic spiking you will only need to load-balance your node servers and add as much stateless servers as you need and send POST messages to that load balancer.
- 使用自托管的快速消息队列服务器(ActiveMQ、RabbitMQ、beanstalkd ...)服务器来处理 php 和节点之间的消息传递逻辑,这些往往很快,但随着负载的增加,你会失去一些性能,并且必须维护/扩展您的消息服务器,并处理跨区域的重复工作,这不是一件容易和愉快的事情(取决于您喜欢做什么)。
- 使用托管消息队列服务器(IronMQ、SQS...)其中一些(IronMQ)速度非常快,非常适合您的用例,但会给您的代码库带来一些(次要)复杂性。
- 使用带有集群节点服务器的 Redis 构建消息队列:https: //davidmarquis.wordpress.com/2013/01/03/reliable-delivery-message-queues-with-redis/
- 在 VPN 内使用 HTTP 与节点服务器通信。一旦您看到流量激增,您只需要对节点服务器进行负载平衡,并根据需要添加尽可能多的无状态服务器,并将 POST 消息发送到该负载平衡器。
The point of this lengthy edit is that there is no such thing as a magic scalable solution, you need to weigh your options and see which one works the best for your use case. In my opinion, if you're starting to build your first iteration now, choose any option that you're comfortable with, write very clean code and when you start scaling it will be very easy to change, this is what I've done :)
这个冗长的编辑的重点是,不存在神奇的可扩展解决方案,您需要权衡您的选择,看看哪一个最适合您的用例。在我看来,如果你现在开始构建你的第一个迭代,选择任何你觉得舒服的选项,编写非常干净的代码,当你开始扩展时,它会很容易改变,这就是我所做的:)
回答by tong
I found such problem can be solved simply by using the Express framework. Let's suppose php sends a json message to the node server and the server replies with ok.
我发现这样的问题可以通过使用 Express 框架来解决。假设 php 向节点服务器发送 json 消息,服务器回复 ok。
In app.js
在 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);
});
In test.php
在 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);
?>
Here we have also a more detailed example where a php script could drop a message to the users of a specific chat room.
这里我们还有一个更详细的示例,其中 php 脚本可以向特定聊天室的用户发送消息。
My personal impression about Redis approach: Cumbersome. You need to run Apache, nodeJS and Redis, three servers together in the same. And PubSub mechanism is quite different from the emit of socket.io, so you need to see if it is compatible with your existing code.
我对 Redis 方法的个人印象:繁琐。您需要同时运行 Apache、nodeJS 和 Redis,三台服务器。而且PubSub机制和socket.io的emit大不相同,所以你需要看看它是否与你现有的代码兼容。
回答by user1274820
I was looking for a really simple way to get PHP to send a socket.io message to clients.
我一直在寻找一种非常简单的方法来让 PHP 向客户端发送 socket.io 消息。
This doesn't require any additional PHP libraries - it just uses sockets.
这不需要任何额外的 PHP 库——它只使用套接字。
Instead of trying to connect to the websocket interface like so many other solutions, just connect to the node.js server and use .on('data')to receive the message.
不要像许多其他解决方案一样尝试连接到 websocket 接口,只需连接到 node.js 服务器并使用它.on('data')来接收消息。
Then, socket.iocan forward it along to clients.
然后,socket.io可以将其转发给客户。
Detect a connection from your PHP server in Node.js like this:
在 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
});
}
});
Here's the incredibly simple php code - I wrapped it in a function - you may come up with something better.
这是非常简单的 php 代码 - 我将它封装在一个函数中 - 你可能会想出更好的东西。
Note that 8080is the port to my Node.js server - you may want to change.
请注意,这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);
}
You can use it like this:
你可以这样使用它:
sio_message("chat message","Hello from PHP!");
sio_message("chat message","Hello from PHP!");
You can also send arrays which are converted to json and passed along to clients.
您还可以发送转换为 json 并传递给客户端的数组。
sio_message("DataUpdate",Array("Data1" => "something", "Data2" => "something else"));
sio_message("DataUpdate",Array("Data1" => "something", "Data2" => "something else"));
This is a useful way to "trust" that your clients are getting legitimate messages from the server.
这是一种“信任”您的客户端正在从服务器获取合法消息的有用方法。
You can also have PHP pass along database updates without having hundreds of clients query the database.
您还可以让 PHP 传递数据库更新,而无需数百个客户端查询数据库。
I wish I'd found this sooner - hope this helps!
我希望我能早点找到这个 - 希望这会有所帮助!
回答by Vazgen Manukyan
We do it by using message queue. There are a lot of solutions like radis (https://github.com/mranney/node_redis) or 0mq (http://zeromq.org/). It allows to send a message to subscribers (for example from php to nodejs).
我们通过使用消息队列来做到这一点。有很多解决方案,如 radis ( https://github.com/mranney/node_redis) 或 0mq ( http://zeromq.org/)。它允许向订阅者发送消息(例如从 php 到 nodejs)。
回答by Clay
Step 1. Get the PHP Emitter: https://github.com/rase-/socket.io-php-emitter
步骤 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>');
add this to your index.js:
将此添加到您的 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);
});
});
add something like this to your index.html
将这样的内容添加到您的 index.html
socket.on('new question', function(msg) {
$('body').append( msg );
});

