当我在我的 iOS 应用程序中接收数据时(收到了一些数据,但不是全部)我故意退出应用程序并socket_write挂在服务器上。这是相关的代码:
error_log("start write");
$sent = socket_write($client, $string, $length);
error_log("end write");
Run Code Online (Sandbox Code Playgroud)
我"start write"在错误日志中收到消息,但就是这样,它会继续挂起,直到我重新启动 php 程序。
我尝试设置超时,但随后我尝试上传一个大文件,但在上传完成之前它似乎已超时。我认为超时是一段时间的不活动,而不是客户端连接的总时间。无论如何,任何帮助表示赞赏。我假设socket_write如果套接字断开连接会返回,但要么我错了,要么代码错了。谢谢你的帮助。
编辑
基本上,我需要知道客户端何时断开连接。看起来 fwrite、socket_send 和 socket_write 在客户端断开中间写入和阻塞模式时都挂起。如果我关闭阻塞模式,我的代码如下所示:
function send_data($client, $string)
{
$length = strlen($string);
socket_set_nonblock($client);
while(true)
{
$sent = socket_write($client, $string, $length);
//OR - $sent = socket_send($client, $string, $length, 0);
if($sent === FALSE)
{
error_log("false");
return;
}
if($sent < $length)
{
$string = substr($string, $sent);
$length -= $sent;
}
else
return;
}
}
Run Code Online (Sandbox Code Playgroud)
这样做的问题是,$sent === FALSE当客户端断开连接时,而且当它们暂时不可用时,这被证明是在发送前几个字节后发生的,因此不会发送整个字符串。
您应该使用socket_select()来确定套接字是否准备好写入;通过这种方式,您只需要在对方准备好接收时写一些东西。
您仍然需要检查传输了多少字节并相应地减少消息。
例如:
function send_data($client, $string)
{
socket_set_nonblock($client);
while ($string != '') {
$write = [$client]; $read = $except = null;
// set timeout to 1s
$n = socket_select($read, $write, $except, 1);
if ($n === false) {
return;
} elseif ($n > 0) {
$length = strlen($string);
$sent = socket_write($client, $string, $length);
if ($sent === false || $sent == $length) {
return;
} else /* $sent < $length */ {
$string = substr($string, $sent);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)