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);
}