在提出这个问题之前,我通过阅读severel做到了最好 关于SO的问题(标记为棘轮并处理类似问题但是要处理 徒劳无功。我甚至问了一个没有得到关注的问题 因此删除它写另一个(希望更多 全部清除)。
我的最终目标是使用Ratchet构建一对一的私人聊天应用程序。除了我无法向特定用户发送消息外,一切正常。
每个登录用户在访问网站的安全区域时都会连接到websocket服务器:
$(document).ready(function() {
var conn = new WebSocket('ws://localhost:8080');
conn.onopen = function(e) {
console.log("Connection established!");
// Here I need to send the logged in user_id to websocket server
// and get it in onOpen method so that I can index my array
// of connections with user_id instead of
//$connection->ResourceId, I explain more below
};
conn.onmessage = function(e) {
console.log(e.data);
};
});
当用户在聊天框中写入消息时,消息将通过AJAX发送到Web服务器,然后使用ZeroMQ推送到Websocket。在控制器中:
// Persistence of Message(message_id, sender_id, receiver_id, message_text)
.....
$context = new \ZMQContext();
$socket = $context->getSocket(\ZMQ::SOCKET_PUSH, 'my pusher');
$socket->connect("tcp://localhost:5555");
$pushData = array(
'receiver_id' => $receiver_id,
'sender_id' => $user->getId(),
'message' => $message->getMessageText(),
);
$socket->send(json_encode($pushData));
所以最后,我的websocket服务器能够知道哪个是使用JSON的接收者的id。但他怎么知道该用户的连接是什么?换句话说,我需要将websocket连接存储在由用户id索引的数组中。
<?php
namespace RealTime;
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
use Ratchet\Wamp\WampServerInterface;
class Pusher implements WampServerInterface, MessageComponentInterface{
private $clients;
public function onOpen(ConnectionInterface $conn) {
$this->clients[$conn->resourceId] = $conn;
// I need here to get the user_id received from browser while opening connection
}
public function onMessageEntry($entry) {
$entryData = json_decode($entry, true);
//This is not what I need (It sends to all users in array)
foreach ($this->clients as $key => $client) {
$client->send($entryData['message']);
}
}
public function onMessage(ConnectionInterface $from, $msg) {
echo $msg;
}
}
websocket服务器:
<?php
require dirname(__DIR__) . '/vendor/autoload.php';
use RealTime\Pusher;
$loop = React\EventLoop\Factory::create();
$pusher = new 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, 'onMessageEntry'));
$webSock = new React\Socket\Server($loop);
$webSock->listen(8080, '0.0.0.0');
$webServer = new Ratchet\Server\IoServer(
new Ratchet\Http\HttpServer(
new Ratchet\WebSocket\WsServer(
new Ratchet\Wamp\WampServer(
$pusher
)
)
),
$webSock
);
$loop->run();
?>
问题:
如何在打开连接时从客户端发送登录的user_id
。我需要在websocket服务器中获取值,以便我可以用它来索引我的客户端数组($client[user_id]=$conn
而不是$client[recourceId]=$conn
)。我尝试了javascript函数send
,但我不知道从哪里接收发送的数据(即使onMessage
也没有打印任何内容)。
为什么onMessage
方法甚至没有执行MessageComponentInterface
已实施(是因为我有onMessageEntry
方法+ $pull->on('message', array($pusher, 'onMessageEntry'));
代码行吗?
谢谢。
答案 0 :(得分:3)
我被&#34; whiteletters问到了空白纸&#34;为这个问题做出贡献(抱歉迟到)。
实际上在我最后一次尝试时,我放弃了PHP WebSocket(使这项工作变得如此复杂)并开始使用带有nodeJS的SocketIO解决了我的整个问题并且可以给我一个功能简单的聊天系统。
答案 1 :(得分:2)
这是我发现的,欢迎提出任何改进此解决方案的建议。
可以使用棘轮SessionProvider。这将需要使用其中一个Symfony Custom Session处理程序。我在以下代码中使用了PdoSessionHandler
。
<?php
require dirname(__DIR__) . '/vendor/autoload.php';
use YourDirectory\Pusher;
use Symfony\Component\HttpFoundation\Session\Storage\Handler;
use \Ratchet\Session\SessionProvider;
$pusher = new Pusher;
$pdo = new PDO('mysql:host=localhost;dbname=community', 'root', null);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
//This info is related to you db
$dbOptions = array(
'db_table' => 'session',
'db_id_col' => 'sess_id',
'db_data_col' => 'sess_data',
'db_time_col' => 'sess_time',);
$loop = \React\EventLoop\Factory::create();
$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, 'onMessageEntry'));
$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\Http\HttpServer(
new Ratchet\WebSocket\WsServer(
new SessionProvider(
new Ratchet\Wamp\WampServer(
$pusher
),new Handler\PdoSessionHandler($pdo,$dbOptions)
)
)
),
$webSock
);
$loop->run();
?>
然后我的存根类将成为:
public function onOpen(ConnectionInterface $conn) {
$this->clients[$conn->Session->get('current_user_id')] = $conn;
}
public function onMessageEntry($entry) {
$entryData = json_decode($entry, true);
$ReceiverConnection=$this->clients[$entryData['receiver_id']];
$ReceiverConnection->send($entryData['message']);
}
但之前,我已将用户ID添加到Web服务器中的会话中(在返回初始页面的控制器中)
$user = $this->getUser();
$request->getSession()->set('current_user_id', $user->getId());
PS:
迁移到PdoSessionHandler可以通过实现this(Symfony)来完成。
我仍然无法回答2但是所有可以放置onMessage
的逻辑现在都转移到了onMessageEntry
,这恰好满足了他们的需求。
答案 2 :(得分:2)
作为在clientConnection
和他的ID
之间建立关联的替代方法,您需要在打开与websocket服务器的连接后使用websockets发送消息,此消息将包含您的用户ID将使用它通过数组中的ID
索引他的连接对象。
对于第二个问题,因为我知道默认的websocket实现与pubsub
协议无法正常工作,你需要使用websocket库,我建议使用AutobahnJS
它是一个很好的websocket库,具有很多很棒的功能。