宝哥软件园

深度分析php在浏览器退出后还会继续执行吗?

编辑:宝哥软件园 来源:互联网 时间:2021-10-30

前提:我们这里说的是典型的lnmp结构和nginx php-fpm的模式。

如果我有一个执行非常慢的php程序,即使当我在代码中sleep()然后浏览器连接到服务时,我也会启动一个php-fpm进程,但是此时,如果浏览器关闭,服务器上的这个php-fpm进程会在此时继续运行吗?

今天就是要解决这个问题。

最简单的实验。

最简单的方法是做实验。我们写一个程序:在睡眠前后,我们用file_put_contents写日志:

?phpfile _ put _ contents('/tmp/test . log ',' 11111 '。PHP_EOL,FILE _ APPEND | LOCK _ EX);睡眠(3);file _ put _ contents('/tmp/test . log ',' 2222 '。PHP_EOL,FILE _ APPEND | LOCK _ EX);实际操作的结果是,当我们在服务器睡眠期间关闭客户端浏览器时,2222将被写入日志。

意味着浏览器关闭后服务器上的php会继续运行?

忽略用户中止

老王和迪奥金提醒,这可能与php的ignore_user_abort函数有关。

所以我稍微修改了一下代码:

?phpignore _ user _ abort(false);file _ put _ contents('/tmp/test . log ',' 11111 '。PHP_EOL,FILE _ APPEND | LOCK _ EX);睡眠(3);file _ put _ contents('/tmp/test . log ',' 2222 '。PHP_EOL,FILE _ APPEND | LOCK _ EX);发现没有软件,无论设置什么值,都将继续执行ignore_user_abort。

但是这里有一个问题。什么是: user_abort?

在关于cli模式中止的文档中非常清楚,当php脚本被执行并且用户终止脚本时,中止将被触发。然后脚本根据ignore_user_abort决定是否继续执行。

然而,官方文件并没有明确描述cgi模式的中止。感觉即使客户端断开连接,cgi模式下的php也不会收到中止。

ignore_user_abort在cgi模式下没用吗?

是心跳问题吗?

首先想到的是心跳吗?当我们断开浏览器客户端时,我们断开客户端而不关闭,直到tcp keepalive达到时间限制,服务器才会检测到它。

好的,我们需要先消除浏览器设置的保活问题。

放弃浏览器,简单编写一个客户端程序:程序连接到http服务后,发送一个头,程序在sleep1的1秒内主动关闭连接,但是这个程序没有带http的keepalive头。

程序如下:

package main import ' net ' import ' fmt ' import ' time ' func main(){ conn,_ :=net。拨号(' tcp ',' 192.168.33.10:10011') fmt。Fprintf(conn,Get/index . phbhttp/1.0 r n r n ')time . sleep(1 * time . second)conn . close()return }服务器程序:

?phpignore _ user _ abort(false);file _ put _ contents('/tmp/test . log ',' 11111 '。PHP_EOL,FILE _ APPEND | LOCK _ EX);睡眠(3);file _ put _ contents('/tmp/test . log ',' 2222 '。PHP_EOL,FILE _ APPEND | LOCK _ EX);仍然发现不管是否设置了ignore_user_abort,php都会继续执行整个脚本。似乎ignore_user_abort仍未生效。

如何触发ignore_user_abort?

如何触发ignore_user_abort?服务器怎么知道这个套接字不能用?老王和迪奥金说在判断套接字是否可以使用之前,服务器是否应该主动与套接字进行交互?

此外,我们还发现php提供了两种方法,connection_status和connection _ aborted,可以检测当前的连接状态。因此,我们的日志行可以更改为:

file _ put _ contents('/tmp/test . log ',' 1连接状态: '。connection_status()。abort :’。connection _中止()。PHP_EOL,FILE _ APPEND | LOCK _ EX);根据手动连接处理,我们可以打印出当前的连接状态。

仍然缺少一个与socket交互的程序。我们用echo,以后记得带同花顺,消除了同花顺的影响。

程序更改为

?phpignore_user_abort(真);file _ put _ contents('/tmp/test . log ',' 1连接状态: '。connection_status()。abort :’。connection _中止()。PHP_EOL,FILE _ APPEND | LOCK _ EX);睡眠(3);for($ I=0;10美元;$ I){ echo ' 22222 ';flush();睡眠(1);file _ put _ contents('/tmp/test . log ',' 2连接状态: '。connection_status()。abort :’。connection _中止()。PHP_EOL,FILE _ APPEND | LOCK _ EX);}很好,执行我们之前写的客户端。观察日志:

1连接状态:0端口:02连接状态:0端口:02连接状态:1端口336012连接状态:1端口:12 c连接状态33601端口:12连接状态33601端口:12连接状态33601端口:12连接状态33601端口:12连接部分状态日志还显示以下次数的中止状态为1。

但是这里有一个奇怪的地方,为什么前2个连接状态的状态还是0 (NORMAL)?

英特尔的快速储存技术

我们使用wireshark捕获包来查看客户端-服务器交互的整个过程。

在这个过程中,只发送了14个数据包。当服务器第一次发送22222时,客户端返回rst。没有后续的包请求。

因此,可以理解,客户端和服务器之间的大致交互过程如下:

当服务器在循环中第一次发送2222时,客户端已断开连接并返回rst,但发送过程被视为成功请求。直到第二次,当服务器想再次写入这个套接字时,套接字不会进行网络传输,直接返回连接状态已经中止。因此,出现上述情况,第一次222是状态0,第二次出现中止。

验证策略。

我们也可以用strace php -S XXX进行验证。

整个过程的日志如下:

close(5)=0 stat('/tmp/test。log ',{st_mode=S_IFREG|0644,st_size=49873651,})=0open('/tmp/test.log ',O_WRONLY|O_CREAT|O_APPEND,0666)=5fstat(5,{st_mode=S_IFREG|0644,st_size=49873651,})=0 SEEK(5,0,SEEK _ CUR)=0 SEEK(5,0,SEEK_CUR)=0flock(5,LOCK_EX)=0write(5,' 1连接状态: 0abort:0n ',30)=30close(5)=0sendto(4,' HTTP/1.0 200 OK r n连接: clo '.89,0,NULL,0)=89sendto(4,' 111111111 ',9,0,NULL,0)=9rt_sigprocmask(SIG_BLOCK,[CHLD],[],8)=0rt_sigaction(SIGCHLD,NULL,{SIG_DFL,[],0},8)=0rt_sigprocmask(SIG_SETMASK,[],NULL,8)=0nanosleep({3,0},0x 7fff 60 a 40290)=.})=0 SEEK(5,0,SEEK _ CUR)=0 SEEK(5,0,SEEK_CUR)=0flock(5,LOCK_EX)=0write(5,' 2连接状态: 0abort:0n ',30)=30 close(5)=0rt _ sigprocmask(SIG _ BLOCK,[CHLD],[],8)=0rt_sigaction(SIGCHLD,NULL,{SIG_DFL,[],0},8)=0rt_sigprocmask(SIG_SETMASK).})=0 SEEK(5,0,SEEK _ CUR)=0 SEEK(5,0,SEEK_CUR)=0flock(5,LOCK_EX)=0write(5,' 2连接状态: 1abort:1n ',30)=30 close(5)=0rt _ sigprocmask(SIG _ BLOCK,[CHLD],[],8)=0rt_sigaction(SIGCHLD,NULL,{SIG_DFL,[],0},8)=0rt_sigprocmask(SIG_SETMASK).})=0 SEEK(5,0,SEEK _ CUR)=0 SEEK(5,0,SEEK_CUR)=0flock(5,LOCK_EX)=0write(5,' 2连接状态: 1abort:1n ',30)=30close(5)。我们照中看状态从0到一转变的地方。sendto(4,' 22222 ',5,0,NULL,0)=5.写(5,' 2连接状态: 0abort:0n ',30)=30 close(5)=0rt _ sigprocmask(SIG _ BLOCK,[CHLD],[],8)=0rt_sigaction(SIGCHLD,NULL,{SIG_DFL,[],0},8)=0rt_sigprocmask(SIG_SETMASK,[],NULL,8)=0nanosleep({1,0},0x 7ff 60 a 40290)=0 send to(4,' 220).})=0 SEEK(5,0,SEEK _ CUR)=0 SEEK(5,0,SEEK_CUR)=0flock(5,LOCK_EX)=0write(5,' 2连接状态: 1abort:1n ',30)=30close(5)第二次往窝中发送2222的时候显示了破裂的管道。这就是程序告诉我们,这个窝已经不能使用了,顺便服务器端编程语言(专业超文本预处理器的缩写)中的连接状态就会被设置为一了。后续的写操作也都不会再执行了。

总结

正常情况下,如果客户端客户异常推出了,服务端的程序还是会继续执行,直到与超正析象管(图像或图标)进行了两次交互操作。服务端发现客户端已经断开连接,这个时候会触发一个用户_中止,如果这个没有设置忽略用户中止,那么这个进程的程序才会被中断。

至此,问题结了。

以上这篇深入剖析浏览器退出之后服务器端编程语言(专业超文本预处理器的缩写)还会继续执行么就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们。

更多资讯
游戏推荐
更多+