zoukankan      html  css  js  c++  java
  • 视频 | 一步步教你操作websocket通知案例

                                 (文末有福利)

    websocket通知流程 解析

    1. 我们不能保证用户B和用户A都处于连接状态,但是通常情况下,用户B至少是连接状态,用户A不一定跟server保持连接;

    2. 任一用户都不止对应一个客户端。换言之,用户A和用户B都可能打开了多个tab页,对于一个tab页,就会有一个独立的fd标识,我们这里认为任一用户只有最新的fd有效,或者你可以认为用户所有的tab页的连接都有效;

    3. 因为没有用户系统,我们以get传递的参数uid为标识,uid=100视为用户A,uid=101视为用户B;

    4. 我们模拟的tab页包将会包含一个输入内容的文本框、一个输入目标uid的input和一个发送的按钮以满足需求。

    操作流程分析:

    1. 用户A($_GET['uid'] = 100)在某个tab页的输入框输入"回复xxx的内容"字样后,点击发送

    2. 用户B($_GET['uid'] = 101)如果处于连接状态,则alert提醒用户B,他的评论被回复了

    Server

    后端启动:php server.php

    class CommentServer
    {
        private $_serv;
        public $key = '^manks.top&swoole$';
        // 用户id和fd对应的映射,key => value,key是用户的uid,value是用户的fd
        public $user2fd = [];
    
    
        public function __construct()
    {
            $this->_serv = new swoole_websocket_server("127.0.0.1", 9501);
            $this->_serv->set([
                'worker_num' => 1,
                'heartbeat_check_interval' => 60,
                'heartbeat_idle_time' => 125,
            ]);
            $this->_serv->on('open', [$this, 'onOpen']);
            $this->_serv->on('message', [$this, 'onMessage']);
            $this->_serv->on('close', [$this, 'onClose']);
        }
    
    
        /**
         * @param $serv
         * @param $request
         * @return mixed
         */
        public function onOpen($serv, $request)
    {
            // 连接授权
            $accessResult = $this->checkAccess($serv, $request);
            if (!$accessResult) {
                return false;
            }
            // 始终把用户最新的fd跟uid映射在一起
            if (array_key_exists($request->get['uid'], $this->user2fd)) {
                $existFd = $this->user2fd[$request->get['uid']];
                $this->close($existFd, 'uid exists.');
                $this->user2fd[$request->get['uid']] = $request->fd;
                return false;
            } else {
                $this->user2fd[$request->get['uid']] = $request->fd;
            }
        }
    
    
        /**
         * @param $serv
         * @param $frame
         * @return mixed
         */
        public function onMessage($serv, $frame)
    {
            // 校验数据的有效性,我们认为数据被`json_decode`处理之后是数组并且数组的`event`项非空才是有效数据
            // 非有效数据,关闭该连接
            $data = $frame->data;
            $data = json_decode($data, true);
            if (!$data || !is_array($data) || empty($data['event'])) {
                $this->close($frame->fd, 'data format invalidate.');
                return false;
            }
            // 根据数据的`event`项,判断要做什么,`event`映射到当前类具体的某一个方法,方法不存在则关闭连接
            $method = $data['event'];
            if (!method_exists($this, $method)) {
                $this->close($frame->fd, 'event is not exists.');
                return false;
            }
            $this->$method($frame->fd, $data);
        }
        public function onClose($serv, $fd)
    {
            echo "client {$fd} closed.\n";
        }
    
    
        /**
         * 校验客户端连接的合法性,无效的连接不允许连接
         * @param $serv
         * @param $request
         * @return mixed
         */
        public function checkAccess($serv, $request)
    {
            // get不存在或者uid和token有一项不存在,关闭当前连接
            if (!isset($request->get) || !isset($request->get['uid']) || !isset($request->get['token'])) {
                $this->close($request->fd, 'access faild.');
                return false;
            }
            $uid = $request->get['uid'];
            $token = $request->get['token'];
            // 校验token是否正确,无效关闭连接
            if (md5(md5($uid) . $this->key) != $token) {
                $this->close($request->fd, 'token invalidate.');
                return false;
            }
            return true;
        }
    
    
        /**
         * @param $fd
         * @param $message
         * 关闭$fd的连接,并删除该用户的映射
         */
        public function close($fd, $message = '')
    {
            // 关闭连接
            $this->_serv->close($fd);
            // 删除映射关系
            if ($uid = array_search($fd, $this->user2fd)) {
                unset($this->user2fd[$uid]);
            }
        }
    
    
        public function alertTip($fd, $data)
    {
            // 推送目标用户的uid非真或者该uid尚无保存的映射fd,关闭连接
            if (empty($data['toUid']) || !array_key_exists($data['toUid'], $this->user2fd)) {
                $this->close($fd);
                return false;
            }
            $this->push($this->user2fd[$data['toUid']], ['event' => $data['event'], 'msg' => '收到一条新的回复.']);
        }
        /**
         * @param $fd
         * @param $message
         */
        public function push($fd, $message)
    {
            if (!is_array($message)) {
                $message = [$message];
            }
            $message = json_encode($message);
            // push失败,close
            if ($this->_serv->push($fd, $message) == false) {
                $this->close($fd);
            }
        }
    
    
        public function start()
    {
            $this->_serv->start();
        }
    }
    
    
    $server = new CommentServer;
    $server->start();
    

    前端页面 client.php

    <div>
        发送内容:<textarea name="content" id="content" cols="30" rows="10"></textarea><br>
        发送给谁:<input type="text" name="toUid" value="" id="toUid"><br>
        <button onclick="send();">发送</button>
    </div>
    
    
    <script>
        var ws = new WebSocket("ws://127.0.0.1:9501?uid=<?php echo $uid ?>&token=<?php echo $token; ?>");
        ws.onopen = function(event) {
        };
        ws.onmessage = function(event) {
            var data = event.data;
            data = eval("("+data+")");
            if (data.event == 'alertTip') {
                alert(data.msg);
            }
        };
        ws.onclose = function(event) {
            console.log('Client has closed.\n');
        };
    
    
        function send() {
            var obj = document.getElementById('content');
            var content = obj.value;
            var toUid = document.getElementById('toUid').value;
            ws.send('{"event":"alertTip", "toUid": '+toUid+'}');
        }
    </script>
    

    一步一步教你操作

    回复关键字获取资源链接:

    wokerman实战之PHP在线客服:wokerman

  • 相关阅读:
    Power of Matrix(uva11149+矩阵快速幂)
    Training little cats(poj3735,矩阵快速幂)
    233 Matrix(hdu5015 矩阵)
    Contemplation! Algebra(矩阵快速幂,uva10655)
    Another kind of Fibonacci(矩阵)
    欢迎使用CSDN-markdown编辑器
    M斐波那契数列(矩阵快速幂+费马小定理)
    Fibonacci(矩阵)
    常系数线性递推的第n项及前n项和 (Fibonacci数列,矩阵)
    Evolution(矩阵快速幂)zoj2853
  • 原文地址:https://www.cnblogs.com/lxwphp/p/15452912.html
Copyright © 2011-2022 走看看