<?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()
那个大哥帮忙解决一下这个问题。难受了一天,小弟对你感谢万分
[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
同样的问题,求解释。。