这个问题的解决方法如下
问题:当使用 websocket 接收长字节的数据时,像socket_recv($socket,$buffer,5000,0); 这样的单次调用可能无法获得完整的数据,您需要再次调用socket_recv($socket,$buffer,5000,0);。
例如,假设我们使用 JS (socket.send) 从浏览器向 websocket 发送了 8000 字节的数据。在服务器端,我们将使用 socket_recv 来获取消息。但是我们可能首先只接收到大约 4000 字节的数据,可能需要再次调用 socket_recv 来获取剩余的 4000 字节。
现在在我的原始代码中,我曾经在调用 socket_recv 后立即调用函数“unmask”来取消屏蔽数据。这适用于收到的第一组消息。但是对于下一组消息,“unmask”函数将尝试提取新的 Mask 并应用它。这是错误,因为该消息是先前消息的延续,并且 Mask 不会更改。解决方案是保留第一条消息的掩码并检查下一条消息是否继续。这可以通过检查消息的第一位来完成。
$fin=ord($payload[0]) & 0x77;
如果 $fin 为 1,则消息为新消息,否则为先前消息的延续。在 ($fin!=1) 的情况下,您需要使用上一条消息的掩码来取消屏蔽消息。不要忘记,由于您需要再次使用 mask 的值,您需要在函数外部定义它并使其成为全局。
我在下面提供了新旧代码供您参考。我希望这是正确的解决方案,但请随时添加任何内容,或者让我知道我是否在任何地方出错。
我原来的 Unmask 函数:
function unmask($payload) {
$length = ord($payload[1]) & 127;
if($length == 126) {
$masks = substr($payload, 4, 4);
$data = substr($payload, 8);
$firstcode=substr($payload, 1, 1);
}
elseif($length == 127) {
$masks = substr($payload, 10, 4);
$data = substr($payload, 14);
$firstcode=substr($payload, 1, 1);
}
else {
$masks = substr($payload, 2, 4);
$data = substr($payload, 6);
$firstcode=substr($payload, 1, 1);
}
$text = '';
for ($i = 0; $i < strlen($data); ++$i) {
$text .= $data[$i] ^ $masks[$i%4];
}
return $text;
}
更新功能:
function unmask($payload,$masks) {
global $masks;
$fin=ord($payload[0]) & 0x77;
if($fin!=1){
$data=substr($payload,0);
$text='';
for ($i = 0; $i < strlen($data); ++$i) {
$text .= $data[$i] ^ $masks[$i%4];
}
return $text;
}else{
$length = ord($payload[1]) & 127;
Echo "Mask functiion Payload Lenght".$length."\n";
if($length == 126) {
$masks = substr($payload, 4, 4);
$data = substr($payload, 8);
}
elseif($length == 127) {
$masks = substr($payload, 10, 4);
$data = substr($payload, 14);
}
else {
$masks = substr($payload, 2, 4);
$data = substr($payload, 6);
}
$text = '';
for ($i = 0; $i < strlen($data); ++$i) {
$text .= $data[$i] ^ $masks[$i%4];
}
return $text;
}
}