注:これは、を利用するこの質問と同じではありません。私は代わりに使用しているので、この質問は特にその部分に関係しています。これは将来他の人に役立つことがわかるので、コード例と説明を含む回答が必要です。
MessageComponentInterface
WampServerInterface
個々のユーザーに対してループ プッシュを試みる
私は Ratchet と ZeroMQ の WAMP 部分を使用しています。現在、プッシュ統合チュートリアルの作業バージョンがあります。
私は次のことを実行しようとしています:
- zeromq サーバーが稼働中で、サブスクライバーとアンサブスクライバーをログに記録する準備ができています
- ユーザーは、websocket プロトコルを介してブラウザーで接続します
- 要求した特定のユーザーにデータを送信するループが開始されます
- ユーザーが切断すると、そのユーザーのデータのループが停止します
ポイント(1)と(2)が機能していますが、問題は3番目のものにあります:
まず、特定のユーザーにのみデータを送信するにはどうすればよいですか? おそらく「トピック」が個々のユーザーIDになる場合を除いて、ブロードキャストはそれを全員に送信しますか?
第二に、セキュリティ上の大きな問題があります。クライアント側からサブスクライブしたいユーザー ID を送信する必要があるように思われる場合、ユーザーは変数を別のユーザーの ID に変更するだけで、そのデータが代わりに返されます。
第三に、実際のループを開始するには、zeromq のコードを含む別の php スクリプトを実行する必要があります。これが最善の方法であるかどうかはわかりませんが、個別の 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 経由でデータを送信するプッシャー
無駄なことは省き、メソッドに集中しましonMessage()
たonSubscribe()
。
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);
}
ループ内で上記のプッシャー コードの使用を開始するスクリプト
これは私の問題です。これは、将来的に他のコードに統合される可能性がある別の 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 を取得してクライアント側から送信するのは安全ではありません。これは偽造される可能性があります。もっと簡単な方法があれば教えてください。