web-dev-qa-db-ja.com

特定のユーザーにメッセージを送信する方法Ratchet PHP Websocket

ユーザーが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>
9
user3049006

基本的に、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>

注:このコードはテストされていません。ラチェットでの経験からその場で作成しました。幸運を :)

24
MarshallOfSound
// 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失敗した場合に接続を永続的に保つために、このコードを調査で見つけました。接続を再試行してください。

1
Rodrigo Santana

わかりました、今私は私の経験を共有しています。トークンを送信して、このトークンをデータベースの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で送信され、特定のユーザーのみを送信します。

0
Anurag