/** * 数据接收完整后处理业务逻辑 * @see Man\Core.SocketWorker::dealProcess() */ public function dealProcess($recv_str) { /** * data的数据格式为 * ['class'=>xx, 'method'=>xx, 'param_array'=>array(xx)] * @var array */ $data = JsonProtocol::decode($recv_str); // 判断数据是否正确 if (empty($data['class']) || empty($data['method']) || !isset($data['param_array'])) { // 发送数据给客户端,请求包错误 return $this->sendToClient(JsonProtocol::encode(array('code' => 400, 'msg' => 'bad request', 'data' => null))); } // 获得要调用的类、方法、及参数 $class = $data['class']; $method = $data['method']; $param_array = $data['param_array']; StatisticClient::tick($class, $method); $success = false; // 判断类对应文件是否载入 if (!class_exists($class)) { $include_file = ROOT_DIR . "/Services/{$class}.php"; if (is_file($include_file)) { require_once $include_file; } if (!class_exists($class)) { $code = 404; $msg = "class {$class} not found"; StatisticClient::report($class, $method, $success, $code, $msg, $this->statisticAddress); // 发送数据给客户端 类不存在 return $this->sendToClient(JsonProtocol::encode(array('code' => $code, 'msg' => $msg, 'data' => null))); } } // 调用类的方法 try { $ret = call_user_func_array(array($class, $method), $param_array); StatisticClient::report($class, $method, 1, 0, '', $this->statisticAddress); // 发送数据给客户端,调用成功,data下标对应的元素即为调用结果 return $this->sendToClient(JsonProtocol::encode(array('code' => 0, 'msg' => 'ok', 'data' => $ret))); } catch (Exception $e) { // 发送数据给客户端,发生异常,调用失败 $code = $e->getCode() ? $e->getCode() : 500; StatisticClient::report($class, $method, $success, $code, $e, $this->statisticAddress); return $this->sendToClient(JsonProtocol::encode(array('code' => $code, 'msg' => $e->getMessage(), 'data' => $e))); } }
$interface_name_length = strlen($interface); $avalible_size = self::MAX_UDP_PACKGE_SIZE - self::PACKAGE_FIXED_LENGTH - $module_name_length - $interface_name_length; if (strlen($msg) > $avalible_size) { $msg = substr($msg, 0, $avalible_size); } // 打包 return pack('CCfCNnN', $module_name_length, $interface_name_length, $cost_time, $success ? 1 : 0, $code, strlen($msg), time()) . $module . $interface . $msg; } /** * 解包 * @param string $bin_data * @return array */ public static function decode($bin_data) { // 解包 $data = unpack("Cmodule_name_len/Cinterface_name_len/fcost_time/Csuccess/Ncode/nmsg_len/Ntime", $bin_data); $module = substr($bin_data, self::PACKAGE_FIXED_LENGTH, $data['module_name_len']); $interface = substr($bin_data, self::PACKAGE_FIXED_LENGTH + $data['module_name_len'], $data['interface_name_len']); $msg = substr($bin_data, self::PACKAGE_FIXED_LENGTH + $data['module_name_len'] + $data['interface_name_len']); return array('module' => $module, 'interface' => $interface, 'cost_time' => $data['cost_time'], 'success' => $data['success'], 'time' => $data['time'], 'code' => $data['code'], 'msg' => $msg); } } if (PHP_SAPI == 'cli' && isset($argv[0]) && $argv[0] == basename(__FILE__)) { StatisticClient::tick("TestModule", 'TestInterface'); usleep(rand(10000, 600000)); $success = rand(0, 1); $code = rand(300, 400); $msg = '这个是测试消息'; var_export(StatisticClient::report('TestModule', 'TestInterface', $success, $code, $msg)); }
/** * 每当到达设定的时间时触发 */ public function onTime() { $time_now = microtime(true); if (($time_now - $this->lastCallOnTime) * 1000 >= $this->timeIntervalMS) { $this->lastCallOnTime = $time_now; if (function_exists('on_time')) { StatisticClient::tick($this->serviceName, 'on_time'); try { call_user_func('on_time'); StatisticClient::report($this->serviceName, 'on_time'); } catch (Exception $e) { StatisticClient::report($this->serviceName, 'on_time', $e->getMessage(), $e, false, $this->getLocalIp()); } } } $time_diff = $this->lastCallOnTime * 1000 + $this->timeIntervalMS - microtime(true) * 1000; if ($time_diff <= 0) { call_user_func(array($this, 'onTime')); } else { $this->event->setReadTimeOut($time_diff); } }
return $res; } public static function getErrCode() { $errcode = 10001; return $errcode; } public static function getErrMsg() { $errmsg = '添加用户失败'; return $errmsg; } } include 'StatisticClient.php'; // 统计开始 StatisticClient::tick("User", 'addInfo'); // 统计的产生,接口调用是否成功、错误码、错误日志 $success = true; $code = 0; $msg = ''; // 假如有个User::getInfo方法要监控 $user_info = User::addInfo(); if (!$user_info) { // 标记失败 $success = false; // 获取错误码,假如getErrCode()获得 $code = User::getErrCode(); // 获取错误日志,假如getErrMsg()获得 $msg = User::getErrMsg(); } // 上报结果
$port = 2207; $pid_array = array(); $time_start = microtime(true); $suc_cnt = 0; $fail_cnt = 0; $j = $proc_cnt; while ($j-- != 0) { $pid = pcntl_fork(); if ($pid > 0) { $pid_array[$pid] = $pid; } else { $i = $req_cnt; // while($i-- > 0) while (1) { // === tick 用于记录接口调用起始时间,精确到毫秒=== StatisticClient::tick(); usleep(rand(1000, 2000000)); $module_map = array('User' => 'User', 'Order' => 'Order', 'Card' => 'Card'); $interface_map = array('getUserByUid' => 'getUserByUid', 'getOrderInfo' => 'getOrderInfo', 'getInfo' => 'getInfo', 'getLists' => 'getLists', 'update' => 'update', 'delete' => 'delete'); $module = array_rand($module_map); $interface = array_rand($interface_map); $msg_array = array('参数错误', '数据库链接超时', '数据库无法链接,请稍后重试', '用户不存在', '网络繁忙,请稍后再试'); $msg = $msg_array[array_rand($msg_array)]; $code = rand(11011, 11100); $suc = rand(1, 9999) < 9997 ? true : false; // === 上报结果 === $ret = StatisticClient::report($module, $interface, $code, $msg, $suc); } print_result(); exit(""); }
<?php require '/usr/local/nginx/html/workerman-statistics/Applications/Statistics/Clients/StatisticClient.php'; // 统计开始 StatisticClient::tick("User", 'getInfo'); // 统计的产生,接口调用是否成功、错误码、错误日志 $success = true; $code = 0; $msg = ''; // 假如有个User::getInfo方法要监控 $user_info = User::getInfo(); if (!$user_info) { // 标记失败 $success = false; // 获取错误码,假如getErrCode()获得 $code = User::getErrCode(); // 获取错误日志,假如getErrMsg()获得 $msg = User::getErrMsg(); } // 上报结果 StatisticClient::report('User', 'getInfo', $success, $code, $msg);
/** * 有消息时 * @param int $client_id * @param string $message */ public static function onMessage($client_id, $data) { $class_dir = __DIR__ . "/Services"; //要读取的类文件路径 $host_type = "internet"; //客户端类型 echo $_SERVER['REMOTE_ADDR'] . "\n"; if ($_SERVER['REMOTE_ADDR'] == "127.0.0.1") { echo "内网登陆"; $class_dir = __DIR__ . "/SysServices"; $host_type = "localhost"; //客户端类型 } echo $_SESSION['UID'] . "\n"; $statistic_address = 'udp://127.0.0.1:55656'; // 判断数据是否正确 if (empty($data['class']) || empty($data['method']) || !isset($data['param_array'])) { // 发送数据给客户端,请求包错误 if ($host_type == "internet" && empty($_SESSION['UID'])) { $ret = Gateway::sendToCurrentClient(array('stat' => 100, 'text' => 'no login', 'data' => null)); Gateway::closeCurrentClient(); } else { $ret = Gateway::sendToCurrentClient(array('stat' => 400, 'text' => 'bad request', 'data' => null)); } return $ret; } // 获得要调用的类、方法、及参数 $class = $data['class']; $method = $data['method']; $param_array = $data['param_array']; //所有的调用一定要在登录后才可以 if (!empty($_SESSION['UID']) || $class == "Device" && $method == "Login" || $host_type == "localhost") { StatisticClient::tick($class, $method); $success = false; // 判断类对应文件是否载入 if (!class_exists($class)) { $include_file = $class_dir . "/{$class}.php"; if (is_file($include_file)) { require_once $include_file; } if (!class_exists($class)) { $code = 404; $msg = "class {$class} not found"; StatisticClient::report($class, $method, $success, $code, $msg, $statistic_address); // 发送数据给客户端 类不存在 //var_dump($connection); return Gateway::sendToCurrentClient(array('stat' => $code, 'text' => $msg, 'data' => null)); } } // 调用类的方法 try { $ret = call_user_func_array(array($class, $method), array($client_id, $param_array)); StatisticClient::report($class, $method, 1, 0, '', $statistic_address); // 发送数据给客户端,调用成功,data下标对应的元素即为调用结果 return Gateway::sendToCurrentClient(array('stat' => 0, 'text' => 'ok', 'data' => $ret)); } catch (Exception $e) { // 发送数据给客户端,发生异常,调用失败 $code = $e->getCode() ? $e->getCode() : 500; StatisticClient::report($class, $method, $success, $code, $e, $statistic_address); return Gateway::sendToCurrentClient(array('stat' => $code, 'text' => $e->getMessage(), 'data' => $e)); } } else { $ret = Gateway::sendToCurrentClient(array('stat' => 400, 'text' => 'no login', 'data' => null)); Gateway::closeCurrentClient(); return $ret; } }
public static function tick() { self::$timeStart = StatisticClient::tick(); }
public function callInterfaceCommon($apiurl, $type, $auth, $params, $token) { // 判断参数$params 是否为标准json try { $info = explode('/', ltrim($apiurl, '/')); $method_workman = current($info); $this->validate($token, current($info)); // 验证权限 $apiurl = $_SERVER['SERVER_NAME'] . '/api/restful/' . $apiurl; json_decode($params, true); if (json_last_error() !== JSON_ERROR_NONE) { throw new Exception('params非法的json格式', 555); } $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $apiurl); // 发贴地址 curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-type: application/json;charset="UTF-8"')); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); switch (strtoupper($type)) { case "GET": curl_setopt($ch, CURLOPT_HTTPGET, true); break; case "POST": curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST"); curl_setopt($ch, CURLOPT_POSTFIELDS, $params); break; case "PUT": curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT"); curl_setopt($ch, CURLOPT_POSTFIELDS, $params); break; case "DELETE": curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "DELETE"); curl_setopt($ch, CURLOPT_POSTFIELDS, $params); break; } curl_setopt($ch, CURLOPT_USERPWD, $auth->username . ':' . $auth->password); $result = curl_exec($ch); // 获得返回值 // file_put_contents("./up.log", 'data:' . var_export($result, true) . PHP_EOL, FILE_APPEND); json_decode($result, true); if (json_last_error() != JSON_ERROR_NONE) { $httpcode = 500; } else { $httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE); $contenttype = curl_getinfo($ch, CURLINFO_CONTENT_TYPE); echo $res = json_encode(['code' => $httpcode, 'data' => json_decode($result, TRUE)]); } // 判断服务器是win还是linux if (PATH_SEPARATOR == ':') { require '/usr/local/nginx/html/workerman-statistics/Applications/Statistics/Clients/StatisticClient.php'; // 统计开始 StatisticClient::tick("Restful", $method_workman); // 统计的产生,接口调用是否成功、错误码、错误日志 $success = true; $code = 0; $msg = ''; // 假如有个User::getInfo方法要监控 if (!in_array($httpcode, ['200', '201', '400', '404', '409'])) { // 标记失败 $success = false; // 获取错误码,假如getErrCode()获得 $code = $httpcode; // 获取错误日志,假如getErrMsg()获得 $msg = 'apiurl:' . $apiurl . PHP_EOL . 'requset_type:' . $type . PHP_EOL . 'params:' . $params . PHP_EOL . 'code:' . $code . PHP_EOL . 'data:' . var_export($result, true); } // 上报结果 StatisticClient::report('Restful', $method_workman, $success, $code, $msg); } // file_put_contents("./up.log", 'json:' . $res . PHP_EOL . "<hr/>" . PHP_EOL, FILE_APPEND); curl_close($ch); } catch (Exception $e) { echo json_encode(['code' => $e->getCode(), 'message' => $e->getMessage()]); } }
public static function startTick($module, $interface) { // 统计开始 StatisticClient::tick($module, $interface); }
// 启动多少服务进程 $worker->count = 16; // worker名称,php start.php status 时展示使用 $worker->name = 'JsonRpc'; $worker->onMessage = function ($connection, $data) { $statistic_address = 'udp://127.0.0.1:55656'; // 判断数据是否正确 if (empty($data['class']) || empty($data['method']) || !isset($data['param_array'])) { // 发送数据给客户端,请求包错误 return $connection->send(array('code' => 400, 'msg' => 'bad request', 'data' => null)); } // 获得要调用的类、方法、及参数 $class = $data['class']; $method = $data['method']; $param_array = $data['param_array']; StatisticClient::tick($class, $method); $success = false; // 判断类对应文件是否载入 if (!class_exists($class)) { $include_file = __DIR__ . "/Services/{$class}.php"; if (is_file($include_file)) { require_once $include_file; } if (!class_exists($class)) { $code = 404; $msg = "class {$class} not found"; StatisticClient::report($class, $method, $success, $code, $msg, $statistic_address); // 发送数据给客户端 类不存在 return $connection->send(array('code' => $code, 'msg' => $msg, 'data' => null)); } }