PHP 在 Nginx 下主动断开连接 Connection Close 与 ignore_user_abort 后台运行

这两天弄个PHP调用 SVN 同步 update 多台服务器更新的程序,为了避免 commit 的时候不会被阻塞卡半天得想个办法只请求触发,而不需要等待程序 update 完成返回结果这样耗时太长,所以研究过了下如何让PHP主动断开连接的方法。搞了一下午,发现很多问题,还好最终还是弄出来了,主要是 Nginx 太坑。。


废话不多说,下面上代码:




/**
 * 主动断开与客户端浏览器的连接
 * 如果是 Nginx 服务器需要输出大于等于 fastcgi_buffer_size 缓存的数据才能即时输出 header 断开连接, 若还是不行可尝试关闭 gzip
 * 如: fastcgi_buffer_size 64k; 即: 需要 64*1024 字符(可多不可少),
 * 可使用 str_repeat(‘ ‘, 65536); 另外 str_repeat(‘          ‘, 6554); 这种方式其实生成速度更慢
 * @param null|string $str 当前输出的内容, 若无需输出则设置为空
 */
public function connectionClose($str = null) {
    $str = ob_get_contents() . $str;
    // 若实际输出内容长度小于该值将可能导致主动断开失败
    header(‘Content-Length: ‘. strlen($str));
    Header::connectionClose();
    ob_start();
    echo $str;
    ob_flush();
    flush();
}

补充说明下:

对于 apache 一般没什问题,我一开始在 windows 上用的 xampp 调试的 没发现什么问题,结果到服务器上是 Nginx ,死活不行,崩溃了一下午,后来才反映过来是 Nginx 的 fastcgi_buffer 的问题。

各种情况测试了N多次,应该没什么 BUG 了。。。


另外再说说 ignore_user_abort() 函数的问题

当浏览器关闭后,决定程序是否还会在后台继续执行,(下图的例子中,你在测试时不一定非要设置为永不超时 limit 0 ,设置一两分钟就行了,否则可能重启 HTTP 服务需要很长时间)





简单来说,如果你要用户浏览器关闭后还需要程序继续执行,那么你必须加上下面这句代码:

ignore_user_abort(true);

但根据你后面程序(主要是 while 死循环)的情况不同而有些许不同:

一般在程序中你可以监控连接状态进行控制:

$isAborted = connection_aborted();
$status = connection_status();
if (0 !== $status || $isAborted) {
    break;
}

但这两个函数要想正常工作得有个前提,就是你的程序必须要有输出内容,且大于当前WebServer 的输出缓存,这样才会起作用。

如果你只是简单的输出一个空格 echo ’ ‘; 可能得循环几千次才会判断到,所以为了更即时的检测到状态你必须每次循环时输出足够多的内容才会触发状态检测。

所以这里也经常会遇到一个问题:当浏览器断开后,即使没有使用 ignore_user_abort(true); 但因为没有任何输出,导致程序仍然会继续执行,死循环会一直跑,如果设置了超时那还好,否则就真死掉了。


下面贴上测试代码(贴个图主要是为了防盗 嘿嘿~)


set_time_limit(0);

ignore_user_abort(true);

while (1) {
    echo str_repeat(‘ ‘, 65536);
    $isAborted = connection_aborted();
    $status = connection_status();
    file_put_contents(‘test.txt‘, ‘time: ‘. time() .‘; abroted:‘. $isAborted .‘; status: ‘. $status);
    if (0 !== $status || $isAborted) {
        break;
    }
    sleep(2);
}

你可以试试注释掉这句

// echo str_repeat(’ ‘, 65536);

另外

set_time_limit(0); 最好也别用 0

版权声明:本文为博主原创文章,未经博主允许不得转载。http://blog.csdn.net/zhouzme

时间: 2024-10-14 05:31:20

PHP 在 Nginx 下主动断开连接 Connection Close 与 ignore_user_abort 后台运行的相关文章

在HTTP通讯过程中,是客户端还是服务端主动断开连接?

比如说:IE访问IIS,获取文件,肯定是要建立一个连接,这个连接在完成通讯后,是客户端Close了连接,还是服务端Close了连接.我用程序测模拟IE和IIS,都没有收到断开连接的消息,也就是都没有触发OnClose事件.我是用Socket建立的连接.如果两方面都没有主动断开连接,那么我猜测可能是传输的数据中有结束的标志,请问这个标志是怎样的?谢谢各位. 解决方案 ? 不知道iis是怎么弄得http的回应包中有个字段通常是close收到指定长度之后就应该断开的. HTTP 你的意思是B/S模式的

linux下ping加时间戳实时输出到文件 放后台运行

放后台运行命令:setsid 实时输出命令:unbuffer 加时间戳:awk '{ print $0"\t" strftime("%D_%H:%M:%S",systime()) } ' 命令如下:setsid unbuffer ping 172.17.1.1 -i 2 | awk '{ print $0"\t" strftime("%D_%H:%M:%S",systime()) } '  >> test.txt

windows下修改tomcat的startup.bat脚本文件后台运行

1.修改startup.bat文件 rem Get remaining unshifted command line arguments and save them in the set CMD_LINE_ARGS= :setArgs if ""%1""=="""" goto doneSetArgs set CMD_LINE_ARGS=%CMD_LINE_ARGS% %1 shift goto setArgs :doneSet

关于TCP主动关闭连接中的wait_timeout

首先我们先来回顾一下tcp关闭连接的过程: 假设A和B连接状态为EST,A需要主动关闭: A发送FIN给B,并将状态更改为FIN_WAIT1, B接收到FIN将状态更改为CLOSE_WAIT,并回复ACK和FIN A收到ACK后将状态更改为FIN_WAIT2,收到FIN后,更改状态为WAIT_TIMEOUT并给B返回ACK B收到ACK后,将关闭自己的链接CLOSE. 问题就在此时,A将处于WAIT_TIMEOUT状态长达2MSL时常(RFC793定义了MSL为2分钟,Linux设置成了30s)

Tcp服务端判断客户端是否断开连接

今天搞tcp链接弄了一天,前面创建socket,绑定,监听等主要分清自己的参数,udp还是tcp的.好不容易调通了,然后就是一个需求,当客户端主动断开连接时,服务端也要断开连接,这样一下次客户端请求链接的时候才能成功链接. 然后就开始找各种方法.其中简单的是看recv()返回为0,表明断开了链接,但是recv函数始终返回SOCKET_ERROR,找不到原因............ 参考的方法: 下面来罗列一下判断远端已经断开的方法: 法一: 当recv()返回值小于等于0时,socket连接断开

PHP主动断开与浏览器的连接

曾经整理过一篇<关于PHP连接处理中set_time_limit().connection_status()和ignore_user_abort()深入解析>,是讲解浏览器客户端断开时,服务器PHP脚本的处理. 这篇文章,将讲解一下服务器PHP脚本怎样主动断开与浏览器的连接,主要方法是使用http协议header中的Content-Length和Connection Content-Length的作用:浏览器接收到指定Content-Length大小的消息实体后,则会断开与服务器的连接. Co

linux下命令行连接FTP是遇到的错误(425 Failed to establish connection)

linux下命令行连接FTP是遇到的错误(425 Failed to establish connection) 首先FTP的运行模式有主动模式和被动模式两种 然后笔者在工作中搭建了ftp,但是没有开启他的被动模式. 然后server端的防火墙开放了21端口. 因此客户端能连上server,但是输入命令会提示.(首先要数据passive off命令关闭客户端以被动模式连接server端) 原因是ftp在主动模式下是通过21端口进行登陆的,但是后续是通过20端口与客户端进行数据交换. 因此笔者在这

HTTP 499状态码 nginx下499错误及其解决方法

HTTP 499 状态码 nginx下 499错误: HTTP 499 状态码 nginx下 499错误 日志记录中HTTP状态码出现499错误有多种情况,我遇到的一种情况是nginx反代到一个永远打不开的后端,就这样了,日志状态记录是499.发送字节数是0. 老是有用户反映网站系统时好时坏,因为线上的产品很长时间没有修改,所以前端程序的问题基本上可以排除,于是就想着是Get方式调用的接口不稳定,问了相关人员,说没有问题,为了拿到确切证据,于是我问相关人员要了nginx服务器的日志文件(awst

【转】HTTP 499 状态码 nginx下 499错误

HTTP 499 状态码 nginx下 499错误 日志记录中HTTP状态码出现499错误有多种情况,我遇到的一种情况是nginx反代到一个永远打不开的后端,就这样了,日志状态记录是499.发送字节数是0. 老是有用户反映网站系统时好时坏,因为线上的产品很长时间没有修改,所以前端程序的问题基本上可以排除,于是就想着是Get方式调用的接口不稳定,问了相关人员,说没有问题,为了拿到确切证据,于是我问相关人员要了nginx服务器的日志文件(awstats日志),分析后发现日志中很多错误码为499的错误