当我在我的 iOS 应用程序中接收数据时(收到了一些数据,但不是全部)我故意退出该应用程序并且 socket_write
卡在服务器上。相关代码如下:
error_log("start write");
$sent = socket_write($client, $string, $length);
error_log("end 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;
}
}
问题在于,$sent === FALSE
当客户端断开连接时,而且当它们暂时不可用时,这被证明是在发送前几个字节后发生的,因此不会发送整个字符串。
最佳答案
The problem with this is that, $sent === FALSE when the client disconnects, but also when they are temporarily unavailable, which proved to happen after sending the first few bytes, thus not sending the whole string.
您需要检查 socket_last_error()
是否有 EAGAIN
/EWOULDBLOCK
。
它应该是错误编号 11 或 35,表示套接字仍处于连接状态。
编辑:PHP 包括 constants对于套接字错误。
测试 SOCKET_EWOULDBLOCK
。它适用于 Linux 和 Windows。
socket_write definitely does not return after a client disconnect (according to the error log, "start write" shows up, but not "end write" even after waiting for 10 - 30 mins.
如果另一端没有明确关闭连接就消失了,这可能会导致阻塞的 socket_write
调用无限期挂起。
TCP 不会在很长一段时间内自动超时。您可以通过使用非阻塞套接字并测量自上次成功写入以来的时间来强制执行自己的超时。
或者,您可以使用 SO_SNDTIMEO
套接字选项。
关于PHP:当客户端在写入时断开连接时,socket_write 挂起,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30175998/