/** * Data decoding, according to related IETF draft * * @see http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-10#page-16 */ protected function _dataDecode() { //参考 http://blog.csdn.net/fenglibing/article/details/6852497 //这里仅仅处理最基本的 $encodedData =& $this->webSocketSession->buf; // 至少有2个字节的头 while (($buflen = strlen($encodedData)) >= 2) { $len = 0; $isMasked = (bool) (ord($encodedData[1]) >> 7); $opcode = ord($encodedData[0]) & 15; $dataLength = ord($encodedData[1]) & 127; $len += 2; if ($dataLength === 126) { $extDataLength = hexdec(sprintf('%02x%02x', ord($encodedData[2]), ord($encodedData[3]))); $len += 2; } else { if ($dataLength === 127) { $extDataLength = hexdec(sprintf('%02x%02x%02x%02x%02x%02x%02x%02x', ord($encodedData[2]), ord($encodedData[3]), ord($encodedData[4]), ord($encodedData[5]), ord($encodedData[6]), ord($encodedData[7]), ord($encodedData[8]), ord($encodedData[9]))); $len += 8; } else { $extDataLength = $dataLength; } } if (webSocketSession::maxPacketSize <= $extDataLength) { // Too big packet $this->webSocketSession->close(); return; } if ($isMasked) { $maskingKey = Utils::binarySubstr($encodedData, $len, 4); $len += 4; } if ($extDataLength + $len > strlen($encodedData)) { //没有出现包 // not enough data yet return; } $data = Utils::binarySubstr($encodedData, $len, $extDataLength); //这里用的引用,所以会处理掉 socketSession->buf $encodedData = Utils::binarySubstr($encodedData, $len + $extDataLength); if ($opcode === self::CLOSE) { //客户端主动关闭连接 $this->webSocketSession->close(); return; } if ($opcode === self::PING) { $this->sendFrame('', 'PONG'); continue; } if ($opcode === self::PONG) { //todo: 收到 pong 包,不做任何事情,以后应该更新最后的连接时间 daemon::log(get_class($this) . '::' . __METHOD__ . ' : receive PONG packet. ' . $this->webSocketSession->addr); continue; } if ($isMasked) { $unmaskingFunc = function ($data, $mask) { for ($i = 0, $l = strlen($data); $i < $l; $i++) { // Avoid storing a new copy of $data... $data[$i] = $data[$i] ^ $mask[$i % 4]; } return $data; }; $this->webSocketSession->onFrame($unmaskingFunc($data, $maskingKey), $opcode); } else { $this->webSocketSession->onFrame($data, $opcode); } } }