public function onStart()
 {
     $listen = \Man\Core\Lib\Config::get($this->workerName . '.listen');
     $udp_address = str_replace('tcp', 'udp', $listen);
     $this->broadcastSocket = stream_socket_server($udp_address, $error_no, $error_msg, STREAM_SERVER_BIND);
     $this->event->add($this->broadcastSocket, \Man\Core\Events\BaseEvent::EV_READ, array($this, 'dealBroadcastUdp'));
 }
Example #2
0
 /**
  * 启动的时候初始化统计上报地址)
  * @see Man\Core.SocketWorker::onStart()
  */
 public function onStart()
 {
     // 获取统计上报地址
     $statistic_address = \Man\Core\Lib\Config::get($this->workerName . '.statistic_address');
     if ($statistic_address) {
         $this->statisticAddress = $statistic_address;
     }
 }
 /**
  * 进程启动时做的一些初始化工作
  * @see Man\Core.SocketWorker::onStart()
  * @return void
  */
 public function onStart()
 {
     // 查看配置中是否有设置Protocol
     if ($protocol = \Man\Core\Lib\Config::get($this->workerName . '.thrift_protocol')) {
         $this->thriftProtocol = "\\Thrift\\Protocol\\" . $protocol;
         if (!class_exists($this->thriftProtocol, true)) {
             $this->notice('Class ' . $this->thriftProtocol . ' not exsits , Please check ./conf/conf.d/' . $this->workerName . '.conf');
             return;
         }
     }
     // 查看配置中是否有设置Transport
     if ($transport = \Man\Core\Lib\Config::get($this->workerName . '.thrift_transport')) {
         $this->thriftTransport = "\\Thrift\\Transport\\" . $transport;
         if (!class_exists($this->thriftTransport, true)) {
             $this->notice('Class ' . $this->thriftTransport . ' not exsits , Please check ./conf/conf.d/' . $this->workerName . '.conf');
             return;
         }
     }
     // 载入该服务下的所有文件
     foreach (glob(THRIFT_ROOT . '/Services/' . $this->workerName . '/*.php') as $php_file) {
         require_once $php_file;
     }
     // 检查类是否存在
     $processor_class_name = "\\Services\\" . $this->workerName . "\\" . $this->workerName . 'Processor';
     if (!class_exists($processor_class_name)) {
         $this->notice("Class {$processor_class_name} not found");
         return;
     }
     // 检查类是否存在
     $handler_class_name = "\\Services\\" . $this->workerName . "\\" . $this->workerName . 'Handler';
     if (!class_exists($handler_class_name)) {
         $this->notice("Class {$handler_class_name} not found");
         return;
     }
     // 统计上报地址
     $statistic_address = \Man\Core\Lib\Config::get($this->workerName . '.statistic_address');
     if ($statistic_address) {
         $this->statisticAddress = $statistic_address;
     }
     $handler = new $handler_class_name();
     $this->processor = new $processor_class_name($handler);
 }
Example #4
0
 /**
  * 运行线程
  */
 public function run()
 {
     date_default_timezone_set('Asia/Shanghai');
     // 保存一个副本
     $this->mainSocket = $this->worker->mainSocket;
     // 改变当前工作目录
     chdir(WORKERMAN_ROOT_DIR);
     // 重新载入一次配置
     \Man\Core\Lib\Config::reload();
     // 载入入口文件
     require_once $this->worker->workerFile;
     // 入口文件类名
     $class_name = basename($this->worker->workerFile, '.php');
     // 实例化入口类
     $worker = new $class_name($this->worker->serviceName);
     // 如果该worker有配置监听端口,则将监听端口的socket传递给子进程
     if ($this->mainSocket) {
         $worker->setListendSocket($this->mainSocket);
     }
     // 使worker开始服务
     $worker->start();
 }
Example #5
0
 /**
  * 该worker进程开始服务的时候会触发一次
  * @return bool
  */
 public function start()
 {
     if (\Man\Core\Lib\Config::get('workerman.debug') != 1 || !\Man\Core\Master::getQueueId()) {
         while (1) {
             if (!$this->hasShutDown()) {
                 sleep(PHP_INT_MAX);
             } else {
                 exit(0);
             }
         }
     }
     $msg_type = $message = 0;
     \Man\Core\Lib\Task::init();
     \Man\Core\Lib\Task::add(1, array($this, 'sendSignalAndGetResult'));
     \Man\Core\Lib\Task::add(1, array($this, 'checkFilesModify'));
     \Man\Core\Lib\Task::add(1, array($this, 'checkTty'));
     while (1) {
         $this->collectFiles(true);
         if ($this->hasShutDown()) {
             exit(0);
         }
     }
     return true;
 }
Example #6
0
 /**
  * 检查worker配置、worker语法错误等
  * @return void
  */
 public static function checkWorkersConfig()
 {
     $current_pwuid = posix_getpwuid(posix_getuid());
     $current_user_name = $current_pwuid['name'];
     self::$maxUserNameLength = strlen($current_user_name);
     foreach (Config::getAllWorkers() as $worker_name => $config) {
         if (strlen($worker_name) > self::$maxWorkerNameLength) {
             self::$maxWorkerNameLength = strlen($worker_name);
         }
         if (isset($config['user']) && strlen($config['user']) > self::$maxUserNameLength) {
             self::$maxUserNameLength = strlen($config['user']);
         }
         if (isset($config['listen']) && strlen($config['listen']) > self::$maxListenLength) {
             self::$maxListenLength = strlen($config['listen']);
         }
     }
     $total_worker_count = 0;
     // 检查worker 是否有语法错误
     echo "------------------------ WORKERS -------------------------------\n";
     echo "user", str_pad('', self::$maxUserNameLength + 2 - strlen('user')), "worker", str_pad('', self::$maxWorkerNameLength + 2 - strlen('worker')), "listen", str_pad('', self::$maxListenLength + 2 - strlen('listen')), "processes", str_pad('', self::$maxProcessCountLength + 2 - strlen('processes')), "", "status\n";
     foreach (Config::getAllWorkers() as $worker_name => $config) {
         if (isset($config['user'])) {
             $worker_user = $config['user'];
             if (!self::checkWorkerUserName($worker_user)) {
                 echo str_pad($config['user'], self::$maxUserNameLength + 2), str_pad($worker_name, self::$maxWorkerNameLength + 2), " [FAIL] \n";
                 \Man\Core\Master::notice("Can not run {$worker_name} processes as user {$worker_user} , User {$worker_user} not exists\tWorkerman start fail");
                 exit("\nCan not run {$worker_name} processes as user {$worker_user} , User {$worker_user} not exists\n\nWorkerman start fail\n\n");
             }
         } else {
             $worker_user = $current_user_name;
         }
         echo str_pad($worker_user, self::$maxUserNameLength + 2), str_pad($worker_name, self::$maxWorkerNameLength + 2);
         if (isset($config['listen'])) {
             echo str_pad($config['listen'], self::$maxListenLength + 2);
         } else {
             echo str_pad('none', self::$maxListenLength + 2);
         }
         if (empty($config['start_workers'])) {
             \Man\Core\Master::notice(str_pad($worker_name, 40) . " [start_workers not set]\tWorkerman start fail");
             exit(str_pad('', self::$maxProcessCountLength + 2) . " [start_workers not set]\n\nWorkerman start fail\n");
         }
         echo str_pad(' ' . $config['start_workers'], self::$maxProcessCountLength + 2);
         $total_worker_count += $config['start_workers'];
         // 语法检查
         if ($worker_file = \Man\Core\Lib\Config::get($worker_name . '.worker_file')) {
             $class_name = basename($worker_file, '.php');
         } else {
             \Man\Core\Master::notice("{$worker_name} not set worker_file in conf/conf.d/{$worker_name}.conf");
             echo " [not set worker_file] \n";
             continue;
         }
         if (0 != self::checkSyntaxError($worker_file, $class_name)) {
             //unset(Config::instance()->config[$worker_name]);
             \Man\Core\Master::notice("{$worker_name} has Fatal Err");
             echo " [Fatal Err] \n";
             continue;
         }
         echo " [OK] \n";
     }
     if ($total_worker_count > \Man\Core\Master::SERVER_MAX_WORKER_COUNT) {
         \Man\Core\Master::notice("Number of worker processes can not be greater than " . \Man\Core\Master::SERVER_MAX_WORKER_COUNT . ".\tPlease check start_workers in " . WORKERMAN_ROOT_DIR . "config/main.php\tWorkerman start fail");
         exit("\nNumber of worker processes can not be greater than " . \Man\Core\Master::SERVER_MAX_WORKER_COUNT . ".\nPlease check start_workers in " . WORKERMAN_ROOT_DIR . "config/main.php\n\nWorkerman start fail\n");
     }
     echo "----------------------------------------------------------------\n";
 }
Example #7
0
 /**
  * 进程启动
  */
 public function start()
 {
     // 安装信号处理函数
     $this->installSignal();
     // 添加accept事件
     $ret = $this->event->add($this->mainSocket, Man\Core\Events\BaseEvent::EV_READ, array($this, 'accept'));
     // 创建内部通信套接字,用于与BusinessWorker通讯
     $start_port = Man\Core\Lib\Config::get($this->workerName . '.lan_port_start');
     // 计算本进程监听的ip端口
     if (strpos(\Man\Core\Master::VERSION, 'mt')) {
         $this->lanPort = $start_port + \Thread::getCurrentThreadId() % 100;
     } else {
         $this->lanPort = $start_port - posix_getppid() + posix_getpid();
     }
     // 如果端口不在合法范围
     if ($this->lanPort < 0 || $this->lanPort >= 65535) {
         $this->lanPort = rand($start_port, 65535);
     }
     // 如果
     $this->lanIp = Man\Core\Lib\Config::get($this->workerName . '.lan_ip');
     if (!$this->lanIp) {
         $this->notice($this->workerName . '.lan_ip not set');
         $this->lanIp = '127.0.0.1';
     }
     $error_no_udp = $error_no_tcp = 0;
     $error_msg_udp = $error_msg_tcp = '';
     // 执行监听
     $this->innerMainSocketUdp = stream_socket_server("udp://" . $this->lanIp . ':' . $this->lanPort, $error_no_udp, $error_msg_udp, STREAM_SERVER_BIND);
     $this->innerMainSocketTcp = stream_socket_server("tcp://" . $this->lanIp . ':' . $this->lanPort, $error_no_tcp, $error_msg_tcp, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN);
     // 出错,退出,下次会换个端口
     if (!$this->innerMainSocketUdp || !$this->innerMainSocketTcp) {
         $this->notice('create innerMainSocket udp or tcp fail and exit ' . $error_msg_udp . $error_msg_tcp);
         $this->stop();
     } else {
         stream_set_blocking($this->innerMainSocketUdp, 0);
         stream_set_blocking($this->innerMainSocketTcp, 0);
     }
     // 注册套接字
     if (!$this->registerAddress($this->lanIp . ':' . $this->lanPort)) {
         $this->notice('registerAddress fail and exit');
         $this->stop();
     }
     // 添加读udp/tcp事件
     $this->event->add($this->innerMainSocketUdp, Man\Core\Events\BaseEvent::EV_READ, array($this, 'recvInnerUdp'));
     $this->event->add($this->innerMainSocketTcp, Man\Core\Events\BaseEvent::EV_READ, array($this, 'acceptInnerTcp'));
     // 初始化心跳包时间间隔
     $ping_interval = \Man\Core\Lib\Config::get($this->workerName . '.ping_interval');
     if ((int) $ping_interval > 0) {
         $this->pingInterval = (int) $ping_interval;
     }
     // 获取心跳包数据
     $ping_data_or_path = \Man\Core\Lib\Config::get($this->workerName . '.ping_data');
     if (is_file($ping_data_or_path)) {
         $this->pingData = file_get_contents($ping_data_or_path);
     } else {
         $this->pingData = $ping_data_or_path;
     }
     // 不返回心跳回应(客户端发来的任何数据都算是回应)的限定值
     $this->pingNotResponseLimit = (int) \Man\Core\Lib\Config::get($this->workerName . '.ping_not_response_limit');
     // 设置定时任务,发送心跳
     if ($this->pingInterval > 0) {
         \Man\Core\Lib\Task::init($this->event);
         \Man\Core\Lib\Task::add($this->pingInterval, array($this, 'ping'));
     }
     // 主体循环,整个子进程会阻塞在这个函数上
     $ret = $this->event->loop();
     // 下面正常不会执行到
     $this->notice('worker loop exit');
     // 执行到就退出
     exit(0);
 }
 protected function getExcludeFiles()
 {
     $exclude_path = \Man\Core\Lib\Config::get($this->workerName . '.exclude_path');
     return (array) $exclude_path;
 }
 /**
  * 设置server信号处理函数
  * @param null $null
  * @param int $signal
  */
 public function signalHandler($signal, $null = null, $null = null)
 {
     switch ($signal) {
         // 时钟处理函数
         case SIGALRM:
             // 停止服务后EXIT_WAIT_TIME秒还没退出则强制退出
             if ($this->workerStatus == self::STATUS_SHUTDOWN) {
                 exit(0);
             }
             break;
             // 停止该进程
         // 停止该进程
         case SIGINT:
             $this->stop();
             // EXIT_WAIT_TIME秒后退出进程
             pcntl_alarm(self::EXIT_WAIT_TIME);
             break;
             // 平滑重启
         // 平滑重启
         case SIGHUP:
             $this->onReload();
             // 如果配置了no_reload则不重启该进程
             if (\Man\Core\Lib\Config::get($this->workerName . '.no_reload')) {
                 return;
             }
             $this->stop();
             // EXIT_WAIT_TIME秒后退出进程
             pcntl_alarm(self::EXIT_WAIT_TIME);
             break;
             // 报告进程状态
         // 报告进程状态
         case SIGUSR1:
             $this->writeStatusToQueue();
             break;
             // 报告进程使用的php文件
         // 报告进程使用的php文件
         case SIGUSR2:
             $this->writeFilesListToQueue();
             break;
             // FileMonitor检测到终端已经关闭,向此进程发送SIGTTOU信号,关闭此进程的标准输入输出
         // FileMonitor检测到终端已经关闭,向此进程发送SIGTTOU信号,关闭此进程的标准输入输出
         case SIGTTOU:
             $this->resetFd();
             break;
     }
 }
Example #10
0
 /**
  * 创建一个worker进程
  * @param string $worker_name worker的名称
  * @return int 父进程:>0得到新worker的pid ;<0 出错; 子进程:始终为0
  */
 protected static function forkOneWorker($worker_name)
 {
     // 创建子进程
     $pid = pcntl_fork();
     // 先处理收到的信号
     pcntl_signal_dispatch();
     // 父进程
     if ($pid > 0) {
         // 初始化master的一些东东
         self::$workerPids[$worker_name][$pid] = $pid;
         // 更新进程信息到共享内存
         self::updateStatusToShm();
         return $pid;
     } elseif ($pid === 0) {
         // 忽略信号
         self::ignoreSignal();
         // 清空任务
         Lib\Task::delAll();
         // 关闭不用的监听socket
         foreach (self::$listenedSockets as $tmp_worker_name => $tmp_socket) {
             if ($tmp_worker_name != $worker_name) {
                 fclose($tmp_socket);
             }
         }
         // 尝试以指定用户运行worker
         if ($worker_user = Lib\Config::get($worker_name . '.user')) {
             self::setWorkerUser($worker_user);
         }
         // 关闭输出
         self::resetStdFd();
         // 尝试设置子进程进程名称
         self::setWorkerProcessTitle($worker_name);
         // 查找worker文件
         if ($worker_file = \Man\Core\Lib\Config::get($worker_name . '.worker_file')) {
             include_once $worker_file;
             $class_name = basename($worker_file, '.php');
         } else {
             $class_name = $worker_name;
             include_once WORKERMAN_ROOT_DIR . "workers/{$worker_name}.php";
         }
         // 创建实例
         $worker = new $class_name($worker_name);
         // 如果该worker有配置监听端口,则将监听端口的socket传递给子进程
         if (isset(self::$listenedSockets[$worker_name])) {
             $worker->setListendSocket(self::$listenedSockets[$worker_name]);
         }
         // 使worker开始服务
         $worker->start();
         return 0;
     } else {
         self::notice("create worker fail worker_name:{$worker_name} detail:pcntl_fork fail");
         return $pid;
     }
 }
Example #11
0
 /**
  * 获取本地ip
  * @param string $worker_name
  * @return string
  */
 public function getIp($worker_name = '')
 {
     $ip = $this->getLocalIp();
     if (empty($ip) || $ip == '0.0.0.0' || ($ip = '127.0.0.1')) {
         if ($worker_name) {
             $ip = \Man\Core\Lib\Config::get($worker_name . '.ip');
         }
         if (empty($ip) || $ip == '0.0.0.0' || ($ip = '127.0.0.1')) {
             $ret_string = shell_exec('ifconfig');
             if (preg_match("/:(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})/", $ret_string, $match)) {
                 $ip = $match[1];
             }
         }
     }
     return $ip;
 }
Example #12
0
 /**
  * 初始化AccessLog
  * @return void 
  */
 public function initAccessLog()
 {
     // 虚拟机访问日志目录
     self::$accessLog = \Man\Core\Lib\Config::get($this->workerName . '.access_log');
     // 默认访问日志目录
     if ($default_access_log = \Man\Core\Lib\Config::get($this->workerName . '.default_access_log')) {
         self::$defaultAccessLog = $default_access_log;
     }
 }
Example #13
0
 /**
  * 检查worker配置、worker语法错误等
  * @return void
  */
 public static function checkWorkersConfig()
 {
     $pad_length = 26;
     $total_worker_count = 0;
     // 检查worker 是否有语法错误
     echo "----------------------WORKERS--------------------\n";
     foreach (Config::getAllWorkers() as $worker_name => $config) {
         if (empty($config['start_workers'])) {
             \Man\Core\Master::notice(str_pad($worker_name, $pad_length) . " [start_workers not set]\tServer start fail");
             exit(str_pad($worker_name, $pad_length) . " [start_workers not set]\n\nServer start fail\n");
         }
         $total_worker_count += $config['start_workers'];
         // 语法检查
         if ($worker_file = \Man\Core\Lib\Config::get($worker_name . '.worker_file')) {
             $class_name = basename($worker_file, '.php');
         } else {
             $worker_file = WORKERMAN_ROOT_DIR . "workers/{$worker_name}.php";
             $class_name = $worker_name;
         }
         if (0 != self::checkSyntaxError($worker_file, $class_name)) {
             unset(Config::instance()->config[$worker_name]);
             \Man\Core\Master::notice("{$worker_name} has Fatal Err");
             echo str_pad($worker_name, $pad_length), " [Fatal Err] \n";
             continue;
         }
         if (isset($config['user'])) {
             $worker_user = $config['user'];
             if (!self::checkWorkerUserName($worker_user)) {
                 echo str_pad($worker_name, $pad_length), " [FAIL] \n";
                 \Man\Core\Master::notice("Can not run {$worker_name} processes as user {$worker_user} , User {$worker_user} not exists\tServer start fail");
                 exit("\nCan not run {$worker_name} processes as user {$worker_user} , User {$worker_user} not exists\n\nServer start fail\n\n");
             }
         }
         echo str_pad($worker_name, $pad_length), " [OK] \n";
     }
     if ($total_worker_count > \Man\Core\Master::SERVER_MAX_WORKER_COUNT) {
         \Man\Core\Master::notice("Number of worker processes can not be more than " . \Man\Core\Master::SERVER_MAX_WORKER_COUNT . ".\tPlease check start_workers in " . WORKERMAN_ROOT_DIR . "config/main.php\tServer start fail");
         exit("\nNumber of worker processes can not be more than " . \Man\Core\Master::SERVER_MAX_WORKER_COUNT . ".\nPlease check start_workers in " . WORKERMAN_ROOT_DIR . "config/main.php\n\nServer start fail\n");
     }
     echo "-------------------------------------------------\n";
 }
Example #14
0
 /**
  * 记录日志
  * @param sring $str
  * @return void
  */
 protected function notice($str, $display = true)
 {
     $str = 'Worker[' . get_class($this) . ':' . posix_getpid() . ']:' . $str;
     Log::add($str);
     if ($display && Config::get('workerman.debug') == 1) {
         echo $str . "\n";
     }
 }
Example #15
0
 /**
  * 检查控制终端是否已经关闭, 如果控制终端关闭,则停止打印数据到终端
  * @return void
  */
 public static function checkTty()
 {
     // 已经重置了fd,就不检查终端是否关闭,因为不会打印东西到屏幕了
     if (self::$hasResetStd) {
         return;
     }
     // 没开启debug不打印数据到屏幕,不检测终端是否关闭
     if (!Config::get('workerman.debug')) {
         return;
     }
     // 检测终端是否关闭
     if (!self::$terminalClosed && !@posix_ttyname(STDOUT)) {
         self::resetStdFd(true);
         // 日志
         self::notice("terminal closed and reset workers fd");
         // 获取所有子进程pid
         $all_worker_pid = self::getPidWorkerNameMap();
         // 向所有子进程发送重置标准输入输出信号
         foreach ($all_worker_pid as $pid => $worker_name) {
             // 发送SIGTTOU信号
             posix_kill($pid, SIGTTOU);
         }
         // 设置标记
         self::$terminalClosed = true;
     }
 }
Example #16
0
 /**
  * 检查worker配置、worker语法错误等
  * @return void
  */
 public static function checkWorkersConfig()
 {
     foreach (Config::getAllWorkers() as $worker_name => $config) {
         if (strlen($worker_name) > self::$maxWorkerNameLength) {
             self::$maxWorkerNameLength = strlen($worker_name);
         }
         if (isset($config['user']) && strlen($config['user']) > self::$maxUserNameLength) {
             self::$maxUserNameLength = strlen($config['user']);
         }
         if (isset($config['listen']) && strlen($config['listen']) > self::$maxListenLength) {
             self::$maxListenLength = strlen($config['listen']);
         }
     }
     $total_worker_count = 0;
     // 检查worker
     echo "------------------------ WORKERS -------------------------------\n";
     echo "worker", str_pad('', self::$maxWorkerNameLength + 2 - strlen('worker')), "listen", str_pad('', self::$maxListenLength + 2 - strlen('listen')), "processes", str_pad('', self::$maxProcessCountLength + 2 - strlen('processes')), "", "status\n";
     foreach (Config::getAllWorkers() as $worker_name => $config) {
         echo str_pad($worker_name, self::$maxWorkerNameLength + 2);
         if (isset($config['listen'])) {
             echo str_pad($config['listen'], self::$maxListenLength + 2);
         } else {
             echo str_pad('none', self::$maxListenLength + 2);
         }
         if (empty($config['start_workers'])) {
             \Man\Core\Master::notice(str_pad($worker_name, 40) . " [start_workers not set]\tWorkerman start fail");
             exit(str_pad('', self::$maxProcessCountLength + 2) . " [start_workers not set]\n\nWorkerman start fail\n");
         }
         echo str_pad(' ' . $config['start_workers'], self::$maxProcessCountLength + 2);
         $total_worker_count += $config['start_workers'];
         // 语法检查
         if (!($worker_file = \Man\Core\Lib\Config::get($worker_name . '.worker_file'))) {
             \Man\Core\Master::notice("{$worker_name} not set worker_file in conf/conf.d/{$worker_name}.conf");
             echo " [not set worker_file] \n";
             continue;
         }
         echo " [OK] \n";
     }
     if ($total_worker_count > \Man\Core\Master::SERVER_MAX_WORKER_COUNT) {
         \Man\Core\Master::notice("Number of worker processes can not be greater than " . \Man\Core\Master::SERVER_MAX_WORKER_COUNT . ".\tPlease check start_workers in " . WORKERMAN_ROOT_DIR . "config/main.php\tWorkerman start fail");
         exit("\nNumber of worker processes can not be greater than " . \Man\Core\Master::SERVER_MAX_WORKER_COUNT . ".\nPlease check start_workers in " . WORKERMAN_ROOT_DIR . "config/main.php\n\nWorkerman start fail\n");
     }
     echo "----------------------------------------------------------------\n";
 }
Example #17
0
 /**
  * 那些路径不监控更新
  * @return array
  */
 protected function getExcludePaths()
 {
     $config_exclude_path = Config::get('Monitor.exclude_path');
     // 被排除的路径
     $exclude_path = array();
     // 因为配置可能会被更改,所以每次都会重新从配置中查找排除路径
     foreach ($config_exclude_path as $path) {
         if ($real_path = realpath($path)) {
             $exclude_path[] = $real_path;
         }
     }
     return (array) $exclude_path;
 }
Example #18
0
 /**
  * 创建一个worker进程
  * @param string $worker_name 服务名
  * @return int 父进程:>0得到新worker的pid ;<0 出错; 子进程:始终为0
  */
 protected static function createOneWorker($worker_name)
 {
     // 创建子进程
     $pid = pcntl_fork();
     // 先处理收到的信号
     pcntl_signal_dispatch();
     // 父进程
     if ($pid > 0) {
         // 初始化master的一些东东
         self::$workerPidMap[$worker_name][$pid] = $pid;
         // 更新进程信息到共享内存
         self::updateStatusToShm();
         return $pid;
     } elseif ($pid === 0) {
         // 忽略信号
         self::ignoreSignal();
         // 清空任务
         Lib\Task::delAll();
         // 关闭不用的监听socket
         foreach (self::$listenedSocketsArray as $tmp_worker_name => $tmp_socket) {
             if ($tmp_worker_name != $worker_name) {
                 fclose($tmp_socket);
             }
         }
         // 尝试以指定用户运行worker进程
         if ($worker_user = Lib\Config::get($worker_name . '.user')) {
             self::setProcUser($worker_user);
         }
         // 关闭输出
         self::resetStdFd(Lib\Config::get($worker_name . '.no_debug'));
         // 尝试设置子进程进程名称
         self::setWorkerProcTitle($worker_name);
         // 包含必要文件
         require_once WORKERMAN_ROOT_DIR . 'Core/SocketWorker.php';
         // 查找worker文件
         $worker_file = \Man\Core\Lib\Config::get($worker_name . '.worker_file');
         $class_name = basename($worker_file, '.php');
         // 如果有语法错误 sleep 5秒 避免狂刷日志
         if (\Man\Core\Lib\Checker::checkSyntaxError($worker_file, $class_name)) {
             sleep(5);
         }
         require_once $worker_file;
         // 创建实例
         $worker = new $class_name($worker_name);
         // 如果该worker有配置监听端口,则将监听端口的socket传递给子进程
         if (isset(self::$listenedSocketsArray[$worker_name])) {
             $worker->setListendSocket(self::$listenedSocketsArray[$worker_name]);
         }
         // 使worker开始服务
         $worker->start();
         return 0;
     } else {
         self::notice("create worker fail worker_name:{$worker_name} detail:pcntl_fork fail");
         return $pid;
     }
 }
 /**
  * 构造函数
  * @param int $port
  * @param string $ip
  * @param string $protocol
  * @return void
  */
 public function __construct($worker_name = null)
 {
     // worker name
     $this->workerName = $worker_name ? $worker_name : get_class($this);
     // 是否开启长连接
     $this->isPersistentConnection = (bool) Lib\Config::get($this->workerName . '.persistent_connection');
     // 最大请求数,超过这个数则安全重启,如果没有配置则使用PHP_INT_MAX
     $this->maxRequests = (int) Lib\Config::get($this->workerName . '.max_requests');
     $this->maxRequests = $this->maxRequests <= 0 ? PHP_INT_MAX : $this->maxRequests;
     // 预读数据长度,长连接需要设置此项
     $preread_length = (int) Lib\Config::get($this->workerName . '.preread_length');
     if ($preread_length > 0) {
         $this->prereadLength = $preread_length;
     } elseif (!$this->isPersistentConnection) {
         $this->prereadLength = 65535;
     }
     // 接收缓冲区大小限制
     if (($max_recv_buffer_size = Lib\Config::get($this->workerName . '.max_recv_buffer_size')) && $max_recv_buffer_size > 0) {
         $this->maxRecvBufferSize = $max_recv_buffer_size;
     }
     // 发送缓冲区大小限制
     if (($max_send_buffer_size = Lib\Config::get($this->workerName . '.max_send_buffer_size')) && $max_send_buffer_size > 0) {
         $this->maxSendBufferSize = $max_send_buffer_size;
     }
     // worker启动时间
     $this->statusInfo['start_time'] = time();
     //事件轮询库
     if (extension_loaded('libevent')) {
         $this->setEventLoopName('Libevent');
     }
     // 检查退出状态
     $this->addShutdownHook();
     // 初始化事件轮询库
     $this->event = new $this->eventLoopName();
 }
Example #20
0
 /**
  * 构造函数
  * @param int $port
  * @param string $ip
  * @param string $protocol
  * @return void
  */
 public function __construct($worker_name = null)
 {
     // worker name
     $this->workerName = $worker_name ? $worker_name : get_class($this);
     // 是否开启长连接
     $this->isPersistentConnection = (bool) Lib\Config::get($this->workerName . '.persistent_connection');
     // 最大请求数,如果没有配置则使用PHP_INT_MAX
     $this->maxRequests = (int) Lib\Config::get($this->workerName . '.max_requests');
     $this->maxRequests = $this->maxRequests <= 0 ? PHP_INT_MAX : $this->maxRequests;
     $preread_length = (int) Lib\Config::get($this->workerName . '.preread_length');
     if ($preread_length > 0) {
         $this->prereadLength = $preread_length;
     } elseif (!$this->isPersistentConnection) {
         $this->prereadLength = 65535;
     }
     // worker启动时间
     $this->statusInfo['start_time'] = time();
     //事件轮询库
     if (extension_loaded('libevent')) {
         $this->setEventLoopName('Libevent');
     }
     // 检查退出状态
     $this->addShutdownHook();
     // 初始化事件轮询库
     // $this->event = new Libevent();
     // $this->event = new Select();
     $this->event = new $this->eventLoopName();
 }
Example #21
0
 /**
  * 根据配置文件创建Workers
  * @return void
  */
 protected static function createWorkers()
 {
     require_once WORKERMAN_ROOT_DIR . 'Core/ThreadWorker.php';
     $workers = Lib\Config::getAllWorkers();
     foreach ($workers as $worker_name => $config) {
         $main_socket = isset(self::$listenedSockets[$worker_name]) ? self::$listenedSockets[$worker_name] : null;
         $worker_file = \Man\Core\Lib\Config::get($worker_name . '.worker_file');
         self::$threads[$worker_name] = new \Pool($config['start_workers'], '\\Man\\Core\\Worker', array($main_socket, $worker_file, $worker_name));
         for ($i = 0; $i < $config['start_workers']; $i++) {
             self::$threads[$worker_name]->submit(new ThreadWorker());
         }
     }
 }