PHP:socket_write在写入时客户端断开连接时挂起

时间:2015-05-11 19:24:13

标签: php apache

虽然我在iOS应用程序中收到数据(收到一些数据,但不是全部)我故意退出应用程序并且socket_write挂起在服务器上。以下是相关代码:

error_log("start write");
$sent = socket_write($client, $string, $length);
error_log("end write");

我在错误日志中收到"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;  
    }
}

问题在于,$sent === FALSE当客户端断开连接时,以及当它们暂时不可用时,这证明在发送前几个字节后发生,因此不发送整个字符串。

3 个答案:

答案 0 :(得分:2)

  

这个问题是,当客户端断开连接时,$ sent === FALSE,但是当它们暂时不可用时,这证明在发送前几个字节后发生,因此不发送整个字符串。

您需要检查socket_last_error() / EAGAIN的{​​{1}}。

它应该是错误号11或35,并且表示套接字仍然连接。

编辑: PHP包含constants套接字错误。

测试EWOULDBLOCK。它适用于Linux和Linux。视窗。

  

在客户端断开连接后,socket_write肯定不会返回   (根据错误日志,“开始写入”显示,但不是“结束   写“即使等了10 - 30分钟。

如果另一端在没有明确关闭连接的情况下消失,则可能导致阻止SOCKET_EWOULDBLOCK调用无限期挂起。

TCP不会自动超时很长时间。您可以使用非阻塞套接字来强制执行自己的超时。测量自上次成功写入以来的时间。

或者,您可以使用socket_write套接字选项。

答案 1 :(得分:1)

您应该使用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);
            }
        }
    }
}

答案 2 :(得分:0)

我的解决方案是使用socket_select,超时为3秒。我认为就计算机而言,“暂时不可用”和“断开连接”是同义词。