我正在尝试构建一个系统,用户可以在建立与websocket服务器的连接时订阅类别,然后他将开始接收该类别的更新。到目前为止,我已经与Ratchet合作,我能够向所有连接的客户发送消息,但问题是我不想向所有客户发送消息我只想将消息发送给有客户的客户订阅了发送消息的特定类别。
PHP代码
Chat.php
<?php
namespace MyApp;
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
class Chat implements MessageComponentInterface
{
protected $clients;
public function __construct()
{
$this->clients = new \SplObjectStorage;
}
public function onOpen(ConnectionInterface $conn)
{
$this->clients->attach($conn);
}
public function onMessage(ConnectionInterface $conn, $msg)
{
foreach ($this->clients as $client)
{
if($conn !== $client)
$client->send($msg);
}
}
public function onClose(ConnectionInterface $conn)
{
$this->clients->detach($conn);
}
public function onError(ConnectionInterface $conn, \Exception $e)
{
echo "An error has occurred: {$e->getMessage()}\n";
$conn->close();
}
}
?>
server.php
<?php
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use MyApp\Chat;
require dirname(__DIR__) . '/Ratchet/vendor/autoload.php';
$server = IoServer::factory(
new HttpServer(
new WsServer(
new Chat()
)
),
8080
);
$server->run();
?>
客户端js代码
<script type="text/javascript">
var conn = new WebSocket('ws://localhost:8080');
conn.onopen = function(e) {
console.log("Connection established!");
};
conn.onmessage = function(e) {
console.log(e.data);
};
</script>
答案 0 :(得分:24)
基本上你需要一种将数据发送到WebSocket的语法,我建议使用JSON对象来执行此操作。在您的WebSocket类中,您需要一个名为subscriptions
的局部变量和一个名为users
的局部变量。
<?php
namespace MyApp;
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
class Chat implements MessageComponentInterface
{
protected $clients;
private $subscriptions;
private $users;
public function __construct()
{
$this->clients = new \SplObjectStorage;
$this->subscriptions = [];
$this->users = [];
}
public function onOpen(ConnectionInterface $conn)
{
$this->clients->attach($conn);
$this->users[$conn->resourceId] = $conn;
}
public function onMessage(ConnectionInterface $conn, $msg)
{
$data = json_decode($msg);
switch ($data->command) {
case "subscribe":
$this->subscriptions[$conn->resourceId] = $data->channel;
break;
case "message":
if (isset($this->subscriptions[$conn->resourceId])) {
$target = $this->subscriptions[$conn->resourceId];
foreach ($this->subscriptions as $id=>$channel) {
if ($channel == $target && $id != $conn->resourceId) {
$this->users[$id]->send($data->message);
}
}
}
}
}
public function onClose(ConnectionInterface $conn)
{
$this->clients->detach($conn);
unset($this->users[$conn->resourceId]);
unset($this->subscriptions[$conn->resourceId]);
}
public function onError(ConnectionInterface $conn, \Exception $e)
{
echo "An error has occurred: {$e->getMessage()}\n";
$conn->close();
}
}
?>
与之相关的javascript看起来有点像这样
<script type="text/javascript">
var conn = new WebSocket('ws://localhost:8080');
conn.onopen = function(e) {
console.log("Connection established!");
};
conn.onmessage = function(e) {
console.log(e.data);
};
function subscribe(channel) {
conn.send(JSON.stringify({command: "subscribe", channel: channel}));
}
function sendMessage(msg) {
conn.send(JSON.stringify({command: "message", message: msg}));
}
</script>
注意:此代码未经测试我是根据我对Ratchet的经验动态编写的。祝你好运:)
答案 1 :(得分:1)
// SOCKET VARIABLE DECLARATION
var mySocket;
// MESSAGE
const socketMessageListener = function(event) {
var data = JSON.parse(event.data);
};
// OPEN SOCKET
const socketOpenListener = function(event) {
console.log('Connected');
};
// CLOSE OR DISCONNECT SOCKET
const socketCloseListener = function(event) {
if (mySocket) {
console.error('Disconnected.');
}
mySocket = new WebSocket('ws://localhost:8080');
mySocket.addEventListener('open', socketOpenListener);
mySocket.addEventListener('message', socketMessageListener);
mySocket.addEventListener('close', socketCloseListener);
};
// CALL THE LISTENER
socketCloseListener();
function sendMessage(data) {
mySocket.send(JSON.stringify(data));
}
user3049006我在研究中发现了此代码,以确保在失败后重试连接以保持连接持久。
答案 2 :(得分:1)
好的,现在我分享我的经验。您可以发送令牌并将此令牌插入数据库的onOpen(server.php)中。您可以在用户登录时插入聊天令牌。每次用户登录时,都会生成并更新新令牌。 现在,使用此令牌在onOpen连接中查找用户ID。
var conn = new WebSocket('ws://172.16.23.26:8080?token=<?php echo !empty($_SESSION['user']['token']) ? $_SESSION['user']['token'] : ''; ?>');
conn.onopen = function(e) {
console.log("Connection established!");
};
现在Server.php
public function onOpen(ConnectionInterface $conn) {
$this->clients->attach($conn);
$querystring = $conn->httpRequest->getUri()->getQuery();
parse_str($querystring,$queryarray);
//Get UserID By Chat Token
$objUser = new \users;
$objUser->setLoginToken($queryarray['token']);
$GetUserInfo = $objUser->getUserByToken();
echo "New connection! ({$conn->resourceId})\n";
//save Chat Connection
// Insert the new connection with the user ID to Match to later if user ID in Table Then Update IT with a new connection
}
现在您的连接已建立,然后向特定用户发送消息
客户端发送带有已接收ID和消息的USerID
$("#conversation").on('click', '#ButtionID', function () {
var userId = $("#userId").val();
var msg = $("#msg").val();
var receiverId = $("#receiverId").val();
if ( userId != null && msg != null ){
var data = {
userId: userId,
msg: msg,
receiverId: receiverId
};
conn.send(JSON.stringify(data));
$("#msg").val("");
}
});
服务器端
public function onMessage(ConnectionInterface $from, $msg) {
$numRecv = count($this->clients) - 1;
echo sprintf('Connection %d sending message "%s" to %d other connection%s' . "\n",$from->resourceId, $msg, $numRecv, $numRecv == 1 ? '' : 's');
$data = json_decode($msg, true);
echo $data['userId'];
echo $data['msg'];
echo $data['receiverId'];
// Save User ID receiver Id message in table
//Now Get Chat Connection by user id By Table Which is saved onOpen function
$UptGetChatConnection = $objChatroom->getChatConnectionUserID($data['receiverId']);
$ReciId = $UptGetChatConnection[0]['ConnectionID'];
foreach ($this->clients as $client) {
if ($from == $client) {
$data['from'] = "Me";
$data['fromname'] = 5;
} else {
$data['from'] = $user['name'];
$data['fromname'] = 6;
}
echo $client->resourceId;
echo $ReciId."\n";
if($client->resourceId == $ReciId || $from == $client){
$client->send(json_encode($data));
}
}
}
现在消息已通过连接ID发送,不广播,仅发送特定消息 用户