请问下我在onMessage写定时器 时间长了就不发数据给用户端

a2465167794

时间长了就不发数据给用户端了 刷新浏览器也不会返回 是被阻塞了吗?
请问下大家这一块需要怎么优化或者设置
截图

1660 5 0
5个回答

a2465167794

浏览器控制台也没有报错 需要命令行重启后才恢复

  • 暂无评论
admin

get_box_record() 贴下

顺便 写一个这个看看,是否因为 缓冲区满 不再发送数据,或者客户端已断开

public function onBufferFull(TcpConnection $connection)
{
    echo "bufferFull and do not send again\n";
};
$worker->onBufferFull = function(TcpConnection $connection)
{
    echo "bufferFull and do not send again\n";
};
a2465167794

截图
截图

  • keytehu 2022-04-10

    浏览器与服务端的ws连接断开了

  • a2465167794 2022-04-10

    是需要长连接加心跳吗

  • keytehu 2022-04-10

    需要心跳,心跳可以维持连接,但是也无法保证连接不断开,客户端做断开重连的逻辑

  • a2465167794 2022-04-10

    好的

  • keytehu 2022-04-10

    还有个问题,get_box_record的定时器没有关闭的逻辑,随着get_box_record请求增多,定时器也会增加,久而久之可能会有成千万的定时器,这样感觉会有内存泄漏,而且这上万定时器一起请求数据库数据库估计会挂。不用的定时器应该及时关闭才对

  • a2465167794 2022-04-10

    有客户就会请求这个

2548a

每次链接都创建一个定时器,而且从来不销毁,最后结果只能是内存溢出.如果说里面涉及到连接数据库,那直接可能耗死数据库了.
看你代码也没有说需要传递什么参数,那说白了就是一个群发功能,启动的时候创建一个定时器群发就是了

  • a2465167794 2022-04-11

    <?php
    namespace app\index\controller;
    use app\common\model\box\Box;
    use app\common\model\box\BoxRecord;
    use app\common\model\ornaments\Ornaments;
    use app\common\model\system\Site;
    use app\common\model\user\User;
    use think\worker\Server;
    use Workerman\Lib\Timer;
    define('HEARTBEAT_TIME', 55);
    class Worker extends Server{

    protected $socket = "websocket://0.0.0.0:25648";
    protected $processes = 1;
    protected $cons = [];
    
    /**
     * 收到信息
     * @param $connection
     * @param $content
     */
    public function onMessage($connection, $content){
        $connection->maxSendBufferSize = 5 * 1024 * 1024;
        if ($content == 'ping'){
            $connection->lastMessageTime = time();
        } else {
            if(!isset($this->cons[$connection->id])){
                $this->cons[$connection->id] = 1;
                if (is_json($content)){
                    $data = json_decode($content, true);
                    if ($data){
                        $method = $data['method'];
                        switch ($method){
                            case 'get_box_record': //获取开箱记录
                                //首次执行下记录
                                $list = $this->get_box_record();
                                $connection->send(json_encode(['code' => 200, 'msg' => '获取成功', 'method' => $method, 'list' => $list]));
                                $this->get_box_record_repeat($connection, $method);
                                break;
                            default:
                                $connection->send(json_encode(['code' => 400, 'msg' => '方法不存在']));
                                break;
                        }
                    } else {
                        $connection->send(json_encode(['code' => 401, 'msg' => '参数错误']));
                    }
                } else {
                    $connection->send(json_encode(['code' => 402, 'msg' => '参数错误']));
                }
            }
        }
    }
    
    /**
     * 当连接建立时触发的回调函数
     * @param $connection
     */
    public function onConnect($connection){
    
    }
    
    /**
     * 当连接断开时触发的回调函数
     * @param $connection
     */
    public function onClose($connection){
        unset($this->cons[$connection->id]);
    }
    
    /**
     * 当客户端的连接上发生错误时触发
     * @param $connection
     * @param $code
     * @param $msg
     */
    public function onError($connection, $code, $msg){
        unset($this->cons[$connection->id]);
        echo "error $code msg $msg";
    }
    
    /**
     * 每个进程启动
     * @param $worker
     */
    public function onWorkerStart($worker){
        if ($worker->id === 0){
            Timer::add(10, function() use ($worker){
                $time_now = time();
                foreach($worker->connections as $connection) {
                    // 有可能该connection还没收到过消息,则lastMessageTime设置为当前时间
                    if (empty($connection->lastMessageTime)) {
                        $connection->lastMessageTime = $time_now;
                        continue;
                    }
                    // 上次通讯时间间隔大于心跳间隔,则认为客户端已经下线,关闭连接
                    if ($time_now - $connection->lastMessageTime > HEARTBEAT_TIME) {
                        $connection->close();
                    }
                }
            });
        }
    }
    
    /**
     * 发送内容
     * @param $connection
     * @param $data
     */
    private function get_box_record_repeat($connection, $method){
        Timer::add(5, function() use ($connection, $method){

    // $list = $this->get_box_record();
    $connection->send(json_encode(['code' => 200, 'msg' => '获取成功', 'method' => $method, 'list' => []]));
    $this->get_box_record_repeat($connection, $method);
    }, [], false);
    }

    /**
     * 获取最近开箱记录
     */
    private function get_box_record(){
        $box_record_model = new BoxRecord();
        $user_model = new User();
        $ornaments_model = new Ornaments();
        $box_model = new Box();
        $site_model = new Site();
        $head = $site_model->getField(['ttid' => 1], 'head');
        $list = $box_record_model->selListLimit(['type' => ['in', '1,4,5']], 20, 'ttid, uid, oid, bid, battle_id, type', 'time desc, ttid desc', function ($item) use ($user_model, $ornaments_model, $box_model, $head) {
            $user = $user_model->getInfo(['ttid' => $item['uid']], 'name, portrait');
            if (!stristr($user['portrait'], 'http')) $user['portrait'] = '/public/uploads/' . $user['portrait'];
            $ornaments = $ornaments_model->getInfo(['ttid' => $item['oid']], 'name, img');
            $box_name = '';
            $bid = '';
            switch ($item['type']){
                case 1:
                    $bid = $item['bid'];
                    $box_name = $box_model->getField(['ttid' => $bid], 'name');
                    break;
                case 4:
                    $bid = $item['bid'];
                    $box_name = $ornaments_model->getField(['ttid' => $bid], 'name');
                    break;
                case 5:
                    $bid = $item['battle_id'];
                    break;
    
            }
            $new_item = [
                'mark' => encrypt_key($item['ttid']),
                'user' => $user,
                'ornaments_name' => $ornaments['name'],
                'ornaments_img' => $ornaments['img'],
                'box_name' => $box_name,
                'bid' => encrypt_key($bid),
                'type' => $item['type'],
            ];
            return $new_item;
        });
        return $list;
    }

    }

  • a2465167794 2022-04-11

    这是整体的代码

  • a2465167794 2022-04-11

    js端:
    var ws, timeid;
    function create(){
    ws = new WebSocket("wss://{$Think.server.HTTP_HOST}/wss");
    ws.onopen = function() {
    ws.send(JSON.stringify({method:'get_box_record'}));
    timeid = setInterval(function(){
    ws.send("ping");
    }, 10000);
    };
    ws.onmessage = function(e){
    var data = JSON.parse(e.data);
    var code = data.code;
    var msg = data.msg;
    var method = data.method;
    var content = data.list;
    if (code == 200){
    eval(method)(content);
    } else {
    // alert(msg);
    }
    };
    ws.onclose = function(){
    clearInterval(timeid);
    setTimeout(function(){
    create();
    }, 1000);
    }
    }
    create();

2548a

在 onWorkerStart 加

    Timer::add(5, function () use ($worker) {
        $list = get_box_record();
        foreach ($worker->connections as $connection) {
            if (empty($connection->get_box_record)) {
                continue;
            }
            $method = $connection->get_box_record;
            $connection->send(json_encode(['code' => 200, 'msg' => '获取成功', 'method' => $method, 'list' => $list]));
        }
    });

在 case 'get_box_record': //获取开箱记录 下面加
$connection->get_box_record = $method;

然后把你自己定时器去掉,
再把
if ($worker->id === 0){

}去掉.

年代过于久远,无法发表回答
🔝