/** * 连接到服务器 * @param SOA_Result $retObj * @return bool * @throws \Exception */ protected function connectToServer(SOA_Result $retObj) { $ret = false; //循环连接 while (count($this->servers) > 0) { $svr = $this->getServer(); if (!$this->useSwoole) { $socket = new TCP(); $socket->try_reconnect = false; $ret = $socket->connect($svr['host'], $svr['port'], $this->timeout); $socketFd = intval($socket->get_socket()); } else { $key = $svr['host'] . ':' . $svr['port'] . '-' . $retObj->index; $socket = new \swoole_client(SWOOLE_SOCK_TCP | SWOOLE_KEEP, SWOOLE_SOCK_SYNC, $key); $socket->set(array('open_length_check' => true, 'package_max_length' => $this->packet_maxlen, 'package_length_type' => 'N', 'package_body_offset' => SOAServer::HEADER_SIZE, 'package_length_offset' => 0)); $ret = $socket->connect($svr['host'], $svr['port'], $this->timeout); $socketFd = $socket->sock; } //连接被拒绝,证明服务器已经挂了 //TODO 如果连接失败,需要上报机器存活状态 if ($ret === false and $socket->errCode == 111) { $this->onConnectServerFailed($svr); unset($socket); } else { $retObj->socket = $socket; $retObj->server_host = $svr['host']; $retObj->server_port = $svr['port']; //使用SOCKET的编号作为ID $retObj->id = $socketFd; break; } } return $ret; }
/** * 发送请求 * @param $type * @param $send * @param SOA_result $retObj * @return bool */ protected function request($type, $send, $retObj) { $svr = $this->getServer(); $socket = new TCP(); $retObj->socket = $socket; $retObj->type = $type; $retObj->send = $send; $retObj->server_host = $svr['host']; $retObj->server_port = $svr['port']; $this->beforeRequest($retObj); //异步connect //TODO 如果连接失败,需要上报机器存活状态 $ret = $socket->connect($svr['host'], $svr['port'], $this->timeout); //使用SOCKET的编号作为ID $retObj->id = (int) $socket->get_socket(); if ($ret === false) { $retObj->code = SOA_Result::ERR_CONNECT; unset($retObj->socket); return false; } //请求串号 $retObj->requestId = self::getRequestId(); //发送失败了 if ($retObj->socket->send(SOAServer::encode($retObj->send, SOAServer::DECODE_PHP, 0, $retObj->requestId)) === false) { $retObj->code = SOA_Result::ERR_SEND; unset($retObj->socket); return false; } //加入wait_list if ($type != self::TYPE_ASYNC) { $this->wait_list[$retObj->id] = $retObj; } return true; }
/** * 发送请求 * @param $type * @param $send * @param SOA_result $retObj * @return bool */ protected function request($send, $retObj) { $retObj->send = $send; $this->beforeRequest($retObj); $ret = false; $socket = null; $svr = null; //循环连接 while (count($this->servers) > 0) { $svr = $this->getServer(); $socket = new TCP(); $socket->try_reconnect = false; $ret = $socket->connect($svr['host'], $svr['port'], $this->timeout); //连接被拒绝,证明服务器已经挂了 //TODO 如果连接失败,需要上报机器存活状态 if ($ret === false and $socket->errCode == 111) { $this->onConnectServerFailed($svr); } else { break; } } $retObj->socket = $socket; $retObj->server_host = $svr['host']; $retObj->server_port = $svr['port']; //使用SOCKET的编号作为ID $retObj->id = (int) $socket->get_socket(); if ($ret === false) { $retObj->code = SOA_Result::ERR_CONNECT; unset($retObj->socket); return false; } //请求串号 $retObj->requestId = self::getRequestId(); //发送失败了 if ($retObj->socket->send(SOAServer::encode($retObj->send, SOAServer::DECODE_PHP, 0, $retObj->requestId)) === false) { $retObj->code = SOA_Result::ERR_SEND; unset($retObj->socket); return false; } //加入wait_list $this->wait_list[$retObj->id] = $retObj; return true; }
/** * @param $payload * @param string $type * @param bool $masked * @return bool|string */ private function hybi10Encode($payload, $type = 'text', $masked = true) { $frameHead = array(); $payloadLength = strlen($payload); switch ($type) { //文本内容 case 'text': // first byte indicates FIN, Text-Frame (10000001): $frameHead[0] = 129; break; //二进制内容 //二进制内容 case 'binary': case 'bin': // first byte indicates FIN, Text-Frame (10000010): $frameHead[0] = 130; break; case 'close': // first byte indicates FIN, Close Frame(10001000): $frameHead[0] = 136; break; case 'ping': // first byte indicates FIN, Ping frame (10001001): $frameHead[0] = 137; break; case 'pong': // first byte indicates FIN, Pong frame (10001010): $frameHead[0] = 138; break; } // set mask and payload length (using 1, 3 or 9 bytes) if ($payloadLength > 65535) { $payloadLengthBin = str_split(sprintf('%064b', $payloadLength), 8); $frameHead[1] = $masked === true ? 255 : 127; for ($i = 0; $i < 8; $i++) { $frameHead[$i + 2] = bindec($payloadLengthBin[$i]); } // most significant bit MUST be 0 (close connection if frame too big) if ($frameHead[2] > 127) { $this->socket->close(); return false; } } elseif ($payloadLength > 125) { $payloadLengthBin = str_split(sprintf('%016b', $payloadLength), 8); $frameHead[1] = $masked === true ? 254 : 126; $frameHead[2] = bindec($payloadLengthBin[0]); $frameHead[3] = bindec($payloadLengthBin[1]); } else { $frameHead[1] = $masked === true ? $payloadLength + 128 : $payloadLength; } // convert frame-head to string: foreach (array_keys($frameHead) as $i) { $frameHead[$i] = chr($frameHead[$i]); } // generate a random mask: $mask = array(); if ($masked === true) { for ($i = 0; $i < 4; $i++) { $mask[$i] = chr(rand(0, 255)); } $frameHead = array_merge($frameHead, $mask); } $frame = implode('', $frameHead); // append payload to frame: for ($i = 0; $i < $payloadLength; $i++) { $frame .= $masked ? $payload[$i] ^ $mask[$i % 4] : $payload[$i]; } return $frame; }