[Transfer] Will php continue to execute after the browser exits? ,php continues to execute_PHP tutorial

WBOY
Release: 2016-07-12 08:52:34
Original
773 people have browsed it

[Transfer] Will php continue to execute after the browser is exited? , php continues to execute

Original link: http://www.cnblogs.com/yjf512/p/5362025.html

Premise: What we are talking about here is the typical lnmp structure, nginx php-fpm mode

If I have a php program that executes very slowly, even sleep() in the code, and then when the browser connects to the service, a php-fpm process will be started, but at this time, if the browser is closed, So, will the php-fpm process on the server continue to run at this time?

Today we are going to solve this problem.

The simplest experiment

The easiest way is to do an experiment. Let’s write a program: use file_put_contents to write logs before and after sleep:

<code class="hljs cs"><?<span class="hljs-function">php
<span class="hljs-title">file_put_contents(<span class="hljs-params"><span class="hljs-string">'/tmp/test.log', <span class="hljs-string">'11111' . PHP_EOL, FILE_APPEND | LOCK_EX);
sleep(<span class="hljs-number">3);
file_put_contents(<span class="hljs-string">'/tmp/test.log', <span class="hljs-string">'2222' . PHP_EOL, FILE_APPEND | LOCK_EX);</span></span></span></span></span></span></span></span></code>
Copy after login

The result of the actual operation is that when we close the client browser while the server is sleeping, 2222 will be written to the log.

So this means that after the browser is closed, the server-side php will still continue to run?

ignore_user_abort

Lao Wang and diogin reminded that this may be related to the ignore_user_abort function of PHP.

So I changed the code slightly to this:

<code class="hljs cs"><?<span class="hljs-function">php
<span class="hljs-title">ignore_user_abort(<span class="hljs-params"><span class="hljs-keyword">false);
file_put_contents(<span class="hljs-string">'/tmp/test.log', <span class="hljs-string">'11111' . PHP_EOL, FILE_APPEND | LOCK_EX);
sleep(<span class="hljs-number">3);
file_put_contents(<span class="hljs-string">'/tmp/test.log', <span class="hljs-string">'2222' . PHP_EOL, FILE_APPEND | LOCK_EX);</span></span></span></span></span></span></span></span></span></code>
Copy after login
Copy after login

It is found that there is no software use. No matter what value ignore_user_abort is set to, it will continue to execute.

But here is a question: What is user_abort?

The document makes it very clear about abort in cli mode. When the php script is executed and the user terminates the script, abort will be triggered. The script then determines whether to continue execution based on ignore_user_abort.

But the official document does not clearly describe abort in cgi mode. It seems that even if the client disconnects, PHP in cgi mode will not receive abort.
Does ignore_user_abort have no effect in cgi mode?

Is it a heartbeat problem?

The first thing that comes to mind is a heartbeat problem? When we disconnect the browser client, it is equivalent to disconnecting the connection without closing the client. The server needs to wait for the TCP keepalive to arrive before detecting it.

Okay, you need to troubleshoot the keepalive problem in the browser settings first.

Abandon the browser and simply write a client program: After the program connects to the http service, it sends a header and sleeps for 1 second before actively closing the connection. However, this program does not have the keepalive header of http.

The procedure is as follows:

<code class="hljs swift">package main

<span class="hljs-keyword">import "net"
<span class="hljs-keyword">import "fmt"
<span class="hljs-keyword">import "time"

<span class="hljs-function"><span class="hljs-keyword">func <span class="hljs-title">main<span class="hljs-params">() {
    conn, <span class="hljs-number">_ := net.<span class="hljs-type">Dial(<span class="hljs-string">"tcp", <span class="hljs-string">"192.168.33.10:10011")
    fmt.<span class="hljs-type">Fprintf(conn, <span class="hljs-string">"GET /index.php HTTP/1.0\r\n\r\n")
    time.<span class="hljs-type">Sleep(<span class="hljs-number">1 * time.<span class="hljs-type">Second)
    conn.<span class="hljs-type">Close()
    <span class="hljs-keyword">return
}</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code>
Copy after login

Server program:

<code class="hljs cs"><?<span class="hljs-function">php
<span class="hljs-title">ignore_user_abort(<span class="hljs-params"><span class="hljs-keyword">false);
file_put_contents(<span class="hljs-string">'/tmp/test.log', <span class="hljs-string">'11111' . PHP_EOL, FILE_APPEND | LOCK_EX);
sleep(<span class="hljs-number">3);
file_put_contents(<span class="hljs-string">'/tmp/test.log', <span class="hljs-string">'2222' . PHP_EOL, FILE_APPEND | LOCK_EX);</span></span></span></span></span></span></span></span></span></code>
Copy after login
Copy after login

I found that it is still the same. PHP will continue to execute the entire script regardless of whether ignore_user_abort is set or not. It seems that ignore_user_abort still does not take effect.

How to trigger ignore_user_abort

How to trigger ignore_user_abort? How does the server know that this socket cannot be used? Lao Wang and Diogin asked whether the server needs to actively interact with the socket to determine whether the socket can be used?

In addition, we also found that PHP provides two methods, connection_status and connection_aborted, both of which can detect the current connection status. So our logging line of code can be changed to:

<code class="hljs lisp">file_put_contents('/tmp/test.log', '<span class="hljs-number">1 connection status: ' . connection_status() . <span class="hljs-string">"abort:" . connection_aborted() . PHP_EOL, FILE_APPEND | LOCK_EX)<span class="hljs-comment">;</span></span></span></code>
Copy after login

According to the manual connection processing display, we can print out the current connection status.

The following is missing a program that interacts with the socket. We use echo, and remember to bring flush later to eliminate the influence of flush.

The program will be changed to:

<code class="hljs django"><span class="xml"><span class="php"><span class="hljs-meta"><?php
ignore_user_abort(<span class="hljs-keyword">true);
file_put_contents(<span class="hljs-string">'/tmp/test.log', <span class="hljs-string">'1 connection status: ' . connection_status() . <span class="hljs-string">"abort:" . connection_aborted() . PHP_EOL, FILE_APPEND | LOCK_EX);

sleep(<span class="hljs-number">3);

<span class="hljs-keyword">for($i = <span class="hljs-number">0; $i < <span class="hljs-number">10; $i++) {
        <span class="hljs-keyword">echo <span class="hljs-string">"22222";
        flush();
        sleep(<span class="hljs-number">1);
        file_put_contents(<span class="hljs-string">'/tmp/test.log', <span class="hljs-string">'2 connection status: ' . connection_status() . <span class="hljs-string">"abort:" . connection_aborted(). PHP_EOL, FILE_APPEND | LOCK_EX);
}</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code>
Copy after login

Very good, execute the client we wrote earlier. Observation log:

<code class="hljs basic"><span class="hljs-symbol">1 connection status: <span class="hljs-number">0abort:<span class="hljs-number">0
<span class="hljs-symbol">2 connection status: <span class="hljs-number">0abort:<span class="hljs-number">0
<span class="hljs-symbol">2 connection status: <span class="hljs-number">1abort:<span class="hljs-number">1
<span class="hljs-symbol">2 connection status: <span class="hljs-number">1abort:<span class="hljs-number">1
<span class="hljs-symbol">2 connection status: <span class="hljs-number">1abort:<span class="hljs-number">1
<span class="hljs-symbol">2 connection status: <span class="hljs-number">1abort:<span class="hljs-number">1
<span class="hljs-symbol">2 connection status: <span class="hljs-number">1abort:<span class="hljs-number">1
<span class="hljs-symbol">2 connection status: <span class="hljs-number">1abort:<span class="hljs-number">1
<span class="hljs-symbol">2 connection status: <span class="hljs-number">1abort:<span class="hljs-number">1
<span class="hljs-symbol">2 connection status: <span class="hljs-number">1abort:<span class="hljs-number">1
<span class="hljs-symbol">2 connection status: <span class="hljs-number">1abort:<span class="hljs-number">1</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code>
Copy after login

Finally made abort. The log also shows that the abort status for the next few times is 1.

But there is something strange here, why is the status of the first 2 connection status still 0 (NORMAL).

RST

We use wireshark to capture packets to see the entire interaction process between the client and the server

This whole process only sends 14 packets. Let’s see that when the server sends 22222 for the first time, the client returns RST. There will be no subsequent package requests.

So I understand, the approximate interaction process between the client and the server is:

When the server sends 2222 for the first time in the loop, the client has disconnected and returns an RST, but this sending process is considered a successful request. Until the second time the server wants to perform a write operation on this socket again, this socket will not perform network transmission, and directly returns that the connection status is abort. So the above situation occurred. The first time 222 was the status was 0, and the abort appeared only the second time.

strace for verification

We can also use strace php -S XXX to verify

The strace log of the entire process is as follows:

<code class="hljs erlang">。。。
<span class="hljs-function"><span class="hljs-title">close<span class="hljs-params">(<span class="hljs-number">5)                                = 0
<span class="hljs-title">lstat<span class="hljs-params">(<span class="hljs-string">"/tmp/test.log", {st_mode=S_IFREG|<span class="hljs-number">0644, st_size=<span class="hljs-number">49873651, ...}) = 0
<span class="hljs-title">open<span class="hljs-params">(<span class="hljs-string">"/tmp/test.log", O_WRONLY|O_CREAT|O_APPEND, <span class="hljs-number">0666) = 5
<span class="hljs-title">fstat<span class="hljs-params">(<span class="hljs-number">5, {st_mode=S_IFREG|<span class="hljs-number">0644, st_size=<span class="hljs-number">49873651, ...}) = 0
<span class="hljs-title">lseek<span class="hljs-params">(<span class="hljs-number">5, <span class="hljs-number">0, SEEK_CUR)                   = 0
<span class="hljs-title">lseek<span class="hljs-params">(<span class="hljs-number">5, <span class="hljs-number">0, SEEK_CUR)                   = 0
<span class="hljs-title">flock<span class="hljs-params">(<span class="hljs-number">5, LOCK_EX)                       = 0
<span class="hljs-title">write<span class="hljs-params">(<span class="hljs-number">5, <span class="hljs-string">"1 connection status: 0abort:0\n", <span class="hljs-number">30) = 30
<span class="hljs-title">close<span class="hljs-params">(<span class="hljs-number">5)                                = 0
<span class="hljs-title">sendto<span class="hljs-params">(<span class="hljs-number">4, <span class="hljs-string">"HTTP/1.0 200 OK\r\nConnection: clo"..., <span class="hljs-number">89, <span class="hljs-number">0, NULL, <span class="hljs-number">0) = 89
<span class="hljs-title">sendto<span class="hljs-params">(<span class="hljs-number">4, <span class="hljs-string">"111111111", <span class="hljs-number">9, <span class="hljs-number">0, NULL, <span class="hljs-number">0)   = 9
<span class="hljs-title">rt_sigprocmask<span class="hljs-params">(SIG_BLOCK, [CHLD], [], <span class="hljs-number">8) = 0
<span class="hljs-title">rt_sigaction<span class="hljs-params">(SIGCHLD, NULL, {SIG_DFL, [], <span class="hljs-number">0}, <span class="hljs-number">8) = 0
<span class="hljs-title">rt_sigprocmask<span class="hljs-params">(SIG_SETMASK, [], NULL, <span class="hljs-number">8) = 0
<span class="hljs-title">nanosleep<span class="hljs-params">({<span class="hljs-number">3, <span class="hljs-number">0}, <span class="hljs-number">0x7fff60a40290)       = 0
<span class="hljs-title">sendto<span class="hljs-params">(<span class="hljs-number">4, <span class="hljs-string">"22222", <span class="hljs-number">5, <span class="hljs-number">0, NULL, <span class="hljs-number">0)       = 5
<span class="hljs-title">open<span class="hljs-params">(<span class="hljs-string">"/tmp/test.log", O_WRONLY|O_CREAT|O_APPEND, <span class="hljs-number">0666) = 5
<span class="hljs-title">fstat<span class="hljs-params">(<span class="hljs-number">5, {st_mode=S_IFREG|<span class="hljs-number">0644, st_size=<span class="hljs-number">49873681, ...}) = 0
<span class="hljs-title">lseek<span class="hljs-params">(<span class="hljs-number">5, <span class="hljs-number">0, SEEK_CUR)                   = 0
<span class="hljs-title">lseek<span class="hljs-params">(<span class="hljs-number">5, <span class="hljs-number">0, SEEK_CUR)                   = 0
<span class="hljs-title">flock<span class="hljs-params">(<span class="hljs-number">5, LOCK_EX)                       = 0
<span class="hljs-title">write<span class="hljs-params">(<span class="hljs-number">5, <span class="hljs-string">"2 connection status: 0abort:0\n", <span class="hljs-number">30) = 30
<span class="hljs-title">close<span class="hljs-params">(<span class="hljs-number">5)                                = 0
<span class="hljs-title">rt_sigprocmask<span class="hljs-params">(SIG_BLOCK, [CHLD], [], <span class="hljs-number">8) = 0
<span class="hljs-title">rt_sigaction<span class="hljs-params">(SIGCHLD, NULL, {SIG_DFL, [], <span class="hljs-number">0}, <span class="hljs-number">8) = 0
<span class="hljs-title">rt_sigprocmask<span class="hljs-params">(SIG_SETMASK, [], NULL, <span class="hljs-number">8) = 0
<span class="hljs-title">nanosleep<span class="hljs-params">({<span class="hljs-number">1, <span class="hljs-number">0}, <span class="hljs-number">0x7fff60a40290)       = 0
<span class="hljs-title">sendto<span class="hljs-params">(<span class="hljs-number">4, <span class="hljs-string">"22222", <span class="hljs-number">5, <span class="hljs-number">0, NULL, <span class="hljs-number">0)       = -1 EPIPE <span class="hljs-params">(Broken pipe)
--- SIGPIPE {<span class="hljs-title">si_signo=SIGPIPE, <span class="hljs-title">si_code=SI_USER, <span class="hljs-title">si_pid=2819, <span class="hljs-title">si_uid=0} ---
<span class="hljs-title">open<span class="hljs-params">(<span class="hljs-string">"/tmp/test.log", O_WRONLY|O_CREAT|O_APPEND, <span class="hljs-number">0666) = 5
<span class="hljs-title">fstat<span class="hljs-params">(<span class="hljs-number">5, {st_mode=S_IFREG|<span class="hljs-number">0644, st_size=<span class="hljs-number">49873711, ...}) = 0
<span class="hljs-title">lseek<span class="hljs-params">(<span class="hljs-number">5, <span class="hljs-number">0, SEEK_CUR)                   = 0
<span class="hljs-title">lseek<span class="hljs-params">(<span class="hljs-number">5, <span class="hljs-number">0, SEEK_CUR)                   = 0
<span class="hljs-title">flock<span class="hljs-params">(<span class="hljs-number">5, LOCK_EX)                       = 0
<span class="hljs-title">write<span class="hljs-params">(<span class="hljs-number">5, <span class="hljs-string">"2 connection status: 1abort:1\n", <span class="hljs-number">30) = 30
<span class="hljs-title">close<span class="hljs-params">(<span class="hljs-number">5)                                = 0
<span class="hljs-title">rt_sigprocmask<span class="hljs-params">(SIG_BLOCK, [CHLD], [], <span class="hljs-number">8) = 0
<span class="hljs-title">rt_sigaction<span class="hljs-params">(SIGCHLD, NULL, {SIG_DFL, [], <span class="hljs-number">0}, <span class="hljs-number">8) = 0
<span class="hljs-title">rt_sigprocmask<span class="hljs-params">(SIG_SETMASK, [], NULL, <span class="hljs-number">8) = 0
<span class="hljs-title">nanosleep<span class="hljs-params">({<span class="hljs-number">1, <span class="hljs-number">0}, <span class="hljs-number">0x7fff60a40290)       = 0
<span class="hljs-title">open<span class="hljs-params">(<span class="hljs-string">"/tmp/test.log", O_WRONLY|O_CREAT|O_APPEND, <span class="hljs-number">0666) = 5
<span class="hljs-title">fstat<span class="hljs-params">(<span class="hljs-number">5, {st_mode=S_IFREG|<span class="hljs-number">0644, st_size=<span class="hljs-number">49873741, ...}) = 0
<span class="hljs-title">lseek<span class="hljs-params">(<span class="hljs-number">5, <span class="hljs-number">0, SEEK_CUR)                   = 0
<span class="hljs-title">lseek<span class="hljs-params">(<span class="hljs-number">5, <span class="hljs-number">0, SEEK_CUR)                   = 0
<span class="hljs-title">flock<span class="hljs-params">(<span class="hljs-number">5, LOCK_EX)                       = 0
<span class="hljs-title">write<span class="hljs-params">(<span class="hljs-number">5, <span class="hljs-string">"2 connection status: 1abort:1\n", <span class="hljs-number">30) = 30
<span class="hljs-title">close<span class="hljs-params">(5)  
。。。</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code>
Copy after login

Let’s take a look at the place where status changes from 0 to 1.

<code class="hljs erlang">...
<span class="hljs-function"><span class="hljs-title">sendto<span class="hljs-params">(<span class="hljs-number">4, <span class="hljs-string">"22222", <span class="hljs-number">5, <span class="hljs-number">0, NULL, <span class="hljs-number">0)       = 5
...
<span class="hljs-title">write<span class="hljs-params">(<span class="hljs-number">5, <span class="hljs-string">"2 connection status: 0abort:0\n", <span class="hljs-number">30) = 30
<span class="hljs-title">close<span class="hljs-params">(<span class="hljs-number">5)                                = 0
<span class="hljs-title">rt_sigprocmask<span class="hljs-params">(SIG_BLOCK, [CHLD], [], <span class="hljs-number">8) = 0
<span class="hljs-title">rt_sigaction<span class="hljs-params">(SIGCHLD, NULL, {SIG_DFL, [], <span class="hljs-number">0}, <span class="hljs-number">8) = 0
<span class="hljs-title">rt_sigprocmask<span class="hljs-params">(SIG_SETMASK, [], NULL, <span class="hljs-number">8) = 0
<span class="hljs-title">nanosleep<span class="hljs-params">({<span class="hljs-number">1, <span class="hljs-number">0}, <span class="hljs-number">0x7fff60a40290)       = 0
<span class="hljs-title">sendto<span class="hljs-params">(<span class="hljs-number">4, <span class="hljs-string">"22222", <span class="hljs-number">5, <span class="hljs-number">0, NULL, <span class="hljs-number">0)       = -1 EPIPE <span class="hljs-params">(Broken pipe)
--- SIGPIPE {<span class="hljs-title">si_signo=SIGPIPE, <span class="hljs-title">si_code=SI_USER, <span class="hljs-title">si_pid=2819, <span class="hljs-title">si_uid=0} ---
<span class="hljs-title">open<span class="hljs-params">(<span class="hljs-string">"/tmp/test.log", O_WRONLY|O_CREAT|O_APPEND, <span class="hljs-number">0666) = 5
<span class="hljs-title">fstat<span class="hljs-params">(<span class="hljs-number">5, {st_mode=S_IFREG|<span class="hljs-number">0644, st_size=<span class="hljs-number">49873711, ...}) = 0
<span class="hljs-title">lseek<span class="hljs-params">(<span class="hljs-number">5, <span class="hljs-number">0, SEEK_CUR)                   = 0
<span class="hljs-title">lseek<span class="hljs-params">(<span class="hljs-number">5, <span class="hljs-number">0, SEEK_CUR)                   = 0
<span class="hljs-title">flock<span class="hljs-params">(<span class="hljs-number">5, LOCK_EX)                       = 0
<span class="hljs-title">write<span class="hljs-params">(<span class="hljs-number">5, <span class="hljs-string">"2 connection status: 1abort:1\n", <span class="hljs-number">30) = 30
<span class="hljs-title">close<span class="hljs-params">(<span class="hljs-number">5)                                = 0</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code>
Copy after login

第二次往socket中发送2222的时候显示了Broken pipe。这就是程序告诉我们,这个socket已经不能使用了,顺便php中的connection_status就会被设置为1了。后续的写操作也都不会再执行了。

总结

正常情况下,如果客户端client异常推出了,服务端的程序还是会继续执行,直到与IO进行了两次交互操作。服务端发现客户端已经断开连接,这个 时候会触发一个user_abort,如果这个没有设置ignore_user_abort,那么这个php-fpm的程序才会被中断。

至此,问题结了。

www.bkjia.comtruehttp://www.bkjia.com/PHPjc/1126842.htmlTechArticle[转]浏览器退出之后php还会继续执行么?,php继续执行 原文链接:http://www.cnblogs.com/yjf512/p/5362025.html 前提:这里说的是典型的lnmp结构,ng...
Related labels:
php
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template