注意:这与使用的这个问题不同
MessageComponentInterface
。我正在使用WampServerInterface
,所以这个问题专门与那部分有关。我需要一个带有代码示例和解释的答案,因为我可以看到这对未来的其他人有帮助。
尝试为单个用户循环推送
我正在使用 Ratchet 和 ZeroMQ 的 WAMP 部分,目前我有一个推送集成教程的工作版本。
我正在尝试执行以下操作:
- zeromq 服务器已启动并运行,准备记录订阅者和取消订阅者
- 用户通过 websocket 协议在浏览器中连接
- 启动一个循环,将数据发送给请求它的特定用户
- 当用户断开连接时,该用户数据的循环将停止
我有第 (1) 和 (2) 点有效,但是我遇到的问题是第三点:
首先:如何仅向每个特定用户发送数据?广播将其发送给每个人,除非“主题”最终可能是个人用户 ID?
其次:我有一个很大的安全问题。如果我要从客户端发送想要订阅的用户 ID,这似乎是我需要的,那么用户只需将变量更改为另一个用户的 ID,然后返回他们的数据。
第三:我必须运行一个单独的 php 脚本,其中包含 zeromq 的代码来启动实际的循环。我不确定这是最好的方法,我宁愿让它完全在代码库中工作,而不是单独的 php 文件。这是我需要整理的一个主要领域。
以下代码显示了我目前拥有的内容。
刚刚从控制台运行的服务器
我从字面上输入php bin/push-server.php
来运行它。订阅和取消订阅将输出到此终端以进行调试。
$loop = React\EventLoop\Factory::create();
$pusher = Pusher;
$context = new React\ZMQ\Context($loop);
$pull = $context->getSocket(ZMQ::SOCKET_PULL);
$pull->bind('tcp://127.0.0.1:5555');
$pull->on('message', array($pusher, 'onMessage'));
$webSock = new React\Socket\Server($loop);
$webSock->listen(8080, '0.0.0.0'); // Binding to 0.0.0.0 means remotes can connect
$webServer = new Ratchet\Server\IoServer(
new Ratchet\WebSocket\WsServer(
new Ratchet\Wamp\WampServer(
$pusher
)
),
$webSock
);
$loop->run();
通过 websocket 发送数据的 Pusher
我省略了无用的东西,专注于onMessage()
andonSubscribe()
方法。
public function onSubscribe(ConnectionInterface $conn, $topic)
{
$subject = $topic->getId();
$ip = $conn->remoteAddress;
if (!array_key_exists($subject, $this->subscribedTopics))
{
$this->subscribedTopics[$subject] = $topic;
}
$this->clients[] = $conn->resourceId;
echo sprintf("New Connection: %s" . PHP_EOL, $conn->remoteAddress);
}
public function onMessage($entry) {
$entryData = json_decode($entry, true);
var_dump($entryData);
if (!array_key_exists($entryData['topic'], $this->subscribedTopics)) {
return;
}
$topic = $this->subscribedTopics[$entryData['topic']];
// This sends out everything to multiple users, not what I want!!
// I can't send() to individual connections from here I don't think :S
$topic->broadcast($entryData);
}
在循环中开始使用上述 Pusher 代码的脚本
这是我的问题 - 这是一个单独的 php 文件,希望将来可以集成到其他代码中,但目前我不确定如何正确使用它。我是否从会话中获取用户 ID?我仍然需要从客户端发送它......
// Thought sessions might work here but they don't work for subscription
session_start();
$userId = $_SESSION['userId'];
$loop = React\EventLoop\Factory::create();
$context = new ZMQContext();
$socket = $context->getSocket(ZMQ::SOCKET_PUSH, 'my pusher');
$socket->connect("tcp://localhost:5555");
$i = 0;
$loop->addPeriodicTimer(4, function() use ($socket, $loop, $userId, &$i) {
$entryData = array(
'topic' => 'subscriptionTopicHere',
'userId' => $userId
);
$i++;
// So it doesn't go on infinitely if run from browser
if ($i >= 3)
{
$loop->stop();
}
// Send stuff to the queue
$socket->send(json_encode($entryData));
});
最后,要订阅的客户端js
$(document).ready(function() {
var conn = new ab.Session(
'ws://localhost:8080'
, function() {
conn.subscribe('topicHere', function(topic, data) {
console.log(topic);
console.log(data);
});
}
, function() {
console.warn('WebSocket connection closed');
}
, {
'skipSubprotocolCheck': true
}
);
});
结论
以上是有效的,但我真的需要弄清楚以下几点:
如何向个人用户发送个人消息?当他们访问在 JS 中启动 websocket 连接的页面时,我是否也应该启动将内容推入 PHP 队列的脚本(zeromq)?这就是我目前正在手动执行的操作,只是感觉不对。
从 JS 订阅用户时,从会话中获取用户 ID 并从客户端发送是不安全的。这可能是伪造的。请告诉我有一个更简单的方法,如果是这样,怎么做?