我有一个javascript websocket客户端和一个php websocket服务器。当我用循环向服务器发送大量数据时,服务器窗口中出现了奇怪的字符。
我发送:
setInterval(function() {
for (var i=1; i<=5; i++) {
WS.send("0");
}
}, 1000);
服务器窗口:
Received [1]: 0╩┤&ψ╙]▬)╩Zόrcj
Received [1]: 0
Received [1]: 0≤↓ [☺ψ╧
Received [1]: 0¶╞0UoL
§╧q←%ved [1]: 0Τ
Received [1]: 0b:Ρ"6Τι
Received [1]: 0
Received [1]: 0
Received [1]: 0&Ρ┼→↑αΫ
Received [1]: 0
Received [1]: 0
Received [1]: 0
Received [1]: 0╦►╬┘Τ7■
Received [1]: 0SΖ╥m╬'έ
Received [1]: 0
Received [1]: 0,!☼┘L╡?
Received [1]: 0L│%☼ΪH§
Received [1]: 0
Received [1]: 0▀μpp┤A@
Received [1]: 0V[A√╚ύq
当我以较低的频率发送数据时,一切正常
我发送:
setInterval(function() {
WS.send("0");
}, 1000);
和服务器窗口:
Received [1]: 0
Received [1]: 0
Received [1]: 0
Received [1]: 0
Received [1]: 0
Received [1]: 0
Received [1]: 0
Received [1]: 0
Received [1]: 0
为什么会发生这种情况?这正常吗?
用于解除数据掩码的函数:
function unmask($data) {
$length = ord($data[1]) & 127;
if($length == 126) {$masks = substr($data, 4, 4); $data = substr($data, 8);}
elseif($length == 127) {$masks = substr($data, 10, 4); $data = substr($data, 14);}
else {$masks = substr($data, 2, 4); $data = substr($data, 6);}
$text = "";
for ($i = 0; $i < strlen($data); ++$i) {$text .= $data[$i] ^ $masks[$i%4];}
return $text;
}
在这里我收到了消息:
while(socket_recv($client, $buffer, 2048, 0) >= 1) {
$msg = unmask($buffer);
echo "$msgn";
}
由于Nagle算法,您在数据包中获得多个WebSocket帧。您发送小消息的速度如此之快,以至于为了最大限度地减少网络拥塞,客户端一直保留数据,直到它得到服务器的确认,或者直到发生合理的超时。
要解决这个问题,您只需要去掉$length
字节数,然后在剩余的数据上运行unmask()
函数。
你的代码也容易受到超大WebSocket帧在不同数据包中被分割的影响;尝试在消息中发送超过64KB的数据,看看会发生什么。(你可以往下看,看到类似的结果;以太网的MTU是1500字节,但TCP本身的MTU是65536字节,所以当你发送超过64K的数据时,你总是会看到碎片的影响。
在我的服务器中,我为每个连接的用户设置了一个缓冲区,直到我有一个完整的WebSocket帧来处理碎片,并且我一次只从缓冲区的前面取出$header_length + $message_length
值的数据,以防缓冲区中有多个帧。