在PHP服务中使用Websocket

在PHP服务中使用Websocket

WebSocket

WebSocket 协议在2008年诞生,2011年成为国际标准。所有浏览器都已经支持了

它的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种.

为什么需要 WebSocket?

需求是:用户停留页面 15 分钟,且没有任何操作,则弹出登陆窗口,让用户重新登陆.

一般这样的需求实现多为长连接轮询,会有浏览器的卡顿、服务端消耗及不容易维护等问题.

后来发现 websocket 这样的通讯方式,主要有以下优点:

  • 建立在 TCP 协议之上,服务器端的实现比较容易
  • 手时不容易屏蔽,能通过各种 HTTP 代理服务器
  • 数据格式比较轻量,性能开销小,通信高效
  • 可以发送文本,也可以发送二进制数据
  • 没有同源限制,客户端可以与任意服务器通信
  • 协议标识符是ws(如果加密,则为wss),服务器网址就是 URL

目标已经选定,那么如何实现呢?

PHP 已经有非常好用的异步网络通信框架 swoole,节省了自己实现 websocket 服务的时间。我的使用的是 laravel 框架,最终选择了 laravel-swoole 扩展

安装配置

引入 laravel-swoole 扩展包 wiki 。启用 websocket.enabled 及其他相应的配置,通过下面的命名可以非常方便的管理服务:

php artisan swoole:http {start|stop|restart|reload|infos}

修改配置文件中的默认 handler 配置为自定义的类:主要是为了自定义 websocket 的生命周期中的一些回调.

当配置完成后,会在 routes 目录中添加一个名为 websocket.php 的文件。可以非常方便像定义 laravel 路由一样,定义各种事件。例如:

使用

控制器:

public function checkLogin($websocket, $data)
{
    if (empty($data['holding'])) {
        $websocket->emit('message', ['code' => self::HTTP_UNPROCESSABLE_ENTITY, 'message' => "参数错误"]);

        return false;
    }
    $flag = true;
    $step = 1;
    while ($flag) {
        $step++;
        if ( ! $this->validateLoginStatus($data['holding'])) {
            $websocket->emit('message', ['code' => self::HTTP_UNAUTHORIZED, 'message' => "登陆超时"]);
            unset($step);
            $flag = false;
        }else {
            if($step === 1) {
                $websocket->emit('message', ['code' => self::HTTP_OK, 'message' => "success"]);
            }
        }
        sleep(1);
    }
}

前端调用

这里一定要注意数据包的结构,之前就踩了比较多的坑,API docs 才找到正确的结构

var websocket = new WebSocket("ws://127.0.0.1:1215");
    websocket.onopen = function (evt) {
        console.log("已连接websocket服务器");
        // 这里比较关键,通道建立后,可以进非常方便的进行轮询
        setInterval(function() {
           if (websocket.bufferedAmount == 0)
              var data = {"holding": "eyJLQNDqj0y473pCJ6zjMTUyOTk5NzU1MgnVMQ==$d84XkeMCv7umajhMRiU"};
              websocket.send(encodeMessage('loginCheck', data));
        }, 50);
    };
    // 监听消息体
    websocket.onmessage = function (evt) {
        console.log(decodeMessage(evt.data))
    };
    // 监听关闭消息
    websocket.onclose = function (evt) {
        console.log("websocket close");
    };
    //监听连接错误信息
    websocket.onerror = function (evt) {
        console.log(evt);
    };
function decodeMessage(str) {
        return JSON.parse(str.substring(2))[1] || [];
    }

    function encodeMessage(event, data) {
        return JSON.stringify([
            event,
            data
        ])
    }

Swoole扩展安装

因为 swoole 的安装依赖 phpsockets 模块的开启

  • 安装 swoole

中间报错,需要安装以下依赖:

yum -y install gcc postgresql-devel gcc-c++

下载 swoole 扩展源码,安装 安装步骤 进行安装即可

发表评论

邮箱地址不会被公开。

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据