我从浏览器通过Websocket发送大约5000字节的图像数据,但这行仅接收1394字节:
while ($bytes = socket_recv($socket, $r_data, 4000, MSG_DONTWAIT)) {
$data .= $r_data;
}
这是在握手完成后正确接收的。 json数据在1394字节后被截止。 可能是什么原因?
在浏览器界面中,它以JSON:
的形式发送图像websocket.send(JSON.stringify(request));
浏览器界面很好,因为它正在使用我测试的其他PHP websocket免费程序。
以下是完整的source code。
答案 0 :(得分:7)
1394大约是MTU的常用大小,特别是如果你通过VPN隧道(是吗?)。
您不能期望读取一个呼叫中的所有字节,这些数据包可能会根据网络MTU进行分段。
答案 1 :(得分:7)
您通过指定MSG_DONTWAIT将我们的套接字设置为非阻塞,因此它会在读取第一个数据块后返回EAGAIN,而不是等待更多数据。删除MSG_DONTWAIT标志并改为使用MSG_WAITALL,以便等待接收所有数据。
有几种方法可以知道您是否收到了所期望的所有数据:
1和2非常有用 - 例如,如果您正在编写游戏,聊天应用程序或其他套接字保持打开且来回传递多条消息的内容。 #3是最简单的,当您只想一次性接收所有数据时非常有用,例如文件下载。
答案 2 :(得分:7)
这就是我的2美分。 socket_recv可以在错误时返回false。它也可以在非阻塞IO中接收零(0)字节。
你的循环检查应该是:
while(($bytes = socket_recv($resource, $r_data, 4000, MSG_DONTWAIT)) !== false) {}
Altough我也会检查套接字是否有错误并添加一些usleep调用以防止“CPU烧坏”。
$data = '';
$done = false;
while(!$done) {
socket_clear_error($resource);
$bytes = @socket_recv($resource, $r_data, 4000, MSG_DONTWAIT);
$lastError = socket_last_error($resource);
if ($lastError != 11 && $lastError > 0) {
// something went wrong! do something
$done = true;
}
else if ($bytes === false) {
// something went wrong also! do something else
$done = true;
}
else if (intval($bytes) > 0) {
$data .= $r_data;
}
else {
usleep(2000); // prevent "CPU burn"
}
}
答案 3 :(得分:0)
我想知道您的websockets连接是否存在问题。您在上面引用的while循环看起来驻留在客户端握手失败的代码的一部分中,它位于else
if($client->getHandshake()) { ... } else { ... }
中。
据我所知,$ client是一个单独的类,所以我无法看到该类的样子或Client :: getHandshake()的作用,但我猜测它是包含websocket升级握手成功或失败的布尔值的getter。
如果我纠正了握手失败并且客户端关闭了连接。从代码中我可以看到您使用的服务器代码需要规范的第13版。您没有提到您正在使用的客户端库,但其他服务器将接受除此服务器之外的其他版本。
请确保您的客户端库支持最新版本。
当收到传入连接并且传输失败时,从服务器发布详细输出将有帮助,如果我提出的建议是错误的。
答案 4 :(得分:0)
但是,不是你粘贴的代码部分包含在else块中吗?对我来说,看起来像握手的其他区块没有通过?
您可以将收到的字节打印为字符串吗?
答案 5 :(得分:0)
我不认为你的问题是正确的。根据源代码,如果握手成功,则执行此部分代码:
$data = '';
while (true) {
$ret = socket_recv($socket, $r_data, 4000, MSG_DONTWAIT);
if ($ret === false) {
$this->console("$myidentity socket_recv error");
exit(0);
}
$data .= $r_data;
if (strlen($data) > 4000) {
print "breaking as data len is more than 4000\n";
break;
} else {
print "curr datalen=" . strlen($data) . "\n";
}
}
如果程序真的进入了你提供的代码部分,那么值得研究握手失败的原因。
Server Class有第三个参数verboseMode
,当设置为true时,它将为您提供有关确切情况的详细调试日志。
我们将在没有调试日志的情况下进行推测,但如果提供了调试日志,我们可以提出更好的建议。