【问题标题】:Best Practice for Multiple Subscribe Methods in React / Ratchet / ZMQReact / Ratchet / ZMQ 中多个订阅方法的最佳实践
【发布时间】:2015-04-08 17:11:23
【问题描述】:

我尝试构建一个小的实时 websocket 用例,用户可以在其中登录并查看所有其他登录的用户,在新用户登录或现有用户注销时收到通知。

对于这种情况,当用户登录或注销时,我在我的 UserController 中使用 ZMQ PUSH Socket。

用户控制器

public function login() {

        //... here is the auth code, model call etc...

        $aUserData = array();// user data comes from the database with username, logintime, etc....

        $context = new \ZMQContext();
        $oSocket = $context->getSocket(\ZMQ::SOCKET_PUSH, 'USER_LOGIN_PUSHER'); // use persistent_id
        if($oSocket instanceof \ZMQSocket) {

            $oSocket->connect("tcp://127.0.0.1:5555"); //
            $oSocket->send(json_encode($aUserData));
        }
    }

    public function logout() {
        //... here is the logout code, model call etc ....

        $aUserData = array();// user data comes from the SESSION with username, logintime, etc....

        $context = new \ZMQContext();
        $oSocket = $context->getSocket(\ZMQ::SOCKET_PUSH, 'USER_LOGOUT_PUSHER'); // use persistent_id
        if($oSocket instanceof \ZMQSocket) {

            $oSocket->connect("tcp://127.0.0.1:5555"); //
            $oSocket->send(json_encode($aUserData));
        }
    }

然后我有一个像 Ratchet 文档中一样的 Pusher 类:link

在这个类中,有两种方法:onUserLoginonUserLogout,当然还有其他的东西,比如

onSubscribe、onOpen、onPublish

用户信息推送器

 public function onUserLogin($aUserData) {
        //var_dump("onUserLogin");
        $sUserData = json_decode($aUserData, true);

        $oTopic = $this->subscribedTopics["user_login"];

        if($oTopic instanceof Topic) {
            $oTopic->broadcast($sUserData);
        } else {
            return;
        }
    }

    public function onUserLogout($aUserData) {
        //var_dump("onUserLogout");
        $entryData = json_decode($aUserData, true);

        $oTopic = $this->subscribedTopics["user_logout"];

        if($oTopic instanceof Topic) {
            $oTopic->broadcast($entryData);
        } else {
            return;
        }
    }

最后一块是 WampServer/WsServer/HttpServer,它有一个 Loop 监听传入的连接。还有我的ZMQ PULL socket

RatchetServerConsole

public function start_server() {

        $oPusher = new UserInformationPusher();

        $oLoop = \React\EventLoop\Factory::create();
        $oZMQContext = new \React\ZMQ\Context($oLoop);
        $oPullSocket = $oZMQContext->getSocket(\ZMQ::SOCKET_PULL);

        $oPullSocket->bind('tcp://127.0.0.1:5555'); // Binding to 127.0.0.1 means the only client that can connect is itself
        $oPullSocket->on('message', array($oPusher, 'onUserLogin'));
        $oPullSocket->on('message', array($oPusher, 'onUserLogout'));


        $oMemcache = new \Memcache();
        $oMemcache->connect('127.0.0.1', 11211);
        $oMemcacheHandler = new Handler\MemcacheSessionHandler($oMemcache);

        $oSession = new SessionProvider(
            new \Ratchet\Wamp\WampServer(
                $oPusher
            ),
            $oMemcacheHandler
        );

        //$this->Output->info("Server start initiation with memcache!...");
        $webSock = new \React\Socket\Server($oLoop);
        $webSock->listen(8080, '0.0.0.0'); // Binding to 0.0.0.0 means remotes can connect
        $oServer = new \Ratchet\Server\IoServer(
            new \Ratchet\Http\HttpServer(
                new \Ratchet\WebSocket\WsServer(
                    $oSession
                )
            ),
            $webSock
        );
        $this->Output->info("Server started ");
        $oLoop->run();

    }

在此示例中,来自 login() 或 logout() 的调用将始终调用这两个方法(onUserLogin 和 onUserLogout)。 我找不到一些文档,这些文档描述了我可以在 on($event, callable $listener) 方法中使用哪些事件,有人有链接/知识库吗? 检查 UserController 中哪个方法被触发的最佳方法是什么?

  • 我可以在 Controller 中的 $sUserData 中添加一些信息,然后在 Pusher 中进行检查
  • 我可以将另一个套接字绑定到不同的端口(例如 5554 用于 PULL 和 PUSH)并在这个端口上使用 on() 方法
  • 我可以...是否有其他最佳做法可以解决此问题?

不需要客户端代码,因为它可以正常工作

【问题讨论】:

标签: php websocket zeromq ratchet reactphp


【解决方案1】:

在您的 RatchetServerConsole 中,

删除,

$oPullSocket->on('message', array($oPusher, 'onUserLogin'));
$oPullSocket->on('message', array($oPusher, 'onUserLogout'));

添加,

$oPullSocket->on('message', array($oPusher, 'onUserActionBroadcast'));

.

在您的UserInformationPusher中,

删除 onUserLogin() 和 onUserLogout()。

添加,

public function onUserActionBroadcast($aUserData)
{
    $entryData = json_decode($aUserData, true);

    // If the lookup topic object isn't set there is no one to publish to
    if (!array_key_exists($entryData['topic'], $this->subscribedTopics)) {
        return;
    }

    $topic = $this->subscribedTopics[$entryData['topic']];

    unset($entryData['topic']);

    // re-send the data to all the clients subscribed to that category
    $topic->broadcast($entryData);
}

.

你的 UserController(在 $aUserData 中添加主题),

public function login() {

    //... here is the auth code, model call etc...

    $aUserData = array();// user data comes from the database with username, logintime, etc....

    $aUserData['topic'] = 'USER_LOGIN'; // add the topic name

    $context = new \ZMQContext();
    $oSocket = $context->getSocket(\ZMQ::SOCKET_PUSH, 'my pusher'); // use persistent_id
    if($oSocket instanceof \ZMQSocket) {

        $oSocket->connect("tcp://127.0.0.1:5555"); //
        $oSocket->send(json_encode($aUserData));
    }
}

public function logout() {
    //... here is the logout code, model call etc ....

    $aUserData = array();// user data comes from the SESSION with username, logintime, etc....

    $aUserData['topic'] = 'USER_LOGOUT'; // add the topic name

    $context = new \ZMQContext();
    $oSocket = $context->getSocket(\ZMQ::SOCKET_PUSH, 'my pusher'); // use persistent_id
    if($oSocket instanceof \ZMQSocket) {

        $oSocket->connect("tcp://127.0.0.1:5555"); //
        $oSocket->send(json_encode($aUserData));
    }
}

.

终于在你的查看文件中,

<script>
var conn = new ab.Session('ws://yourdomain.dev:9000', // Add the correct domain and port here
    function() {
        conn.subscribe('USER_LOGIN', function(topic, data) {                
            console.log(topic);
            console.log(data);
        });

       conn.subscribe('USER_LOGOUT', function(topic, data) {                
            console.log(topic);
            console.log(data);
        });
    },
    function() {
        console.warn('WebSocket connection closed');
    },
    {'skipSubprotocolCheck': true}
);
</script>

.

注意:基本思想是在 pusher 类中使用单个广播函数。

【讨论】:

    【解决方案2】:

    在 websockets 中使用 PHP 最佳实践进行了一个月的密集处理后,我从我的方法更改为 PHP 后端的Crossbar.iovoryx/Thruway 和前端的Autobahn|JS。 所有这些组件都支持WAMP V2 Websocket Standard 并且能够满足我的要求。

    如果有一些请求,我可以使用上述组件发布解决上述问题的方法。

    【讨论】:

    • 请发布您的解决方案,如果不使用 WAMP V2 就不可能吗?
    • 我知道这篇文章已经很久了,但是你能不能把你如何处理“检查来自 UserController 的哪个方法被触发”。我也在寻找 - 我可以在 on($event, callable $listener) 方法中使用哪些事件。如果还不算太晚,请发布解决方案。谢谢。
    猜你喜欢
    • 2022-01-01
    • 2018-04-19
    • 2023-04-08
    • 1970-01-01
    • 2015-03-11
    • 1970-01-01
    • 1970-01-01
    • 2020-02-04
    • 2020-11-18
    相关资源
    最近更新 更多