/** * 想某个用户网关发送命令和消息 * @param int $client_id * @param int $cmd * @param string $message * @return boolean */ protected static function sendCmdAndMessageToClient($client_id, $cmd, $message, $ext_data = '') { // 如果是发给当前用户则直接获取上下文中的地址 if ($client_id === Context::$client_id || $client_id === null) { $address = long2ip(Context::$local_ip) . ':' . Context::$local_port; $connection_id = Context::$connection_id; } else { $address_data = Context::clientIdToAddress($client_id); $address = long2ip($address_data['local_ip']) . ":{$address_data['local_port']}"; $connection_id = $address_data['connection_id']; } $gateway_data = GatewayProtocol::$empty; $gateway_data['cmd'] = $cmd; $gateway_data['connection_id'] = $connection_id; $gateway_data['body'] = $message; if (!empty($ext_data)) { $gateway_data['ext_data'] = $ext_data; } return self::sendToGateway($address, $gateway_data); }
/** * 当gateway转发来数据时 * @param TcpConnection $connection * @param mixed $data */ public function onGatewayMessage($connection, $data) { $cmd = $data['cmd']; if ($cmd === GatewayProtocol::CMD_PING) { return; } // 上下文数据 Context::$client_ip = $data['client_ip']; Context::$client_port = $data['client_port']; Context::$local_ip = $data['local_ip']; Context::$local_port = $data['local_port']; Context::$connection_id = $data['connection_id']; Context::$client_id = Context::addressToClientId($data['local_ip'], $data['local_port'], $data['connection_id']); // $_SERVER变量 $_SERVER = array('REMOTE_ADDR' => long2ip($data['client_ip']), 'REMOTE_PORT' => $data['client_port'], 'GATEWAY_ADDR' => long2ip($data['local_ip']), 'GATEWAY_PORT' => $data['gateway_port'], 'GATEWAY_CLIENT_ID' => Context::$client_id); // 尝试解析session if ($data['ext_data'] != '') { $_SESSION = Context::sessionDecode($data['ext_data']); } else { $_SESSION = null; } // 备份一次$data['ext_data'],请求处理完毕后判断session是否和备份相等,不相等就更新session $session_str_copy = $data['ext_data']; if ($this->processTimeout) { pcntl_alarm($this->processTimeout); } // 尝试执行Event::onConnection、Event::onMessage、Event::onClose switch ($cmd) { case GatewayProtocol::CMD_ON_CONNECTION: if ($this->_eventOnConnect) { call_user_func($this->_eventOnConnect, Context::$client_id); } break; case GatewayProtocol::CMD_ON_MESSAGE: if ($this->_eventOnMessage) { call_user_func($this->_eventOnMessage, Context::$client_id, $data['body']); } break; case GatewayProtocol::CMD_ON_CLOSE: if ($this->_eventOnClose) { call_user_func($this->_eventOnClose, Context::$client_id); } break; } if ($this->processTimeout) { pcntl_alarm(0); } // 判断session是否被更改 $session_str_now = $_SESSION !== null ? Context::sessionEncode($_SESSION) : ''; if ($session_str_copy != $session_str_now) { \Utils\GatewayWorker\Lib\Gateway::updateSocketSession(Context::$client_id, $session_str_now); } Context::clear(); }