walkor 12 سال پیش
والد
کامیت
fb2db414e5

+ 82 - 0
Applications/GameBuffer.php

@@ -0,0 +1,82 @@
+<?php
+/**
+ * 
+ * 命令字相关
+* @author walkor <worker-man@qq.com>
+* 
+ */
+require_once WORKERMAN_ROOT_DIR . 'Protocols/Buffer.php';
+require_once WORKERMAN_ROOT_DIR . 'Applications/System.php';
+
+class GameBuffer extends WORKERMAN\Protocols\Buffer
+{
+    // 系统命令
+    const CMD_SYSTEM = 128;
+    // 连接事件 
+    const SCMD_ON_CONNECT = 1;
+    // 关闭事件
+    const SCMD_ON_CLOSE = 2;
+    
+    // 发送给网关的命令
+    const CMD_GATEWAY = 129;
+    // 给用户发送数据包
+    const SCMD_SEND_DATA = 1;
+    // 根据uid踢人
+    const SCMD_KICK_UID = 2;
+    // 根据地址和socket编号踢人
+    const SCMD_KICK_ADDRESS = 3;
+    // 广播内容
+    const SCMD_BROADCAST = 4;
+    
+    // 用户中心
+    const CMD_USER = 1;
+    // 登录
+    const SCMD_LOGIN = 1 ;
+    // 获取用户内部通信网关
+    const SCMD_GET_GATEWAY = 4;
+    
+    // 普通业务处理
+    const CMD_MAP  = 2;
+   
+    public static $cmdMap = array(
+            self::CMD_USER  => 'User',
+            self::CMD_MAP => 'Map',
+            self::CMD_GATEWAY => 'GateWay',
+            self::CMD_SYSTEM => 'System',
+     );
+    
+    public static $scmdMap = array(
+            self::SCMD_BROADCAST     => 'broadcast',
+            self::SCMD_GET_GATEWAY => 'getGateway',
+            self::SCMD_LOGIN                => 'login',
+            self::SCMD_ON_CONNECT   =>'onConnect',
+            self::SCMD_ON_CLOSE         => 'onClose',
+     );
+    
+    public static function sendToGateway($address, $bin_data, $to_uid = 0, $from_uid = 0)
+    {
+        $client = stream_socket_client($address);
+        $len = stream_socket_sendto($client, $bin_data);
+        return $len == strlen($bin_data);
+    }
+    
+    public static function sendToUid($uid, $buffer)
+    {
+        $address = System::getAddressByUid($uid);
+        if($address)
+        {
+            return self::sendToGateway($address, $buffer);
+        }
+        return false;
+    }
+    
+    public static function sendToAll($buffer)
+    {
+        $data = GameBuffer::decode($buffer);
+        $all_addresses = Store::get('GLOBAL_GATEWAY_ADDRESS');
+        foreach($all_addresses as $address)
+        {
+            self::sendToGateway($address, $buffer);
+        }
+    }
+}

+ 16 - 0
Applications/Model/User.php

@@ -0,0 +1,16 @@
+<?php
+/**
+ * 
+ * 命令字相关
+* @author walkor <worker-man@qq.com>
+* 
+ */
+require_once WORKERMAN_ROOT_DIR . 'Protocols/Buffer.php';
+
+class User 
+{
+   public static function login()
+   {
+       
+   }
+}

+ 26 - 0
Applications/Store.php

@@ -0,0 +1,26 @@
+<?php
+/**
+ * 
+ * 
+ * @author walkor <worker-man@qq.com>
+ * 
+ */
+
+class Store
+{
+    public static function set($key, $value, $ttl = 0)
+    {
+        return apc_store($key, $value, $ttl);
+    }
+    
+   public static function get($key)
+   {
+       return apc_fetch($key);
+   }
+   
+   public static function delete($key)
+   {
+       return apc_delete($key);
+   }
+   
+}

+ 69 - 0
Applications/System.php

@@ -0,0 +1,69 @@
+<?php
+/**
+ * 
+ * 
+ * @author walkor <worker-man@qq.com>
+ * 
+ */
+require_once WORKERMAN_ROOT_DIR . 'Protocols/Buffer.php';
+
+class System
+{
+   public static function onConnection($address, $socket_id, $sid)
+   {
+       // 检查sid是否合法
+       $uid = self::getUidBySid();
+       // 不合法踢掉
+       if(!$uid)
+       {
+           self::kickAddress($address, $socket_id);
+           return;
+       }
+       
+       // 合法记录uid到address的映射
+       self::storeUidAddress($uid, $address);
+       
+       // 发送数据包到address,确认connection成功
+       self::notifyConnectionSuccess($address, $socket_id, $uid);
+   }
+   
+   public static function onClose($uid)
+   {
+       
+   }
+   
+   public static function kickUid($uid)
+   {
+       
+   }
+   
+   public static function kickAddress($address, $socket_id)
+   {
+       
+   }
+   
+   public static function storeUidAddress($uid, $address)
+   {
+       Store::set($uid, $address);
+   }
+   
+   public static function getAddressByUid($uid)
+   {
+       return Store::get($uid);
+   }
+   
+   public static function deleteUidAddress($uid)
+   {
+       return Store::delete($uid);
+   }
+   
+   protected static function notifyConnectionSuccess($address, $socket_id, $uid)
+   {
+       
+   }
+   
+   protected static function getUidBySid($sid)
+   {
+       return $sid;
+   }
+}

+ 0 - 135
Clients/StatisticClient.php

@@ -1,135 +0,0 @@
-<?php
-/**
- *
- * 上报接口调用统计信息的客户端 UDP协议
- * 用来统计调用量、成功率、耗时、错误码等信息
- *
- * @author liangl
- */
-class StatisticClient
-{
-    // udp最大包长 linux:65507 mac:9216
-    const MAX_UDP_PACKGE_SIZE  = 65507;
-    
-    // char类型能保存的最大数值
-    const MAX_CHAR_VALUE = 255;
-    // usigned short 能保存的最大数值
-    const MAX_UNSIGNED_SHORT_VALUE = 65535;
-    // 固定包长
-    const PACKEGE_FIXED_LENGTH = 25;
-    
-    /**
-     * [module=>[interface=>time_start, interface=>time_start ...], module=>[interface=>time_start..],..]
-     * @var array
-     */
-    protected static $timeMap = array();
-
-
-    /**
-     * 模块接口上报消耗时间记时
-     * @param string $module
-     * @param string $interface
-     * @return void
-     */
-    public static function tick($module = '', $interface = '')
-    {
-        self::$timeMap[$module][$interface] = microtime(true);
-    }
-
-
-    /**
-     * 模块接口上报统计
-     * 格式:
-     * struct{
-     *     int                                    code,                 // 返回码
-     *     unsigned int                           time,                 // 时间
-     *     float                                  cost_time,            // 消耗时间 单位秒 例如1.xxx
-     *     unsigned int                           source_ip,            // 来源ip
-     *     unsigned int                           target_ip,            // 目标ip
-     *     unsigned char                          success,              // 是否成功
-     *     unsigned char                          module_name_length,   // 模块名字长度
-     *     unsigned char                          interface_name_length,// 接口名字长度
-     *     unsigned short                         msg_length,           // 日志信息长度
-     *     unsigned char[module_name_length]      module,               // 模块名字
-     *     unsigned char[interface_name_length]   interface,            // 接口名字
-     *     char[msg_length]                       msg                   // 日志内容
-     *  }
-     * @param string $module 模块名/类名
-     * @param string $interface 接口名/方法名
-     * @param int $code 返回码
-     * @param string $msg 日志内容
-     * @param bool $success 是否成功
-     * @param string $ip ip1
-     * @param string $source_ip ip2
-     * @return true/false
-     */
-    public static function report($module, $interface, $code = 0, $msg = '', $success = true, $source_ip = '', $target_ip = '')
-    {
-        if(isset(self::$timeMap[$module][$interface]) && self::$timeMap[$module][$interface] > 0)
-        {
-            $time_start = self::$timeMap[$module][$interface];
-            self::$timeMap[$module][$interface] = 0;
-        }
-        else if(isset(self::$timeMap['']['']) && self::$timeMap[''][''] > 0)
-        {
-            $time_start = self::$timeMap[''][''];
-            self::$timeMap[''][''] = 0;
-        }
-        else
-        {
-            $time_start = microtime(true);
-        }
-         
-        if(strlen($module) > self::MAX_CHAR_VALUE)
-        {
-            $module = substr($module, 0, self::MAX_CHAR_VALUE);
-        }
-        if(strlen($interface) > self::MAX_CHAR_VALUE)
-        {
-            $interface = substr($interface, 0, self::MAX_CHAR_VALUE);
-        }
-        $module_name_length = strlen($module);
-        $interface_name_length = strlen($interface);
-        //花费的时间
-        $cost_time = microtime(true) - $time_start;
-        $avalible_size = self::MAX_UDP_PACKGE_SIZE - self::PACKEGE_FIXED_LENGTH - $module_name_length - $interface_name_length;
-        if(strlen($msg) > $avalible_size)
-        {
-            $msg = substr($msg, 0, $avalible_size);
-        }
-         
-        $data = pack("iIfIICCCS",
-                $code,
-                time(),
-                $cost_time,
-                $source_ip ? ip2long($source_ip) : ip2long('127.0.0.1'),
-                $target_ip ? ip2long($target_ip) : ip2long('127.0.0.1'),
-                $success ? 1 : 0,
-                $module_name_length,
-                $interface_name_length,
-                strlen($msg)
-        );
-         
-        return self::sendData($data.$module.$interface.$msg);
-    }
-
-    /**
-     * 发送统计数据到监控进程
-     *
-     * @param string $bin_data
-     * @param string $ip
-     * @param int $port
-     * @param string $protocol upd/tcp
-     * @return bool
-     */
-    private static function sendData($bin_data, $ip = '127.0.0.1', $port = 2207, $protocol = 'udp')
-    {
-        $socket = stream_socket_client("{$protocol}://$ip:{$port}");
-        if(!$socket)
-        {
-            return false;
-        }
-        $len = stream_socket_sendto($socket, $bin_data);
-        return $len == strlen($bin_data);
-    }
-}

+ 14 - 43
Config/main.ini

@@ -10,30 +10,32 @@ ipc_key=0x70010a2e
 ;开启共享内存大小
 shm_size=393216
 
-[ChatCenter]
+[GameGateway]
 socket[protocol] = tcp
-socket[port] = 8181
+socket[port] = 8282
 socket[persistent] = 1
-children_count = 1
+children_count = 5
 user = www-data
-preread_length = 3
+preread_length = 19
+lan_ip = 127.0.0.1
+game_worker[] = tcp://127.0.0.1:8383
+game_worker[] = tcp://127.0.0.1:8383
 
-[ChatGateway]
+[GameWorker]
 socket[protocol] = tcp
-socket[port] = 8282
+socket[port] = 8383
 socket[persistent] = 1
 children_count = 5
 user = www-data
-preread_length = 3
-inner_port_begin = 10000 
+preread_length = 19
 
-[ChatWorker]
+[DataCenter]
 socket[protocol] = tcp
-socket[port] = 8383
+socket[port] = 8181
 socket[persistent] = 1
-children_count = 5
+children_count = 1
 user = www-data
-preread_length = 3
+preread_length = 19
 
 ;监控框架的进程,并提供telnet接口
 [Monitor]
@@ -48,36 +50,5 @@ preread_length=64
 max_worker_exit_count=2000
 max_mem_limit=83886
 
-[StatisticWorker]
-socket[protocol]=udp
-socket[port]=2207
-children_count=1
-user=www-data
-
-[StatisticService]
-socket[protocol]=tcp
-socket[port]=20202
-children_count=1
-user=www-data
-
 ;[FileMonitor]
 ;children_count = 1
-
-[EchoWorker]
-socket[protocol] = tcp
-socket[port] = 20304
-socket[persistent] = 0
-children_count=5
-max_requests=10000
-user=www-data
-preread_length=64
-
-[BufferWorker]
-socket[protocol] = tcp
-socket[port] = 20305
-socket[persistent] = 1
-children_count=1
-max_requests=1000000
-user=www-data
-preread_length=15
-

+ 2 - 9
Core/SocketWorker.php

@@ -34,12 +34,6 @@ abstract class SocketWorker extends AbstractWorker
     const EXIT_WAIT_TIME = 3;
     
     /**
-     * 进程意外退出状态码
-     * @var integer
-     */ 
-    const EXIT_UNEXPECT_CODE = 119;
-    
-    /**
      * worker的传输层协议
      * @var string
      */
@@ -240,9 +234,8 @@ abstract class SocketWorker extends AbstractWorker
         
         // 主体循环,整个子进程会阻塞在这个函数上
         $ret = $this->event->loop();
-        $this->notice("evet->loop returned " . var_export($ret, true));
-        
-        exit(self::EXIT_UNEXPECT_CODE);
+        $this->notice('worker loop exit');
+        exit(0);
     }
     
     /**

+ 28 - 25
Protocols/Buffer.php

@@ -3,15 +3,17 @@ namespace WORKERMAN\Protocols;
 /**
  * 通用的server协议,二进制协议
  * 
- * struct JMProtocol
+ * struct BufferProtocol
  * {
  *     unsigned char     version,//版本
  *     unsigned short    series_id,//序列号 udp协议使用
  *     unsigned short    cmd,//主命令字
  *     unsigned short    sub_cmd,//子命令字
- *     int               code,//返回码
- *     unsigned int      pack_len,//包长
- *     char[pack_length] body//包体
+ *     int                         code,//返回码
+ *     unsigned int        from_uid,//来自用户uid
+ *     unsigned int        to_uid,//发往的uid
+ *     unsigned int       pack_len,//包长
+ *     char[pack_length-15] body//包体
  * }
  * 
  * @author walkor <worker-man@qq.com>
@@ -29,14 +31,8 @@ class Buffer
      * 包头长度
      * @var integer
      */
-    const HEAD_LEN = 15;
-    
-    /**
-     * 默认包体序列化类型
-     * @var integer
-     */
-    
-    const DEFAULT_SERIALIZE_TYPE = 0;
+    const HEAD_LEN = 19;
+     
     /**
      * 序列号,防止串包
      * @var integer
@@ -51,9 +47,11 @@ class Buffer
         'version'        => self::VERSION,
         'series_id'      => 0,
         'cmd'            => 0,
-        'sub_cmd'        => 0,
+        'sub_cmd'     => 0,
         'code'           => 0,
-        'pack_len'       => self::HEAD_LEN
+        'from_uid'    => 0,
+        'to_uid'         => 0,
+        'pack_len'    => self::HEAD_LEN
     );
     
     /**
@@ -90,23 +88,28 @@ class Buffer
     
     /**
      * 判断数据包是否都到了
-     * @param string $bin
-     * @return int int=0数据是完整的 int>1数据不完整,还要继续接收int字节
+     * @param string $buffer
+     * @return int int=0数据是完整的 int>0数据不完整,还要继续接收int字节
      */
-    public static function input($bin)
+    public static function input($buffer, &$data = null)
     {
-        $len = strlen($bin);
+        $len = strlen($buffer);
         if($len < self::HEAD_LEN)
         {
             return self::HEAD_LEN - $len;
         }
         
-        $unpack_data = unpack("Cversion/Sseries_id/Scmd/Ssub_cmd/icode/Ipack_len", $bin);
-        if($unpack_data['pack_len'] > $len)
+        $data = unpack("Cversion/Sseries_id/Scmd/Ssub_cmd/icode/Ifrom_uid/Ito_uid/Ipack_len", $buffer);
+        if($data['pack_len'] > $len)
         {
-            return $unpack_data['pack_len'] - $len;
+            return $data['pack_len'] - $len;
+        }
+        $data['body'] = '';
+        $body_len = $data['pack_len'] - self::HEAD_LEN;
+        if($body_len > 0)
+        {
+            $data['body'] = substr($buffer, self::HEAD_LEN, $body_len);
         }
-        
         return 0;
     }
     
@@ -129,17 +132,17 @@ class Buffer
     public function getBuffer()
     {
         $this->header['pack_len'] = self::HEAD_LEN + strlen($this->body);
-        return pack("CSSSiI", $this->header['version'],  $this->header['series_id'], $this->header['cmd'], $this->header['sub_cmd'], $this->header['code'], $this->header['pack_len']).$this->body;
+        return pack("CSSSiIII", $this->header['version'],  $this->header['series_id'], $this->header['cmd'], $this->header['sub_cmd'], $this->header['code'], $this->header['from_uid'], $this->header['to_uid'], $this->header['pack_len']).$this->body;
     }
     
     /**
      * 从二进制数据转换为数组
-     * @param string $bin
+     * @param string $buffer
      * @return array
      */    
     public static function decode($buffer)
     {
-        $data = unpack("Cversion/Sseries_id/Scmd/Ssub_cmd/icode/Ipack_len", $buffer);
+        $data = unpack("Cversion/Sseries_id/Scmd/Ssub_cmd/icode/Ifrom_uid/Ito_uid/Ipack_len", $buffer);
         $data['body'] = '';
         $body_len = $data['pack_len'] - self::HEAD_LEN;
         if($body_len > 0)

+ 1 - 1
Protocols/FastCGI.php

@@ -2,7 +2,7 @@
 
 /**
  * fastcgi 协议解析 相关
- * 简单实现,测试时使用,可能会有bug,不要用到生产环境
+ * 简单实现
 * @author walkor <worker-man@qq.com>
 * */
 class FastCGI{

+ 1 - 1
Protocols/SimpleFastCgi.php

@@ -5,7 +5,7 @@ namespace WORKERMAN\Protocols;
  * 简单实现,测试时使用,可能会有bug,不要用到生产环境
  * @author walkor <worker-man@qq.com>
  * */
-class FastCGI{
+class SimpleFastCgi{
     
     const VERSION_1            = 1;
 

+ 1 - 1
Protocols/SimpleHttp.php

@@ -2,7 +2,7 @@
 namespace WORKERMAN\Protocols;
 /**
  * http 协议解析 相关
- * 简单的实现,可能会有bug,不要用于生产环境
+ * 简单的实现 不支持header cookie
  * @author walkor <worker-man@qq.com>
  * */
 class SimpleHttp{

+ 14 - 0
Tests/game.php

@@ -0,0 +1,14 @@
+<?php 
+error_reporting(E_ALL);
+ini_set('display_errors', 'on');
+include '../Applications/GameBuffer.php';
+
+$sock = stream_socket_client("tcp://127.0.0.1:8282");
+if(!$sock)exit("can not create sock\n");
+
+$buf = new GameBuffer();
+$buf->body = '123'';
+
+fwrite($sock, $buf->getBuffer());
+var_export($ret = fread($sock, 1024));
+var_export(GameBuffer::decode($ret));

+ 0 - 25
Workers/BufferWorker.php

@@ -1,25 +0,0 @@
-<?php
-/**
- * 
- * 测试worker
-* @author walkor <worker-man@qq.com>
- */
-require_once WORKERMAN_ROOT_DIR . 'Core/SocketWorker.php';
-require_once WORKERMAN_ROOT_DIR . 'Protocols/Buffer.php';
-
-class BufferWorker extends WORKERMAN\Core\SocketWorker
-{
-    public function dealInput($recv_str)
-    {
-        $remian = \WORKERMAN\Protocols\Buffer::input($recv_str);
-        return $remian;
-    }
-
-    public function dealProcess($recv_str)
-    {
-        $buf = new \WORKERMAN\Protocols\Buffer();
-        $buf->header['code'] = 200;
-        $buf->body = 'haha';
-        $this->sendToClient($buf->getBuffer());
-    }
-}

+ 0 - 24
Workers/ChatGateway.php

@@ -1,24 +0,0 @@
-<?php
-/**
- * 
- * 暴露给客户端的连接网关 只负责网络io
- * 1、监听客户端连接
- * 2、监听后端回应并转发回应给前端
- * 
- * @author walkor <worker-man@qq.com>
- * 
- */
-require_once WORKERMAN_ROOT_DIR . 'Core/SocketWorker.php';
-
-class ChatGateway extends WORKERMAN\Core\SocketWorker
-{
-    public function dealInput($recv_str)
-    {
-        return 0; 
-    }
-
-    public function dealProcess($recv_str)
-    {
-        $this->sendToClient($recv_str);
-    }
-}

+ 0 - 24
Workers/ChatWorker.php

@@ -1,24 +0,0 @@
-<?php
-/**
- * 
- * 处理具体聊天逻辑
- * 1、查询某用户内网通信gateway ip及端口
- * 2、向某用户对应内网gateway ip及端口发送数据
- * 
- * @author walkor <worker-man@qq.com>
- * 
- */
-require_once WORKERMAN_ROOT_DIR . 'Core/SocketWorker.php';
-
-class ChatWorker extends WORKERMAN\Core\SocketWorker
-{
-    public function dealInput($recv_str)
-    {
-        return 0; 
-    }
-
-    public function dealProcess($recv_str)
-    {
-        $this->sendToClient($recv_str);
-    }
-}

+ 3 - 2
Workers/ChatCenter.php → Workers/DataCenter.php

@@ -10,12 +10,13 @@
  * 
  */
 require_once WORKERMAN_ROOT_DIR . 'Core/SocketWorker.php';
+require_once WORKERMAN_ROOT_DIR . 'Applications/GameBuffer.php';
 
-class ChatCenter extends WORKERMAN\Core\SocketWorker
+class DataCenter extends WORKERMAN\Core\SocketWorker
 {
     public function dealInput($recv_str)
     {
-        return 0; 
+        return GameBuffer::input($recv_str);
     }
 
     public function dealProcess($recv_str)

+ 266 - 0
Workers/GameGateway.php

@@ -0,0 +1,266 @@
+<?php
+/**
+ * 
+ * 暴露给客户端的连接网关 只负责网络io
+ * 1、监听客户端连接
+ * 2、监听后端回应并转发回应给前端
+ * 
+ * @author walkor <worker-man@qq.com>
+ * 
+ */
+require_once WORKERMAN_ROOT_DIR . 'Core/SocketWorker.php';
+require_once WORKERMAN_ROOT_DIR . 'Applications/GameBuffer.php';
+require_once WORKERMAN_ROOT_DIR . 'Applications/Store.php';
+
+class GameGateway extends WORKERMAN\Core\SocketWorker
+{
+    // 内部通信socket
+    protected $innerMainSocket = null;
+    // uid到连接的映射
+    protected $uidConnMap = array();
+    // 连接到uid的映射
+    protected $connUidMap = array();
+    
+    // 到GameWorker的通信地址
+    protected $workerAddresses = array();
+    
+    // 当前处理的包数据
+    protected $data = array();
+    
+    protected $onConnectBuffer = '';
+    protected $onCloseBuffer = ''; 
+    public function start()
+    {
+        // 安装信号处理函数
+        $this->installSignal();
+        
+        // 添加accept事件
+        $ret = $this->event->add($this->mainSocket,  WORKERMAN\Core\Events\BaseEvent::EV_READ, array($this, 'accept'));
+        
+        // 创建内部通信套接字
+        $inner_port = posix_getpid();
+        $lan_ip = WORKERMAN\Core\Lib\Config::get($this->workerName.'.lan_ip');
+        if(!$lan_ip)
+        {
+            $this->notice($this->workerName.'.lan_ip nost set');
+            $lan_ip = '127.0.0.1';
+        }
+        $error_no = 0;
+        $error_msg = '';
+        $this->innerMainSocket = stream_socket_server("udp://$lan_ip:$inner_port", $error_no, $error_msg, STREAM_SERVER_BIND);
+        if(!$this->innerMainSocket)
+        {
+            $this->notice('create innerMainSocket fail and exit '.$error_no . ':'.$error_msg);
+            sleep(1);
+            exit(0);
+        }
+        else
+        {
+            stream_set_blocking($this->innerMainSocket , 0);
+        }
+        
+        $this->registerAddress("udp://$lan_ip:$inner_port");
+        
+        // 添加读udp事件
+        $this->event->add($this->innerMainSocket,  WORKERMAN\Core\Events\BaseEvent::EV_READ, array($this, 'recvUdp'));
+        
+        // 初始化onConnetct / onclose buffer
+        $this->initOnBuffer();
+        
+        // 初始化到worker的通信地址
+        $this->initWorkerAddresses();
+        
+        // 主体循环,整个子进程会阻塞在这个函数上
+        $ret = $this->event->loop();
+        $this->notice('worker loop exit');
+        exit(0);
+    }
+    
+    /**
+     * 存储全局的通信地址
+     * @param string $address
+     * @todo 用锁机制等保证数据完整性
+     */
+    protected function registerAddress($address)
+    {
+        $key = 'GLOBAL_GATEWAY_ADDRESS';
+        $addresses = Store::get($key);
+        if(empty($addresses))
+        {
+            $addresses = array($address);
+        }
+        else
+        {
+            $addresses[] = $address;
+        }
+        Store::set($key, $addresses);
+    }
+    
+    /**
+     * 接收Udp数据
+     * 如果数据超过一个udp包长,需要业务自己解析包体,判断数据是否全部到达
+     * @param resource $socket
+     * @param $null_one $flag
+     * @param $null_two $base
+     * @return void
+     */
+    public function recvUdp($socket, $null_one = null, $null_two = null)
+    {
+        $data = stream_socket_recvfrom($socket , self::MAX_UDP_PACKEG_SIZE, 0, $address);
+        // 惊群效应
+        if(false === $data || empty($address))
+        {
+            return false;
+        }
+         
+        $this->currentClientAddress = $address;
+       
+        $this->innerDealProcess($data);
+    }
+    
+    protected function initOnBuffer()
+    {
+        $buffer = new GameBuffer();
+        $buffer->header['cmd'] = GameBuffer::CMD_SYSTEM;
+        $buffer->header['sub_cmd'] = GameBuffer::SCMD_ON_CONNECT;
+        $buffer->body = '';
+        $this->onConnectBuffer = $buffer->getBuffer();
+        $buffer->header['sub_cmd'] = GameBuffer::SCMD_ON_CLOSE;
+        $this->onCloseBuffer = $buffer->getBuffer();
+    }
+    
+    protected function initWorkerAddresses()
+    {
+        $this->workerAddresses = WORKERMAN\Core\Lib\Config::get($this->workerName.'.game_worker');
+        if(!$this->workerAddresses)
+        {
+            $this->notice($this->workerName.'game_worker not set');
+        }
+    }
+    
+    public function dealInput($recv_str)
+    {
+        return GameBuffer::input($recv_str, $this->data);
+    }
+
+    public function innerDealProcess($recv_str)
+    {
+        $data = GameBuffer::decode($recv_str);
+        if($data['cmd'] != GameBuffer::CMD_GATEWAY)
+        {
+            $this->notice('gateway inner pack err data:' .$recv_str . ' serialize:' . serialize($data) );
+            return;
+        }
+        switch($data['sub_cmd'])
+        {
+            case GameBuffer::SCMD_SEND_DATA:
+                return $this->sendToUid($data['to_uid'], $recv_str);
+               
+            case GameBuffer::SCMD_KICK_UID:
+                return $this->closeClientByUid($data['to_uid'] );
+                
+            case GameBuffer::SCMD_KICK_ADDRESS:
+                $fd = (int)trim($data['body']);
+                $uid = $this->getUidByFd($fd);
+                if($uid)
+                {
+                    return $this->closeClientByUid($uid);
+                }
+                return;
+            case GameBuffer::SCMD_BROADCAST:
+                return $this->broadCast($recv_str);
+        }
+    }
+    
+    protected function broadCast($bin_data)
+    {
+        foreach($this->uidConnMap as $uid=>$conn)
+        {
+            $this->sendToUid($uid, $bin_data);
+        }
+    }
+    
+    public function closeClientByUid($uid)
+    {
+        $fd = $this->getFdByUid($uid);
+        if($fd)
+        {
+            unset($this->uidConnMap[$uid], $this->connUidMap[$fd]);
+            parent::closeClient($fd);
+        }
+    }
+    
+    protected function getFdByUid($uid)
+    {
+        if(isset($this->uidConnMap[$uid]))
+        {
+            return $this->uidConnMap[$uid];
+        }
+        return 0;
+    }
+    
+    protected function getUidByFd($fd)
+    {
+        if(isset($this->connUidMap[$fd]))
+        {
+            return $this->connUidMap[$fd];
+        }
+        return 0;
+    }
+    
+    public function sendToUid($uid, $bin_data)
+    {
+        if(!isset($this->uidConnMap[$uid]))
+        {
+            return false;
+        }
+        $send_len = fwrite($this->connections[$this->uidConnMap[$uid]], $bin_data);
+        return $send_len == strlen($bin_data);
+    }
+    
+    public function dealProcess($recv_str)
+    {
+        // 判断用户是否认证过
+        $from_uid = $this->getUidByFd($this->currentDealFd);
+        if(!$from_uid)
+        {
+            // 没传sid
+            if(empty($this->data->body))
+            {
+                $this->notice("onConnect miss sid ip:".$this->getRemoteIp(). " data[".serialize($this->data)."]");
+                $this->closeClient($this->currentDealFd);
+                return;
+            }
+            // 发送onconnet事件包,包体是sid
+            $this->sendToWorker($this->onConnectBuffer.$this->data->body);
+            return;
+        }
+        
+        // 认证过
+        $this->fillFromUid($recv_str, $from_uid);
+        $this->sendToWorker($recv_str);
+    }
+    
+    // 讲协议的from_uid填充为正确的值
+    protected function fillFromUid(&$bin_data, $from_uid)
+    {
+        // from_uid在包头的12-15字节
+        $bin_data = substr_replace($bin_data, pack('I', $from_uid), 11, 4);
+    }
+    
+    protected function sendToWorker($bin_data)
+    {
+        $len = stream_socket_sendto($this->innerMainSocket, $bin_data, 0, $this->workerAddresses[array_rand($this->workerAddresses)]);
+        return $len == strlen($bin_data);
+    }
+    
+    protected function notice($str, $display=true)
+    {
+        $str = 'Worker['.get_class($this).']:'."$str ip:".$this->getRemoteIp();
+        WORKERMAN\Core\Lib\Log::add($str);
+        if($display && WORKERMAN\Core\Lib\Config::get('debug') == 1)
+        {
+            echo $str."\n";
+        }
+    }
+}

+ 39 - 0
Workers/GameWorker.php

@@ -0,0 +1,39 @@
+<?php
+/**
+ * 
+ * 处理具体聊天逻辑
+ * 1、查询某用户内网通信gateway ip及端口
+ * 2、向某用户对应内网gateway ip及端口发送数据
+ * 
+ * @author walkor <worker-man@qq.com>
+ * 
+ */
+require_once WORKERMAN_ROOT_DIR . 'Core/SocketWorker.php';
+require_once WORKERMAN_ROOT_DIR . 'Applications/GameBuffer.php';
+require_once WORKERMAN_ROOT_DIR . 'Applications/Store.php';
+
+class GameWorker extends WORKERMAN\Core\SocketWorker
+{
+    protected $data = array();
+    public function dealInput($recv_str)
+    {
+        return GameBuffer::input($recv_str, $this->data); 
+    }
+
+    public function dealProcess($recv_str)
+    {
+        if(!isset(GameBuffer::$cmdMap[$this->data['cmd']]) || !isset(GameBuffer::$scmdMap[$this->data['sub_cmd']]))
+        {
+            $this->notice('cmd err ' . serialize($this->data) );
+            return;
+        }
+        $class = GameBuffer::$cmdMap[$this->data['cmd']];
+        $method = GameBuffer::$scmdMap[$this->data['sub_cmd']];
+        if(!method_exists($class, $method))
+        {
+            $this->notice("cmd err $class::$method not exists");
+            return;
+        }
+        call_user_func_array(array($class, $method),  $this->data);
+    }
+}

+ 0 - 966
Workers/StatisticService.php

@@ -1,966 +0,0 @@
-<?php 
-require_once WORKERMAN_ROOT_DIR . 'Core/SocketWorker.php';
-require_once WORKERMAN_ROOT_DIR . 'Protocols/SimpleHttp.php';
-
-/**
- * 
- * 统计中心对外服务进程 查询日志 查询接口调用量 延迟 成功率等
- * 采用http协议对外服务 使用http:://Server_ip:20202 地址查询统计结果
- * 
-* @author walkor <worker-man@qq.com>
- */
-
-class StatisticService extends WORKERMAN\Core\SocketWorker
-{
-    
-    /**
-     * 判断包是否都到达
-     * @see Worker::dealInput()
-     */
-    public function dealInput($recv_str)
-    {
-        return \WORKERMAN\Protocols\SimpleHttp::input($recv_str);
-    }
-    
-    /**
-     * 处理业务逻辑 查询log 查询统计信息
-     * @see Worker::dealProcess()
-     */
-    public function dealProcess($recv_str)
-    {
-        \WORKERMAN\Protocols\SimpleHttp::decode($recv_str);
-        $module = isset($_GET['module']) ? trim($_GET['module']) : '';
-        $interface = isset($_GET['interface']) ? trim($_GET['interface']) : '';
-        $start_time = isset($_GET['start_time']) ? trim($_GET['start_time']) : '';
-        $end_time = isset($_GET['end_time']) ? trim($_GET['end_time']) : '';
-        
-        if(0 === strpos($_SERVER['REQUEST_URI'], '/graph'))
-        {
-            if(!extension_loaded('gd'))
-            {
-                return $this->sendToClient("not suport gd\n");
-            }
-            $type_map = array('request','time');
-            $type = isset($_GET['type']) && in_array($_GET['type'], $type_map) ?  $_GET['type'] : 'request';
-            $this->displayGraph($module, $interface, $type, $start_time);
-        }
-        // 日志
-        elseif(0 === strpos($_SERVER['REQUEST_URI'], '/log'))
-        {
-            $right_str = '';
-            $code = isset($_GET['code']) ? $_GET['code'] : '';
-            $msg = isset($_GET['msg']) ? $_GET['msg'] : '';
-            $pointer = isset($_GET['pointer']) ? $_GET['pointer'] : '';
-            $count = isset($_GET['count']) ? $_GET['count'] : 100;
-            $log_data = $this->getStasticLog($module, $interface , $start_time , $end_time, $code, $msg , $pointer, $count);
-            
-            if($log_data['pointer'] == 0)
-            {
-                return $this->display($log_data['data']);
-            }
-            else
-            {
-                $_GET['pointer'] = $log_data['pointer'];
-                unset($_GET['end_time']);
-                $next_page_url = http_build_query($_GET);
-                $log_data['data'] .= "</br><center><a href='/log/?$next_page_url'>下一页</a></center>";
-                return $this->display(nl2br($log_data['data']));
-            }
-            
-        }
-        // 统计
-        else
-        {
-            // 首页
-            if(empty($module))
-            {
-                return $this->home();
-            }
-            else
-            {
-                if($interface)
-                {
-                    return $this->displayInterface($module, $interface, $start_time, $end_time);
-                }
-                else
-                {
-                    return $this->display();
-                }
-            }
-            
-        }
-        
-        return $this->display();
-    }
-    
-    /**
-     * 统计主页
-     * @return void
-     */
-    protected function home()
-    {
-        $data = '';
-        $address = '127.0.0.1:10101';
-        $sock = stream_socket_client($address);
-        if(!$sock)
-        {
-            return $this->display();
-        }
-        fwrite($sock, 'status');
-        $read_fds = array($sock);
-        $write_fds = $except_fds = array();
-        $time_start = time();
-        while(1)
-        {
-            $ret = @stream_select($read_fds, $write_fds, $except_fds, 1);
-            if(!$ret)
-            {
-                if(time() - $time_start >= 1)
-                {
-                    break;
-                }
-                continue;
-            }
-            foreach($read_fds as $fd)
-            {
-                if($ret_str = fread($fd, 8192))
-                {
-                    $data .= $ret_str;
-                }
-                else
-                {
-                    break;
-                }
-            }
-            if(time() - $time_start >= 1)
-            {
-                break;
-            }
-        }
-        
-        $data = '<pre>'.$data.'</pre>';
-        
-        return $this->display($data);
-    }
-    
-    /**
-     * 接口统计信息
-     * @param string $module
-     * @param string $interface
-     * @param int $start_time
-     * @param int $end_time
-     * @return void
-     */
-    protected function displayInterface($module ,$interface, $start_time, $end_time)
-    {
-        $data = $this->getStatistic($module, $interface, $start_time, $end_time);
-        $suport_gd = extension_loaded('gd');
-        $right_str = '
-        <center>模块:'.$module.' &nbsp; 接口:'.$interface.'</center>
-        </br>
-        '.($suport_gd ? '
-        <img src="/graph/?module='.$module.'&interface='.$interface.'&type=request&start_time='.$start_time.'"/>' : '未安装gd库,图形无法展示') .'
-        <center>请求量</center>
-        </br>
-        '.($suport_gd ? '
-        <img src="/graph/?module='.$module.'&interface='.$interface.'&type=time&start_time='.$start_time.'"/>' : '未安装gd库,图形无法展示') .'
-        <center>延迟单位:秒</center>
-        </br>';
-        
-        $right_str .= '<center>';
-        
-        $date_array = $this->getAvailableStDate($module, $interface);
-        $current_key = strtotime(date('Y-m-d', $start_time ? $start_time : time()));
-        if(!isset($date_array[$current_key]))
-        {
-            $date_array[$current_key] = date('Y-m-d', $current_key);
-        }
-        unset($_GET['start_time']);
-        $st_url = http_build_query($_GET);
-        $date_array_chunk = array_chunk($date_array, 7, true);
-        if($date_array_chunk)
-        {
-            foreach($date_array_chunk as $date_array)
-            {
-                foreach($date_array as $time_stamp => $date)
-                {
-                    $right_str .= ($current_key == $time_stamp) ? ('<a href=/st/?'.$st_url.'&start_time='.$time_stamp.'><b>'.$date.'</b></a>&nbsp;&nbsp;') : ('<a href=/st/?'.$st_url.'&start_time='.$time_stamp.'>'.$date.'</a>&nbsp;&nbsp;');
-                }
-                $right_str .= "<br>";
-            }
-        }
-        
-        $right_str .='<br><br></center>';
-        
-        $right_str .='<table>
-        <tr align="center">
-        <th >时间</th><th>调用总数</th><th>平均耗时</th><th>成功调用总数</th><th>成功平均耗时</th><th>失败调用总数</th><th>失败平均耗时</th><th>成功率</th>
-        </tr>
-        ';
-        
-        if($data)
-        {
-            foreach($data as $item)
-            {
-                $right_str .= "<tr align='center'><td>{$item['time']}</td><td>{$item['total_count']}</td><td>{$item['total_avg_time']}</td><td>{$item['suc_count']}</td><td>{$item['suc_avg_time']}</td><td>".($item['fail_count']>0?("<a href='/log/?module=$module&interface=$interface&start_time=".strtotime($item['time'])."&end_time=".(strtotime($item['time'])+300)."'>{$item['fail_count']}</a>"):$item['fail_count'])."</td><td>{$item['fail_avg_time']}</td><td>".($item['precent']<=98?'<font style="color:red">'.$item['precent'].'%</font>' : $item['precent'].'%')."</td></tr>\n"; 
-            }
-        }
-        
-        $right_str .= '</table>'; 
-        
-        return $this->display($right_str);
-        
-    }
-    
-    /**
-     * 展示曲线图
-     * @param string $module
-     * @param string $interface
-     * @param string $type
-     * @param integer $start_time
-     * @return void
-     */
-    protected function displayGraph($module ,$interface, $type = 'request', $start_time = '')
-    {
-        $data = $this->getStatistic($module, $interface, $start_time);
-        \WORKERMAN\Protocols\SimpleHttp::header("Content-type: image/jpeg");
-        $gg=new buildGraph();
-        $d2 = $d3 = array();
-        $time_point = $start_time ? strtotime(date('Y-m-d',$start_time)) : strtotime(date('Y-m-d'));
-        switch($type)
-        {
-            case 'time':
-                for($i=0;$i<288;$i++)
-                {
-                    $time_point +=300;
-                    $d2[$time_point] = isset($data[$time_point]['total_avg_time']) ? $data[$time_point]['total_avg_time'] : 0;
-                    $d3[$time_point] = isset($data[$time_point]['fail_avg_time']) ? $data[$time_point]['fail_avg_time'] : 0;
-                }
-                break;
-            default:
-                for($i=0;$i<288;$i++)
-                {
-                    $time_point +=300;
-                    $d2[$time_point] = isset($data[$time_point]['total_count']) ? $data[$time_point]['total_count'] : 0;
-                    $d3[$time_point] = isset($data[$time_point]['fail_count']) ? $data[$time_point]['fail_count'] : 0;
-                }
-        }
-        
-        $d2 = array_values($d2);
-        $d3 = array_values($d3);
-        
-        $gg->addData($d2);
-        $gg->addData($d3);
-        $gg->setColors("088A08,b40404");
-        ob_start();
-        // 生成曲线图
-        $gg->build("line",0);      // 参数0表示显示所有曲线,1为显示第一条,依次类推 
-        return $this->sendToClient(\WORKERMAN\Protocols\SimpleHttp::encode(ob_get_clean()));
-    }
-    
-    /**
-     * 获取模块
-     * @return array
-     */
-    public function getModules()
-    {
-        $st_dir = WORKERMAN_LOG_DIR . 'statistic/st/';
-        return glob($st_dir."/*");
-    }
-    
-    /**
-     * 渲染页面
-     * @param string $data
-     * @return bool
-     */
-    protected function display($data=null)
-    {
-        $left_detail = '';
-        $html_left = '<ul>';
-        $current_module = empty($_GET['module']) ? '' : $_GET['module'];
-        if($current_module)
-        {
-            $st_dir = WORKERMAN_LOG_DIR . 'statistic/st/'.$current_module.'/';
-            $all_interface = array();
-            foreach(glob($st_dir."*") as $file)
-            {
-                if(is_dir($file))
-                {
-                    continue;
-                }
-                $tmp = explode("|", basename($file));
-                $interface = trim($tmp[0]);
-                if(isset($all_interface[$interface]))
-                {
-                    continue;
-                }
-                $all_interface[$interface] = $interface;
-                $left_detail .= '<li>&nbsp;&nbsp;&nbsp;&nbsp;<a href="/st/?module='.$current_module.'&interface='.$interface.'">'.$interface.'</a></li>';
-            }
-            
-        }
-        
-        $modules_name_array = $this->getModules();
-        if($modules_name_array)
-        {
-            foreach($modules_name_array as $module_file)
-            {
-                $tmp = explode("/", $module_file);
-                $module = end($tmp);
-                $html_left .= '<li><a href="/st/?module='.$module.'">'.$module.'</a></li>';
-                if($module == $current_module)
-                {
-                    $html_left .= $left_detail;
-                }
-            }
-        }
-        $display_str = <<<EOC
-<html>
-<head>
-<title>WORKERMAN监控</title>
-</head>
-<table>
-<tr valign='top'>
-<td style="border-right:3px solid #dddddd">$html_left</td>
-<td>$data</td>
-</tr>
-</table>
-</html>    
-EOC;
-        return $this->sendToClient(\WORKERMAN\Protocols\SimpleHttp::encode($display_str));
-    }
-    
-    /**
-     * 日志二分查找法
-     * @param int $start_point
-     * @param int $end_point
-     * @param int $time
-     * @param fd $fd
-     * @return int
-     */
-    protected function binarySearch($start_point, $end_point, $time, $fd)
-    {
-        // 计算中点
-        $mid_point = (int)(($end_point+$start_point)/2);
-        
-        // 定位文件指针在中点
-        fseek($fd, $mid_point);
-        
-        // 读第一行
-        $line = fgets($fd);
-        if(feof($fd) || false === $line)
-        {
-            return ftell($fd);
-        }
-        
-        // 第一行可能数据不全,再读一行
-        $line = fgets($fd);
-        if(feof($fd) || false === $line || trim($line) == '')
-        {
-            return ftell($fd);
-        }
-        
-        // 判断是否越界
-        $current_point = ftell($fd);
-        if($current_point>=$end_point)
-        {
-            return $end_point;
-        }
-        
-        // 获得时间
-        $tmp = explode("\t", $line);
-        $tmp_time = strtotime($tmp[0]);
-        
-        // 判断时间,返回指针位置
-        if($tmp_time > $time)
-        {
-            return $this->binarySearch($start_point, $current_point, $time, $fd);
-        } 
-        elseif($tmp_time < $time)
-        {
-            return $this->binarySearch($current_point, $end_point, $time, $fd);
-        }
-        else
-        {
-            return $current_point;
-        }
-    }
-    
-    /**
-     * 获取指定日志
-     * @return array
-     */
-    protected function getStasticLog($module, $interface , $start_time = '', $end_time = '', $code = '', $msg = '', $pointer='', $count=100)
-    {
-        // log文件
-        $log_file = WORKERMAN_LOG_DIR . 'statistic/log/'. ($start_time === '' ? date('Y-m-d') : date('Y-m-d', $start_time));
-        if(!is_readable($log_file))
-        {
-            return array('pointer'=>0, 'data'=>$log_file . 'not exists or not readable');
-        }
-        // 读文件
-        $h = fopen($log_file, 'r');
-        
-        // 如果有时间,则进行二分查找,加速查询
-        if($start_time && $pointer === '' && ($file_size = filesize($log_file) > 5000))
-        {
-            $pointer = $this->binarySearch(0, $file_size, $start_time-1, $h);
-            $pointer = $pointer < 1000 ? 0 : $pointer - 1000; 
-        }
-        
-        // 正则表达式
-        $pattern = "/^([\d: \-]+)\t";
-        
-        if($module)
-        {
-            $pattern .= $module."::";
-        }
-        else
-        {
-            $pattern .= ".*::";
-        }
-        
-        if($interface)
-        {
-            $pattern .= $interface."\t";
-        }
-        else
-        {
-            $pattern .= ".*\t";
-        }
-        
-        if($code !== '')
-        {
-            $pattern .= "code:$code\t";
-        }
-        else 
-        {
-            $pattern .= "code:\d+\t";
-        }
-        
-        if($msg)
-        {
-            $pattern .= "msg:$msg";
-        }
-       
-        $pattern .= '/';
-        
-        // 指定偏移位置
-        if($pointer >= 0)
-        {
-            fseek($h, (int)$pointer);
-        }
-        
-        // 查找符合条件的数据
-        $now_count = 0;
-        $log_buffer = '';
-        
-        while(1)
-        {
-            if(feof($h))
-            {
-                break;
-            }
-            // 读1行
-            $line = fgets($h);
-            if(preg_match($pattern, $line, $match))
-            {
-                // 判断时间是否符合要求
-                $time = strtotime($match[1]);
-                if($start_time)
-                {
-                    if($time<$start_time)
-                    {
-                        continue;
-                    }
-                }
-                if($end_time)
-                {
-                    if($time>$end_time)
-                    {
-                        break;
-                    }
-                }                                    
-                // 收集符合条件的log
-                $log_buffer .= $line;
-                if(++$now_count >= $count)
-                {
-                    break;
-                }
-            }
-        }
-        // 记录偏移位置
-        $pointer = ftell($h);
-        return array('pointer'=>$pointer, 'data'=>$log_buffer);
-    }
-    
-    
-    /**
-     * 获取统计数据
-     * @param string $module
-     * @param string $interface
-     * @param integer $start_time
-     * @param integer $end_time
-     * @return array
-     */
-    protected function getStatistic($module, $interface, $start_time='',$end_time='')
-    {
-        
-        // 正则表达式
-        $need_preg_match =  $start_time || $end_time;
-        $pattern = '';
-        if($need_preg_match)
-        {
-            $pattern .= "/^[\d\.]+\t(\d+)\t/";
-        }
-        
-        // log文件
-        $log_file = WORKERMAN_LOG_DIR . "statistic/st/{$module}/{$interface}|". ($start_time === '' ? date('Y-m-d') : date('Y-m-d', $start_time));
-        if(!is_readable($log_file))
-        {
-            return false;
-        }
-        
-        // 读文件
-        $h = fopen($log_file, 'r');
-        
-        // time:[suc_count:xx,suc_cost_time:xx,fail_count:xx,fail_cost_time:xx]
-        $st_data = array();
-        // 汇总计算
-        while(1)
-        {
-            if(feof($h))
-            {
-                break;
-            }
-            // 读1行
-            $line = fgets($h);
-            if(empty($line))
-            {
-                continue;
-            }
-            if($need_preg_match && preg_match($pattern, $line, $match))
-            {
-                // 判断时间是否符合要求
-                $time = $match[1];
-                if($start_time)
-                {
-                    if($time<=$start_time)
-                    {
-                        continue;
-                    }
-                }
-                if($end_time)
-                {
-                    if($time>=$end_time)
-                    {
-                        continue;
-                    }
-                }
-                
-            }
-            // line = IP time suc_count suc_cost_time fail_count fail_cost_time code_json
-            $line_data = explode("\t", $line);
-            $time_line = $line_data[1];
-            $suc_count = $line_data[2];
-            $suc_cost_time = $line_data[3];
-            $fail_count = $line_data[4];
-            $fail_cost_time = $line_data[5];
-            if(!isset($st_data[$time_line]))
-            {
-                $st_data[$time_line] = array('suc_count'=>0, 'suc_cost_time'=>0, 'fail_count'=>0, 'fail_cost_time'=>0);
-            }
-            $st_data[$time_line]['suc_count'] += $suc_count;
-            $st_data[$time_line]['suc_cost_time'] += $suc_cost_time;
-            $st_data[$time_line]['fail_count'] += $fail_count;
-            $st_data[$time_line]['fail_cost_time'] += $fail_cost_time;
-        }
-        // 按照时间排序
-        ksort($st_data);
-        // time => [total_count:xx,suc_count:xx,suc_avg_time:xx,fail_count:xx,fail_avg_time:xx,percent:xx]
-        $data = array();
-        // 计算成功率 耗时
-        foreach($st_data as $time_line=>$item)
-        {
-            $data[$time_line] = array(
-                'time'          => date('Y-m-d H:i:s', $time_line),
-                'total_count'   => $item['suc_count']+$item['fail_count'],
-                'total_avg_time'=> $item['suc_count']+$item['fail_count'] == 0 ? 0 : round(($item['suc_cost_time']+$item['fail_cost_time'])/($item['suc_count']+$item['fail_count']), 4),
-                'suc_count'     => $item['suc_count'],
-                'suc_avg_time'  => $item['suc_count'] == 0 ? $item['suc_count'] : round($item['suc_cost_time']/$item['suc_count'], 4),
-                'fail_count'    => $item['fail_count'],
-                'fail_avg_time' => $item['fail_count'] == 0 ? 0 : round($item['fail_cost_time']/$item['fail_count'], 4),
-                'precent'       => $item['suc_count']+$item['fail_count'] == 0 ? 0 : round(($item['suc_count']*100/($item['suc_count']+$item['fail_count'])), 4),
-            );
-        }
-        $max_time_line = $time_line;
-        $time_point = $start_time ? strtotime(date('Y-m-d', $start_time)) : strtotime(date('Y-m-d'))+300;
-        for($i=0;$i<288,$time_point<=$max_time_line;$i++)
-        {
-            $data[$time_point] = isset($data[$time_point]) ? $data[$time_point] : 
-            array(
-                    'time'          => date('Y-m-d H:i:s', $time_point),
-                    'total_count'   => 0,
-                    'total_avg_time'=> 0,
-                    'suc_count'     => 0,
-                    'suc_avg_time'  => 0,
-                    'fail_count'    => 0,
-                    'fail_avg_time' => 0,
-                    'precent'       => 100,
-                    );
-            $time_point +=300;
-        }
-        ksort($data);
-        return $data;
-    }
-    
-    /**
-     * 获取能展示统计数据的日期
-     * @param string $module
-     * @param string $interface
-     * @return array
-     */
-    protected function getAvailableStDate($module, $interface)
-    {
-        $date_array = array();
-        $st_dir = WORKERMAN_LOG_DIR . 'statistic/st/'.$module.'/';
-        foreach(glob($st_dir."$interface|*") as $stFile)
-        {
-            $base_name = basename($stFile);
-            $tmp = explode('|', $base_name);
-            $date_array[strtotime($tmp[1])] = $tmp[1];
-        }
-        ksort($date_array);
-        return $date_array;
-    }
-    
-    /**
-     * 缓冲页面输出(non-PHPdoc)
-     * @see SocketWorker::onStart()
-     */
-    public function onStart()
-    {
-        ob_start();
-    }
-    
-    /**
-     * 获取缓冲(non-PHPdoc)
-     * @see SocketWorker::onAlarm()
-     */
-    public function onAlarm()
-    {
-        $ob_content = ob_get_contents();
-        if($ob_content)
-        {
-            \WORKERMAN\Core\Lib\Log::add('StatisticService:ob_content:'.$ob_content);
-            ob_clean();
-        }
-    }
-    
-}
-
-
-/**
- * 
- * 画图的一个类
- *
- */
-class buildGraph {
-    protected $graphwidth=800;
-    protected $graphheight=300;
-    protected $width_num=0;          // 宽分多少等分
-    protected $height_num=10;          // 高分多少等分,默认为10
-    protected $height_var=0;          // 高度增量(用户数据平均数)
-    protected $width_var=0;          // 宽度增量(用户数据平均数)
-    protected $height_max=0;          // 最大数据值
-    protected $array_data=array();      // 用户待分析的数据的二维数组
-    protected $array_error=array();      // 收集错误信息
-
-    protected $colorBg=array(255,255,255);  // 图形背景-白色
-    protected $colorGrey=array(192,192,192);  // 灰色画框
-    protected $colorBlue=array(0,0,255);     // 蓝色
-    protected $colorRed=array(255,0,0);    // 红色(点)
-    protected $colorDarkBlue=array(0, 0, 255);  // 深色
-    protected $colorBlack=array(0,0,0);
-    protected $colorLightBlue=array(200,200,255);     // 浅色
-
-    protected $array_color;          // 曲线着色(存储十六进制数)
-    protected $image;              // 我们的图像
-
-
-    /**
-     * 方法:接受用户数据
-     */
-    function addData($array_user_data){
-        if(!is_array($array_user_data) or empty($array_user_data)){
-            $this->array_error['addData']="没有可供分析的数据";
-            return false;
-        }
-        $i=count($this->array_data);
-        $this->array_data[$i]=$array_user_data;
-    }
-
-    /**
-     * 方法:定义画布宽和长
-     */
-    function setImg($img_width,$img_height){
-        $this->graphwidth=$img_width;
-        $this->graphheight=$img_height;
-    }
-
-    /**
-     * 设定Y轴的增量等分,默认为10份
-     */
-    function setHeightNum($var_y){
-        $this->height_num=$var_y;
-    }
-
-    /**
-     * 定义各图形各部分色彩
-     */
-    function getRgb($color){        // 得到十进制色彩
-        $R=($color>>16) &0xff;
-        $G=($color>>8) &0xff;
-        $B=($color) & 0xff;
-        return(array($R,$G,$B));
-    }
-    
-    /**
-     * 定义背景色
-     * @param unknown_type $c1
-     * @param unknown_type $c2
-     * @param unknown_type $c3
-     */
-    function setColorBg($c1,$c2,$c3){
-        $this->colorBg=array($c1,$c2,$c3);
-    }
-    
-    /**
-     * 定义画框色
-     */
-    function setColorGrey($c1,$c2,$c3){
-        $this->colorGrey=array($c1,$c2,$c3);
-    }
-    
-    /**
-     * 定义蓝色
-     * @param unknown_type $c1
-     * @param unknown_type $c2
-     * @param unknown_type $c3
-     */
-    function setColorBlue($c1,$c2,$c3){
-        $this->colorBlue=array($c1,$c2,$c3);
-    }
-    
-    /**
-     * 定义色Red
-     */
-    function setColorRed($c1,$c2,$c3){
-        $this->colorRed=array($c1,$c2,$c3);
-    }
-    
-    /**
-     * 定义深色
-     * @param unknown_type $c1
-     * @param unknown_type $c2
-     * @param unknown_type $c3
-     */
-    function setColorDarkBlue($c1,$c2,$c3){
-        $this->colorDarkBlue=array($c1,$c2,$c3);
-    }
-    
-    /**
-     * 定义浅色
-     * @param unknown_type $c1
-     * @param unknown_type $c2
-     * @param unknown_type $c3
-     */
-    function setColorLightBlue($c1,$c2,$c3){
-        $this->colorLightBlue=array($c1,$c2,$c3);
-    }
-    
-    /**
-     * 方法:由用户数据将画布分成若干等份宽
-     * 并计算出每份多少像素
-     */
-    function getWidthNum(){
-        $this->width_num=count($this->array_data[0]);
-    }
-    
-    /**
-     * 
-     * @return mixed
-     */
-    function getMaxHeight(){
-        // 获得用户数据的最大值
-        $tmpvar=array();
-        foreach($this->array_data as$tmp_value){
-            $tmpvar[]=max($tmp_value);
-        }
-        $this->height_max=max($tmpvar);
-        return max($tmpvar);
-    }
-    
-    /**
-     * 
-     * @return number
-     */
-    function getHeightLength(){
-        // 计算出每格的增量长度(用户数据,而不是图形的像素值)
-        $max_var=$this->getMaxHeight();
-        $max_var=ceil($max_var/$this->height_num);
-            $first_num=substr($max_var,0,1);
-            if(substr($max_var,1,1)){
-            if(substr($max_var,1,1)>=5)
-            $first_num+=1;
-        }
-        for($i=1;$i<strlen($max_var);$i++){
-        $first_num.="0";
-        }
-        return (int)$first_num;
-    }
-    
-    /**
-     * 
-     */
-    function getVarWh(){      // 得到高和宽的增量
-        $this->getWidthNum();
-        // 得到高度增量和宽度增量
-        $this->height_var=$this->getHeightLength();
-        $this->width_var=$this->graphwidth/$this->width_num;
-    }
-    
-    /**
-     * 
-     * @param unknown_type $str_colors
-     */
-    function setColors($str_colors){
-        // 用于多条曲线的不同着色,如$str_colors="ee00ff,dd0000,cccccc"
-        $this->array_color=explode(",",$str_colors);
-    }
-    
-    /**
-     * 
-     * @param unknown_type $var_num
-     */
-    function buildLine($var_num){
-        if(!empty($var_num)){            // 如果用户只选择显示一条曲线
-            $array_tmp[0]=$this->array_data[$var_num-1];
-            $this->array_data=$array_tmp;
-        }
-        
-        for($j=0;$j<count($this->array_data);$j++){
-            list($R,$G,$B)=$this->getRgb(hexdec($this->array_color[$j]));
-            $colorBlue=imagecolorallocate($this->image,$R,$G,$B);
-        
-            for($i=0;$i<$this->width_num-1;$i++){
-                $height_pix=$this->height_max == 0 ? 0 : round(($this->array_data[$j][$i]/$this->height_max)*$this->graphheight);
-                $height_next_pix= $this->height_max*$this->graphheight == 0 ? 0 : round($this->array_data[$j][$i+1]/$this->height_max*$this->graphheight);
-                imageline($this->image,$this->width_var*$i,$this->graphheight-$height_pix,$this->width_var*($i+1),$this->graphheight-$height_next_pix,$colorBlue);
-            }
-        }
-    }
-    
-    /**
-     * 
-     * @param unknown_type $select_gra
-     */
-    function buildRectangle($select_gra){
-        if(!empty($select_gra)){            // 用户选择显示一个矩形
-            $select_gra-=1;
-        }
-        // 画矩形
-        // 配色
-        $colorDarkBlue=imagecolorallocate($this->image,$this->colorDarkBlue[0], $this->colorDarkBlue[1],$this->colorDarkBlue[2]);
-        $colorLightBlue=imagecolorallocate($this->image,$this->colorLightBlue[0], $this->colorLightBlue[1],$this->colorLightBlue[2]);
-    
-        if(empty($select_gra))
-            $select_gra=0;
-        
-        for($i=0; $i<$this->width_num; $i++){
-            $height_pix = $this->height_max == 0 ? 0 : round(($this->array_data[$select_gra][$i]/$this->height_max)*$this->graphheight);
-            imagefilledrectangle($this->image,$this->width_var*$i,$this->graphheight-$height_pix,$this->width_var*($i+1),$this->graphheight,$colorDarkBlue);
-            imagefilledrectangle($this->image,($i*$this->width_var)+1,($this->graphheight-$height_pix)+1,$this->width_var*($i+1)-5,$this->graphheight-2,$colorLightBlue);
-        }
-    }
-    
-    /**
-     * 
-     */
-    function createCloths(){
-        // 创建画布
-        $this->image=imagecreate($this->graphwidth+20,$this->graphheight+20);
-    }
-    
-    /**
-     * 
-     */
-    function  createFrame(){
-        // 创建画框
-        $this->getVarWh();
-        // 配色
-        $colorBg=imagecolorallocate($this->image,$this->colorBg[0], $this->colorBg[1],$this->colorBg[2]);
-        $colorGrey=imagecolorallocate($this->image,$this->colorGrey[0], $this->colorGrey[1],$this->colorGrey[2]);
-        // 创建图像周围的框
-        imageline($this->image, 0, 0, 0,$this->graphheight,$colorGrey);
-        imageline($this->image, 0, 0,$this->graphwidth, 0,$colorGrey);
-        imageline($this->image,($this->graphwidth-1),0,($this->graphwidth-1),($this->graphheight-1),$colorGrey);
-        imageline($this->image,0,($this->graphheight-1),($this->graphwidth-1),($this->graphheight-1),$colorGrey);
-    }
-    
-    /**
-     * 
-     */
-    function  createLine(){
-        // 创建网格。
-        $this->getVarWh();
-        $colorBg=imagecolorallocate($this->image,$this->colorBg[0], $this->colorBg[1],$this->colorBg[2]);
-        $colorGrey=imagecolorallocate($this->image,$this->colorGrey[0], $this->colorGrey[1],$this->colorGrey[2]);
-        $colorRed=imagecolorallocate($this->image,$this->colorRed[0], $this->colorRed[1],$this->colorRed[2]);
-        $colorBlack=imagecolorallocate($this->image,$this->colorBlack[0], $this->colorBlack[1],$this->colorBlack[2]);
-        for($j=0;$j<$this->width_num;$j++){
-             if($j%12 == 0){
-                 // 画竖线
-                 imageline($this->image,$j*$this->width_var,0,$j*$this->width_var,$this->graphheight,$colorGrey);
-                 // 标出数字
-                 imagestring($this->image,2,$this->width_var*$j,$this->graphheight,$j/12,$colorBlack);
-           }
-         }
-        
-        for($i=1;$i<=$this->height_num;$i++){
-            // 画横线
-            imageline($this->image,0,$this->graphheight-($this->height_max*$this->graphheight == 0 ? 0 : ($this->height_var/$this->height_max*$this->graphheight)*$i),$this->graphwidth,$this->graphheight - ($this->height_max*$this->graphheight == 0 ? 0 : ($this->height_var/$this->height_max*$this->graphheight)*$i),$colorGrey);
-            // 标出数字
-            imagestring($this->image,2,0,$this->graphheight-($this->height_max*$this->graphheight == 0 ? 0 : ($this->height_var/$this->height_max*$this->graphheight)*$i),$this->height_var*$i,$colorBlack);
-        }
-    }
-    
-    /**
-     * 
-     * @param unknown_type $graph
-     * @param unknown_type $str_var
-     */
-    function build($graph,$str_var){
-        // $graph是用户指定的图形种类,$str_var是生成哪个数据的图
-        $this->createCloths();      // 先要有画布啊~~
-        switch ($graph){
-            case"line":
-                $this->createFrame();      // 画个框先:)
-                $this->createLine();      // 打上底格线
-                $this->buildLine($str_var);      // 画曲线
-                break;
-            case"rectangle":
-                $this->createFrame();            // 画个框先:)
-                $this->buildRectangle($str_var);      // 画矩形
-                $this->createLine();            // 打上底格线
-            break;
-        }
-    
-    
-        // 输出图形并清除内存
-        imagepng($this->image);
-        imagedestroy($this->image);
-    }
-    
-}
-    

+ 0 - 328
Workers/StatisticWorker.php

@@ -1,328 +0,0 @@
-<?php 
-require_once WORKERMAN_ROOT_DIR . 'Core/SocketWorker.php';
-/**
- * 
- * 接口成功率统计worker
- * 定时写入磁盘,用来统计请求量、延迟、波动等信息
-* @author walkor <worker-man@qq.com>
- */
-class StatisticWorker extends WORKERMAN\Core\SocketWorker
-{
-    /**
-     * 最大buffer长度
-     * @var ineger
-     */
-    const MAX_BUFFER_SIZE = 524288;
-    
-    /**
-     * 上次写日志数据到磁盘的时间
-     * @var integer
-     */
-    protected $logLastWriteTime = 0;
-    
-    /**
-     * 上次写统计数据到磁盘的时间
-     * @var integer
-     */
-    protected $stLastWriteTime = 0;
-    
-    /**
-     * 上次清理磁盘的时间
-     * @var integer
-     */
-    protected $lastClearTime = 0;
-    
-    /**
-     * 缓冲的日志数据
-     * @var string
-     */
-    protected $logBuffer = '';
-    
-    /**
-     * 缓冲的统计数据
-     * modid=>interface=>['code'=>[xx=>count,xx=>count],'suc_cost_time'=>xx,'fail_cost_time'=>xx, 'suc_count'=>xx, 'fail_count'=>xx, 'time'=>xxx]
-     * @var array
-     */
-    protected $statisticData = array();
-    
-    /**
-     * 多长时间写一次log数据
-     * @var integer
-     */
-    protected $logSendTimeLong = 20;
-    
-    /**
-     * 多长时间写一次统计数据
-     * @var integer
-     */
-    protected $stSendTimeLong = 300;
-    
-    /**
-     * 多长时间清除一次统计数据
-     * @var integer
-     */
-    protected $clearTimeLong = 86400;
-    
-    /**
-     * 日志过期时间 14days
-     * @var integer
-     */
-    protected $logExpTimeLong = 1296000;
-    
-    /**
-     * 统计结果过期时间 14days
-     * @var integer
-     */
-    protected $stExpTimeLong = 1296000;
-    
-    /**
-     * 固定包长
-     * @var integer
-     */
-    const PACKEGE_FIXED_LENGTH = 25;
-    
-    
-    
-    /**
-     * 默认只收1个包
-     * 上报包的格式如下
-     * struct{
-     *     int                                    code,                 // 返回码
-     *     unsigned int                           time,                 // 时间
-     *     float                                  cost_time,            // 消耗时间 单位秒 例如1.xxx
-     *     unsigned int                           source_ip,            // 来源ip
-     *     unsigned int                           target_ip,            // 目标ip
-     *     unsigned char                          success,              // 是否成功
-     *     unsigned char                          module_name_length,   // 模块名字长度
-     *     unsigned char                          interface_name_length,//接口名字长度
-     *     unsigned short                         msg_length,           // 日志信息长度
-     *     unsigned char[module_name_length]      module,               // 模块名字
-     *     unsigned char[interface_name_length]   interface,            // 接口名字
-     *     char[msg_length]                       msg                   // 日志内容
-     *  }
-     * @see Worker::dealInput()
-     */
-    public function dealInput($recv_str)
-    {
-        return 0;
-    }
-    
-    /**
-     * 处理上报的数据 log buffer满的时候写入磁盘
-     * @see Worker::dealProcess()
-     */
-    public function dealProcess($recv_str)
-    {
-        // 解包
-        $time_now = time();
-        $unpack_data = unpack("icode/Itime/fcost_time/Isource_ip/Itarget_ip/Csuccess/Cmodule_name_length/Cinterface_name_length/Smsg_length", $recv_str);
-        $module = substr($recv_str, self::PACKEGE_FIXED_LENGTH, $unpack_data['module_name_length']);
-        $interface = substr($recv_str, self::PACKEGE_FIXED_LENGTH + $unpack_data['module_name_length'], $unpack_data['interface_name_length']);
-        $msg = substr($recv_str, self::PACKEGE_FIXED_LENGTH + $unpack_data['module_name_length'] + $unpack_data['interface_name_length'], $unpack_data['msg_length']);
-        $msg = str_replace("\n", '<br>', $msg);
-        $code = $unpack_data['code'];
-        
-        // 统计调用量、延迟、成功率等信息
-        if(!isset($this->statisticData[$module]))
-        {
-            $this->statisticData[$module] = array();
-        }
-        if(!isset($this->statisticData[$module][$interface]))
-        {
-            $this->statisticData[$module][$interface] = array('code'=>array(), 'suc_cost_time'=>0, 'fail_cost_time'=>0, 'suc_count'=>0, 'fail_count'=>0, 'time'=>$this->stLastWriteTime);
-        }
-        if(!isset($this->statisticData[$module][$interface]['code'][$code]))
-        {
-            $this->statisticData[$module][$interface]['code'][$code] = 0;
-        }
-        $this->statisticData[$module][$interface]['code'][$code]++;
-        if($unpack_data['success'])
-        {
-            $this->statisticData[$module][$interface]['suc_cost_time'] += $unpack_data['cost_time'];
-            $this->statisticData[$module][$interface]['suc_count'] ++;
-        }
-        else
-        {
-            $this->statisticData[$module][$interface]['fail_cost_time'] += $unpack_data['cost_time'];
-            $this->statisticData[$module][$interface]['fail_count'] ++;
-        }
-        
-        // 如果不成功写入日志
-        if(!$unpack_data['success'])
-        {
-            $log_str = date('Y-m-d H:i:s',$unpack_data['time'])."\t{$module}::{$interface}\tcode:{$unpack_data['code']}\tmsg:{$msg}\tsource_ip:".long2ip($unpack_data['source_ip'])."\ttarget_ip:".long2ip($unpack_data['target_ip'])."\n";
-            // 如果buffer溢出,则写磁盘,并清空buffer
-            if(strlen($this->logBuffer) + strlen($recv_str) > self::MAX_BUFFER_SIZE)
-            {
-                // 写入log数据到磁盘
-                $this->wirteLogToDisk();
-                $this->logBuffer = $log_str;
-            }
-            else 
-            {
-                $this->logBuffer .= $log_str;
-            }
-        }
-        
-    }
-    
-    /**
-     * 将日志数据写入磁盘
-     * @return void
-     */
-    protected function wirteLogToDisk()
-    {
-        // 初始化下一波统计数据
-        $this->logLastWriteTime = time();
-        
-        // 有数据才写
-        if(empty($this->logBuffer))
-        {
-            return true;
-        }
-        
-        file_put_contents(WORKERMAN_LOG_DIR . 'statistic/log/'.date('Y-m-d', $this->logLastWriteTime), $this->logBuffer, FILE_APPEND | LOCK_EX);
-        
-        $this->logBuffer = '';
-    }
-    
-    /**
-     * 将统计数据写入磁盘
-     * @return void
-     */
-    protected function wirteStToDisk()
-    {
-        // 记录
-        $this->stLastWriteTime = $this->stLastWriteTime + $this->stSendTimeLong;
-        
-        // 有数据才写磁盘
-        if(empty($this->statisticData))
-        {
-            return true;
-        }
-        
-        $ip = $this->getRemoteIp();
-        
-        foreach($this->statisticData as $module=>$items)
-        {
-            if(!is_dir(WORKERMAN_LOG_DIR . 'statistic/st/'.$module))
-            {
-                umask(0);
-                mkdir(WORKERMAN_LOG_DIR . 'statistic/st/'.$module, 0777, true);
-            }
-            foreach($items as $interface=>$data)
-            {
-                // modid=>['code'=>[xx=>count,xx=>count],'suc_cost_time'=>xx,'fail_cost_time'=>xx, 'suc_count'=>xx, 'fail_count'=>xx, 'time'=>xxx]
-                file_put_contents(WORKERMAN_LOG_DIR . "statistic/st/{$module}/{$interface}|".date('Y-m-d',$data['time']-1), "$ip\t{$data['time']}\t{$data['suc_count']}\t{$data['suc_cost_time']}\t{$data['fail_count']}\t{$data['fail_cost_time']}\t".json_encode($data['code'])."\n", FILE_APPEND | LOCK_EX);
-            }
-        }
-        
-        $this->statisticData = array();
-    }
-    
-    /**
-     * 该worker进程开始服务的时候会触发一次,初始化$logLastWriteTime
-     * @return bool
-     */
-    protected function onStart()
-    {
-        // 创建LOG目录
-        if(!is_dir(WORKERMAN_LOG_DIR . 'statistic/log'))
-        {
-            umask(0);
-            @mkdir(WORKERMAN_LOG_DIR . 'statistic/log', 0777, true);
-        }
-        
-        $time_now = time();
-        $this->logLastWriteTime = $time_now;
-        $this->stLastWriteTime = $time_now - $time_now%$this->stSendTimeLong;
-        \WORKERMAN\Core\Lib\Task::init($this->event);
-        \WORKERMAN\Core\Lib\Task::add(1, array($this, 'onAlarm'));
-    }
-    
-    /**
-     * 该worker进程停止服务的时候会触发一次,保存数据到磁盘
-     * @return bool
-     */
-    protected function onStop()
-    {
-        // 发送数据到统计中心
-        $this->wirteLogToDisk();
-        $this->wirteStToDisk();
-        return false;
-    }
-    
-    /**
-     * 每隔一定时间触发一次 
-     * @see Worker::onAlarm()
-     */
-    public function onAlarm()
-    {
-        $time_now = time();
-        // 检查距离最后一次发送数据到统计中心的时间是否超过设定时间
-        if($time_now - $this->logLastWriteTime >= $this->logSendTimeLong)
-        {
-            // 发送数据到统计中心
-            $this->wirteLogToDisk();
-        }
-        // 检查是否到了该发送统计数据的时间
-        if($time_now - $this->stLastWriteTime >= $this->stSendTimeLong)
-        {
-            $this->wirteStToDisk();
-        }
-        
-        // 检查是否到了清理数据的时间
-        if($time_now - $this->lastClearTime >= $this->clearTimeLong)
-        {
-            $this->lastClearTime = $time_now;
-            $this->clearDisk(WORKERMAN_LOG_DIR . 'statistic/log/', $this->logExpTimeLong);
-            $this->clearDisk(WORKERMAN_LOG_DIR . 'statistic/st/', $this->stExpTimeLong);
-        }
-    }
-    
-    
-    /**
-     * 清除磁盘数据
-     * @param string $file
-     * @param int $exp_time
-     */
-    protected function clearDisk($file = null, $exp_time = 86400)
-    {
-        $time_now = time();
-        if(is_file($file)) 
-        {
-            $stat = stat($file);
-            if(!$stat)
-            {
-                $this->notice("stat $file fail");
-                return;
-            }
-            $mtime = $stat['mtime'];
-            if($time_now - $mtime > $exp_time)
-            {
-                unlink($file);
-            }
-            return;
-        }
-        foreach (glob($file."/*") as $file_name) {
-            if(is_dir($file_name))
-            {
-                $this->clearDisk($file_name, $exp_time);
-                continue;
-            }
-            $stat = stat($file_name);
-            if(!$stat)
-            {
-                $this->notice("stat $file fail");
-                return;
-            }
-            $mtime = $stat['mtime'];
-            if($time_now - $mtime > $exp_time)
-            {
-                unlink($file_name);
-            }
-        }
-        
-    }
-    
-}