parseFrame函数:
function parseFrame($data, $socketId) { //判断该帧是否是经过掩码处理 $isMasked = $this->isMasked($data[1]); //如果未经掩码处理,则根据协议规定,需要断开连接 if (!$isMasked) { //此处使用1002状态码,表示协议错误,发送关闭帧 $this->closeFrame($socketId, 1002, 'There is no mask!'); //断开连接 $this->disconnect($socketId); return false; } //获取负载的长度字节数 $payloadLen = $this->getPayloadLen(substr($data, 1, 9)); //根据负载长度获取负载的全部数据 $payload = $this->getPayload($data, $payloadLen); //获取掩码值 $mask = $this->getMask($data, $payloadLen); //获取帧的类型 $frameType = $this->getFrameType($data[0]); //处理帧 switch ($frameType) { case self::FRAME_CONTINUE: //后续帧,需要拼接buffer $this->socketListMap[$socketId]['buffer'] .= $this->parseRawFrame($payload, $mask); break; case self::FRAME_TEXT: //文本帧,处理方式默认保持一致,均使用parseRawFrame处理,如果由特殊需求可以重写parseTextFrame函数 $this->socketListMap[$socketId]['buffer'] = $this->parseTextFrame($payload, $mask); break; case self::FRAME_BIN: //二进制帧,处理方式默认保持一致,均使用parseRawFrame处理,如果由特殊需求可以重写parseBinaryFrame函数 $this->socketListMap[$socketId]['buffer'] = $this->parseBinaryFrame($payload, $mask); break; case self::FRAME_CLOSE: //发送关闭帧(应答帧) $this->closeFrame($socketId); break; case self::FRAME_PING: //发送pong帧响应,浏览器目前不提供ping、pong帧的API,此处逻辑基本不会走到,只为实现协议内容 $this->sendPong($socketId, $this->parseRawFrame($payload, $mask)); break; case self::FRAME_PONG: //收到pong帧不进行任何处理(正常情况下不会收到,浏览器不会主动发送pong帧) break; default: //其他帧类型无法处理,直接断开连接,根据协议,此处使用1003状态码关闭连接更好 $this->disconnect($socketId); break; } if ($this->debug) { //输出调试信息 echo "isFin:" . ((ord($data[0]) & 0x80) >> 7) . "\n"; echo "opCode:$frameType\n"; echo "payLoad Length:$payloadLen\n"; echo "Mask:$mask\n\n"; } //如果是结束的数据帧,返回true,否则均为false //当返回true时,外层调用函数会继续将执行核心业务逻辑,读取缓冲区中的数据进行处理 //如果是false,则不进行进一步的处理(控制帧及非结束帧都不会提交到业务层处理) return $this->isFin($data[0]) && !$this->isControlFrame($frameType); }