swoole 安装及双协议使用(数据库采用pdo连接池)

//swoole  安装  

/* * git clone https://github.com/swoole/swoole-src.git * * cd swoole-src * * phpize * * ./configure --with-php-config=/www/server/php/71/bin/php-config --enable-openssl * * make && sudo make install * * php --ini -----/www/server/php/71/etc/php.ini * * /www/server/php/71/etc/php.ini 中加入 extension=swoole.so * * 重启php * */
<?php

declare(strict_types=1);

use Swoole\Coroutine;
use Swoole\Database\PDOConfig;
use Swoole\Database\PDOPool;
use Swoole\Runtime;
use JPush\Client as JPush;      //激光推送

class WebSocketServer{

    protected $serv = null;             //WebSocket
    protected $server = null;           //tcp 监听
    protected $pool = null;             //pdo链接池
    protected $host = '0.0.0.0';       //监听对应外网的IP 0.0.0.0监听所有ip
    protected $port = 9306;             //端口号
    protected $server_port = 9307;     //监听端口号
    protected $Push = null;            //苹果 / 安卓  推送

    public function __construct(){

        //创建websocket服务器对象
        $this->serv = new Swoole\WebSocket\Server($this->host, $this->port,SWOOLE_PROCESS);  

        //设置参数
        //如果业务代码是全异步 IO 的,worker_num设置为 CPU 核数的 1-4 倍最合理
        //如果业务代码为同步 IO,worker_num需要根据请求响应时间和系统负载来调整,例如:100-500
        //假设每个进程占用 40M 内存,100 个进程就需要占用 4G 内存
        $this->serv->set(array(
            'worker_num' => 8,                      //设置启动的worker进程数。【默认值:CPU 核数】
            'max_request' => 100000,                //设置每个worker进程的最大任务数。【默认值:0 即不会退出进程】
            'daemonize' => false,                  //开启守护进程化【默认值:0】
            'heartbeat_idle_time'      => 600,     // 表示一个连接如果60秒内未向服务器发送任何数据,此连接将被强制关闭
            'heartbeat_check_interval' => 60,     // 表示每20秒遍历一次
            'tcp_fastopen' => true                 //快速握手
        ));

        $this->server = $this->serv->listen($this->host, $this->server_port,SWOOLE_SOCK_TCP);

        $this->server->set([
            'open_eof_split' => true,
            'package_eof' => "\n",
            'buffer_output_size'=>32 * 1024 * 1024,
            'tcp_fastopen' => true,      //快速握手
        ]);

        // 创建连接池对象,默认创建64个连接
        $this->pool = new PDOPool((new PDOConfig)
            ->withHost('0.0.0.0')
            ->withPort(3306)
            ->withDbName('***')
            ->withCharset('utf8mb4')
            ->withUsername('***')
            ->withPassword('***')
        );

        $this->serv->on('WorkerStart', function ($request, $response) {

            $pdo = $this->pool->get();

            //清空  web  fd
            if ($pdo->query("select * from ***")->fetchAll()){

                $pdo->exec("DELETE FROM **");
            }

            //清空  tcp fd
            if ($pdo->query("select * from **")->fetchAll()){

                $pdo->exec("DELETE FROM ***");
            }

            $this->pool->put($pdo);

            var_dump("启动进程(".$response.")").PHP_EOL;
        });

        //监听WebSocket连接打开事件
        $this->serv->on('open', function ($serv, $open) {

            echo "WebSocket 建立连接: {$open->fd}" . PHP_EOL;
        });

        //监听WebSocket消息事件
        //客户端向服务器端发送信息时,服务器端触发 onMessage 事件回调
        //服务器端可以调用 $server->push() 向某个客户端(使用 $fd 标识符)发送消息,长度最大不得超过 2M
        $this->serv->on('message', function ($ws, $request) {
       try {

                       
            }catch (Exception $e){

                $this->DeBugLog(array('title'=>'web:上线(异常)','fd'=>$request->fd,'err'=>$e));
            }
        });

        //监听WebSocket连接关闭事件
        $this->serv->on('close', function ($serv, $fd) {

            echo "Websocket: close - {$fd}" . PHP_EOL;

            try {

                //下线处理
                
            }catch (Exception $e){

                $this->DeBugLog(array('title'=>'web:下线(异常)','fd'=>$fd,'err'=>$e));
            }
        });

        //-------------------------  tcp  --------------------------------------------------  tcp -------------------------------------------------------------------------------

        //设置每个port的回调函数
        $this->server->on('connect', function ($serv, $fd){

            echo "Tcp 建立连接: {$fd}" . PHP_EOL;
        });

        $this->server->on('receive', function ($serv, $fd, $from_id, $data) {

           try {

                //数据处理
                        
            }catch (Exception $e){

                 $this->DeBugLog(array('title'=>'tcp:上线(异常)','mac'=>$mac,'err'=>$e));
            }
        });

        $this->server->on('close', function ($serv, $fd) {
        
try { //下线处理 }catch (Exception $e){ $this->DeBugLog(array('title'=>'tcp:下线(异常)','fd'=>$fd,'err'=>$e)); } }); //启动服务 $this->serv->start(); }
  
//错误记录 function DeBugLog($content = []){ $pdo = $this->pool->get(); $pdo->exec("insert into *** (addtime,content) values ('".time()."','".json_encode($content,JSON_OBJECT_AS_ARRAY)."')"); $this->pool->put($pdo); } } new WebSocketServer();

 

<!--服务操作-->
<script>

    var key = 'ç∂ßZ6Zu36Zu¿-.-^*^/@/sll';
    var wsServer = 'wss://域名:端口';
    var lockReconnect = false;  //避免wss重复连接
    var ws = null;              // 判断当前浏览器是否支持WebSocket
    var wsUrl =  wsServer;      //https设置wss,http设置ws
    createWebSocket(wsUrl);     //连接ws

    //验证浏览器是否支持
    function createWebSocket(url) {
        try{
            if('WebSocket' in window){
                ws = new WebSocket(url);
            }else if('MozWebSocket' in window){
                ws = new MozWebSocket(url);
            }else{
                layui.use(['layer'],function(){
                    var layer = layui.layer;
                    layer.alert("您的浏览器不支持websocket协议,建议使用新版谷歌、火狐等浏览器,请勿使用IE10以下浏览器,360浏览器请使用极速模式,不要使用兼容模式!");
                });
            }
            initEventHandle();
        }catch(e){
            reconnect(url);
            console.log(e);
        }
    }
    // 服务连接及数据处理
    function initEventHandle() {
        ws.onclose = function () {
            reconnect(wsUrl);
            console.log("ws连接关闭!" + new Date().toUTCString());
            alert('服务器连接已关闭');
        };
        ws.onerror = function () {
            reconnect(wsUrl);
            console.log("ws连接错误!");
            alert('服务器失去连接');
        };
        ws.onopen = function () {

            //心跳检测重置
            heartCheck.reset().start();

            //获取用户id
            var id = $('#id').val();

            //首次连接成功把id发送过去保存
            ws.send(key+id);

            alert('已成功连接服务器');
            //连接时间:new Date().toUTCString() 国际标准时间 GMT 时间
            console.log("ws连接成功!" + new Date().toUTCString());
        };
        ws.onmessage = function (event) {    //如果获取到消息,心跳检测重置
            heartCheck.reset().start();      //拿到任何消息都说明当前连接是正常的
            console.log("ws收到消息啦:" + event.data);
            if (event.data != key) {

                //上线:失败
                if (event.data == 'error'){

                    alert('上线失败,请刷新页面重试');
                }

                //消息发送失败
                if (event.data == 'timeout'){

                    alert('发送失败');
                }

                //接收好友发送的数据
                if (event.data.substr(0,4) == 'send'){    //接收到的消息

                    //获取好友id
                    var FriendId = $('#FriendId').val();

                    //获取内容
                    var info = event.data.substr(5);

                    if (info != ''){

                        //解析json数据
                        var datas = $.parseJSON(info);
                        console.log(datas);
                    }

                 

            // 监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
            window.onbeforeunload = function () {
                ws.close();
            }
        }
    }
    // 重连
    function reconnect(url) {
        if (lockReconnect) return;
        lockReconnect = true;
        setTimeout(function () {     //没连接上会一直重连,设置延迟避免请求过多
            createWebSocket(url);
            lockReconnect = false;
        }, 2000);
    }
    //心跳检测
    var heartCheck = {
        timeout: 30000,        //半分钟发一次心跳
        timeoutObj: null,
        serverTimeoutObj: null,
        reset: function () {
            clearTimeout(this.timeoutObj);
            clearTimeout(this.serverTimeoutObj);
            return this;
        },
        start: function () {
            var self = this;
            this.timeoutObj = setTimeout(function () {
                //这里发送一个心跳,后端收到后,返回一个心跳消息,
                //onmessage拿到返回的心跳就说明连接正常
                ws.send(key);
                console.log(new Date().toUTCString()+':兄弟出来嗨!!!');

                //如果超过一定时间还没重置,说明后端主动断开了
                self.serverTimeoutObj = setTimeout(function () {
                    //如果onclose会执行reconnect,我们执行ws.close()就行了.如果直接执行reconnect 会触发onclose导致重连两次
                    ws.close();
                }, self.timeout)
            }, this.timeout)
        }
    }

    
    //发送消息
    ws.send('send-'+data.value.fid+':'+content);    //发送消息
   
</script>

 

posted @ 2021-06-01 19:07  祈愿仙帝  阅读(249)  评论(0编辑  收藏  举报