0
<?php
/**
 * websocket 封装
 */
class Websocket
{
    CONST HOST = '0.0.0.0';
    CONST PORT =  9501;
    CONST REDIS_HOST = '127.0.0.1';
    CONST REDIS_PORT = 6379;
    CONST REDIS_AUTH = 'Q1w2e3r4REDIS.';

    /**
     * 存储pid文件的位置
     */
    public $pidFile;

    public $ws = null;
    public function __construct()
    {
        $this->ws = new swoole_websocket_server(self::HOST, self::PORT);
        if ($this->ws) {
            $this->ws->set([
                'worker_num'=>4,
                'task_worker_num'=>4,
                'deamonize' => true,//守护进程化
                'log_file' => '/var/log/swoole_server.log',
            ]);
            $this->ws->on("start", [$this, "onSwooleStart"]);
            // 此事件在Server正常结束时发生
            $this->ws->on("shutDown", [$this, "onSwooleShutDown"]);
            //事件在Worker进程/Task进程启动时发生。这里创建的对象可以在进程生命周期内使用。
            $this->ws->on("workerStart", [$this, "onSwooleWorkerStart"]);
            //  此事件在worker进程终止时发生。在此函数中可以回收worker进程申请的各类资源。
            $this->ws->on("workerStop", [$this, "onSwooleWorkerStop"]);
            // 当worker/task_worker进程发生异常后会在Manager进程内回调此函数
            $this->ws->on("workerError", [$this, "onSwooleWrokerError"]);
            // 当管理进程启动时调用它,函数原型:
            $this->ws->on("managerStart", [$this, "onSwooleManagerStart"]);
            // onManagerStop
            $this->ws->on("managerStop", [$this, "onSwooleManagerStop"]);
            // 接收到数据时回调此函数,发生在worker进程中
            $this->ws->on("receive", [$this, 'onSwooleReceive']);
            // 有新的连接进入时,在worker进程中回调。
            $this->ws->on("connect", [$this, 'onSwooleConnect']);

            $this->ws->on("open", [$this, 'onOpen']);
            $this->ws->on("message", [$this, 'onMessage']);
            $this->ws->on("task", [$this, 'onTask']);
            $this->ws->on("finish", [$this, 'onFinish']);
            $this->ws->on("close", [$this, 'onClose']);
            $this->ws->start();
        }


    }
    /**
     * @warning 进程隔离
     * 该步骤一般用于存储进程的 master_pid 和 manager_pid 到文件中
     * 本例子存储的位置是  "/var/log/" 下面
     * 可以用 kill -15 master_pid 发送信号给进程关闭服务器,并且触发下面的onSwooleShutDown事件
     * @param $server
     */
    public function onSwooleStart($ws)
    {
        $this->setProcessName('SwooleMaster');
        $debug = debug_backtrace();
        if(!$debug){
            $d = 0;
        }else{
            $d = $debug[count($debug) - 1] ["file"] . ".pid";
        }
        $this->pidFile = "/var/log/" . str_replace("/", "_", $d);
        $pid = [$ws->master_pid, $ws->manager_pid];
        file_put_contents($this->pidFile, implode(",", $pid));
    }

    /**
     * 已关闭所有Reactor线程、HeartbeatCheck线程、UdpRecv线程
     * 已关闭所有Worker进程、Task进程、User进程
     * 已close所有TCP/UDP/UnixSocket监听端口
     * 已关闭主Reactor
     * @warning
     * 强制kill进程不会回调onShutdown,如kill -9
     * 需要使用kill -15来发送SIGTREM信号到主进程才能按照正常的流程终止
     * 在命令行中使用Ctrl+C中断程序会立即停止,底层不会回调onShutdown
     */
    public function onSwooleShutDown($ws)
    {
        echo "shutdown\n";
    }

    /**
     * @warning 进程隔离
     * 该函数具有进程隔离性 ,
     * {$this} 对象从 swoole_server->start() 开始前设置的属性全部继承
     * {$this} 对象在 onSwooleStart,onSwooleManagerStart中设置的对象属于不同的进程中.
     * 因此这里的pidFile虽然在onSwooleStart中设置了,但是是不同的进程,所以找不到该值.
     * @param \swoole_server $server
     * @param int $worker_id
     */
    public function onSwooleWorkerStart(swoole_websocket_server $ws, $worker_id)
    {
        if ($this->isTaskProcess($ws)) {
            $this->setProcessName('SwooleTask');
        } else {
            $this->setProcessName('SwooleWorker');
        }
        $debug = debug_backtrace();
        if(!$debug){
            $d = 0;
        }else{
            $d = $debug[count($debug) - 1] ["file"] . ".pid";
        }
        $this->pidFile = "/var/log/" . str_replace("/", "_", $d);
        file_put_contents($this->pidFile, ",{$worker_id}", FILE_APPEND);

        if ($worker_id == 23) {

        }
    }

    public function onSwooleWorkerStop($ws, $worker_id)
    {
        echo "#worker exited {$worker_id}\n";
    }

    /**
     * worker进程发送错误的错误处理回调 .
     * 记录日志等操作
     * 此函数主要用于报警和监控,一旦发现Worker进程异常退出,那么很有可能是遇到了致命错误或者进程CoreDump。通过记录日志或者发送报警的信息来提示开发者进行相应的处理。
     * @param $server
     * @param $worker_id 是异常进程的编号
     * @param $worker_pid  是异常进程的ID
     * @param $exit_code  退出的状态码,范围是 1 ~255
     * @param $signal 进程退出的信号
     */
    public function onSwooleWrokerError($ws, $worker_id, $worker_pid, $exit_code, $signal)
    {
        echo "#workerError:{$worker_id}\n{$signal}";
    }

    public function onSwooleFinish()
    {

    }

    public function onSwooleManagerStart()
    {
        $this->setProcessName('SwooleManager');
    }

    public function onSwooleManagerStop()
    {
        echo "#managerstop\n";
    }

    /**
     * @param $server server对象
     * @param $fd 文件描述符
     * @param $reactorId reactor线程id
     */
    public function onSwooleReceive($ws, $fd, $reactorId, $data)
    {

        try {
            $ws->push($fd,'abcdefg');
            unset($ws);
        } catch (Exception $e) {
            echo time() . $e->getMessage() . PHP_EOL;
        }
    }

    /**
     * 客户端连接
     * onConnect/onClose这2个回调发生在worker进程内,而不是主进程。
     * UDP协议下只有onReceive事件,没有onConnect/onClose事件
     * @param $server
     * @param $fd
     * @param $reactorId
     */
    public function onSwooleConnect($ws, $fd, $reactorId)
    {
        echo $fd . "----connected\n";
        $ws->push($fd,'hello');
    }

    /**
     * 监听ws连接事件
     * @param  [type] $ws      [description]
     * @param  [type] $request [description]
     * @return [type]          [description]
     */
    public function onOpen($ws,$request)
    {
        $redis = $this->redis();
        $redis->set('FD:' . $request->fd,1);
        echo "connection open: ".$request->fd."\n";
        $ws->push($request->fd, '你好,欢迎链接');
        $countent = [
            'date'=>date('Y-m-d H:i:s'),
            'get'=>$request->get,
            'post'=>$request->post,
            'header'=>$request->header
        ];
        $debug = debug_backtrace();
        if($debug){
            @swoole_async_writefile('/var/log/swoole_access.log',json_encode($countent),function(){},FILE_APPEND);
        }
        var_dump($request->fd);
    }


    /**
     * 监听客户端消息事件
     * @param $ws
     * @param $frame
     */
    public function onMessage($ws,$frame)
    {
        echo "clien_push_message:{$frame->data}\n";
        $data = [
            'task'=>1,
            'fd'=>$frame->fd
        ];
        $ws->task($data);
        swoole_timer_tick(2000, function () use ($ws) {
            $str = 'server';
            $redis = $this->redis();
            $length = $redis->lLen($str);
            if($length > 0) {
                for ($i=0;$i<$length;$i++) {
                    $fd = $redis->rpop($str);
                    $data = $redis->get('L:'.$fd);
                    $type = $redis->get('FD:'.$fd);
                    if($type == 1){
                        $ws->push($fd, $data);
                        $redis->del('L:'.$fd);
                    }
                }
                echo '开始查看命令';
            }
        });
        $ws->push($frame->fd, '我是机器'.$frame->fd.'请上报位置');
        if($frame->data){
            echo "message: ".$frame->data."\n";
            $ws->push($frame->fd, $frame->fd.'号机器,你的位置是'.$frame->data);
        }
    }

    /**
     * task
     * @param $serv
     * @param $taskId
     * @param $workerId
     * @param $data
     * @return string
     */
    public function onTask($serv,$taskId,$workerId,$data)
    {
        return $data;
    }

    public function onFinish($serv,$taskId,$data)
    {
    }

    /**
     * 监听关闭事件
     * @param $ws
     * @param $fd
     */
    public function onClose($ws,$fd)
    {
        $redis = $this->redis();
        $redis->set('FD:' . $fd,0);
        echo "close clientId:{$fd}\n";
    }

    /**
     * 返回真说明该进程是task进程
     * @param $server
     * @return bool
     */
    public function isTaskProcess($server)
    {
        return $server->taskworker === true;
    }

    public function setProcessName($name)
    {
        if (function_exists('cli_set_process_title')) {
            @cli_set_process_title($name);
        } else {
            @swoole_set_process_name($name);
        }
    }

    public function redis()
    {
        $redis = new \Redis();
        $redis->connect(self::REDIS_HOST, self::REDIS_PORT);
        $redis->auth(self::REDIS_AUTH);
        return $redis;

    }
}

$obj = new Websocket();

代码如上,不知道为什么,报错如下
[2019-07-17 14:46:33 ^10634.4] WARNING swSignal_callback (ERRNO 707): Unable to find callback function for signal Hangup: 1
[2019-07-17 14:46:33 #10630.2] WARNING swSignalfd_onSignal (ERRNO 707): Unable to find callback function for signal Hangup: 1
[2019-07-17 14:46:33 *10640.2] WARNING swSignalfd_onSignal (ERRNO 707): Unable to find callback function for signal Hangup: 1
[2019-07-17 14:46:33 *10639.1] WARNING swSignalfd_onSignal (ERRNO 707): Unable to find callback function for signal Hangup: 1
[2019-07-17 14:46:33 ^10636.6] WARNING swSignal_callback (ERRNO 707): Unable to find callback function for signal Hangup: 1
[2019-07-17 14:46:33 *10638.0] WARNING swSignalfd_onSignal (ERRNO 707): Unable to find callback function for signal Hangup: 1
[2019-07-17 14:46:33 ^10637.7] WARNING swSignal_callback (ERRNO 707): Unable to find callback function for signal Hangup: 1
[2019-07-17 14:46:33 $10631.0] WARNING swSignal_callback (ERRNO 707): Unable to find callback function for signal Hangup: 1
[2019-07-17 14:46:33 ^10635.5] WARNING swSignal_callback (ERRNO 707): Unable to find callback function for signal Hangup: 1
[2019-07-17 14:46:33 *10641.3] WARNING swSignalfd_onSignal (ERRNO 707): Unable to find callback function for signal Hangup: 1
,其次还报错
[2019-07-17 14:32:03 *9878.2] NOTICE swoole_server_rshutdown (ERRNO 9003): worker process is terminated by exit()/die()
[2019-07-17 14:32:03 *9865.3] NOTICE swoole_server_rshutdown (ERRNO 9003): worker process is terminated by exit()/die()
[2019-07-17 14:32:03 *9885.3] NOTICE swoole_server_rshutdown (ERRNO 9003): worker process is terminated by exit()/die()
[2019-07-17 14:32:03 *9886.3] NOTICE swoole_server_rshutdown (ERRNO 9003): worker process is terminated by exit()/die()
[2019-07-17 14:32:36 *9887.3] NOTICE swoole_server_rshutdown (ERRNO 9003): worker process is terminated by exit()/die()
[2019-07-17 14:32:36 *9870.0] NOTICE swoole_server_rshutdown (ERRNO 9003): worker process is terminated by exit()/die()
[2019-07-17 14:32:36 *9916.0] NOTICE swoole_server_rshutdown (ERRNO 9003): worker process is terminated by exit()/die()
[2019-07-17 14:32:36 *9917.0] NOTICE swoole_server_rshutdown (ERRNO 9003): worker process is terminated by exit()/die()
[2019-07-17 14:32:48 *9918.0] NOTICE swoole_server_rshutdown (ERRNO 9003): worker process is terminated by exit()/die()
[2019-07-17 14:32:48 *9874.1] NOTICE swoole_server_rshutdown (ERRNO 9003): worker process is terminated by exit()/die()
[2019-07-17 14:32:48 *9929.1] NOTICE swoole_server_rshutdown (ERRNO 9003): worker process is terminated by exit()/die()
[2019-07-17 14:32:48 *9930.1] NOTICE swoole_server_rshutdown (ERRNO 9003): worker process is terminated by exit()/die()
[2019-07-17 14:35:43 *9931.1] NOTICE swoole_server_rshutdown (ERRNO 9003): worker process is terminated by exit()/die()
那个大哥帮忙解决一下这个问题。难受了一天,小弟对你感谢万分

7月17日提问

1 个回答

0

[2019-07-20 09:03:24 ^29562.13] WARNING swSignalfd_onSignal (ERRNO 707): Unable to find callback function for signal Hangup: 1
[2019-07-20 09:03:24 *29566.1] WARNING swSignalfd_onSignal (ERRNO 707): Unable to find callback function for signal Hangup: 1
[2019-07-20 09:03:24 ^29564.15] WARNING swSignalfd_onSignal (ERRNO 707): Unable to find callback function for signal Hangup: 1
同样的问题,求解释。。

推广链接