Home  >  Article  >  Backend Development  >  用浏览器到Nginx服务器这中间到底发生了什么?

用浏览器到Nginx服务器这中间到底发生了什么?

WBOY
WBOYOriginal
2016-06-06 20:33:281548browse

一个URL到nginx服务器,语言用的是PHP,这中间的过程是怎样的。

回复内容:

一个URL到nginx服务器,语言用的是PHP,这中间的过程是怎样的。

Nginx和PHP-FPM之间的通信可以采用TCP网络通信,或者是更加轻量但高并发没有TCP稳定的UnixSock(不需要经过网络),下面以TCP通信说明.

tcpdump/wireshark分析firefox/nginx/php-fpm完成一次PHP请求
用浏览器到Nginx服务器这中间到底发生了什么?

sudo lsof -i -n -P | egrep ":80|:9000" | grep ESTABLISHED

<code>firefox   2510  eechen   69u  IPv4 288893      0t0  TCP 127.0.0.1:57939->127.0.0.1:80 (ESTABLISHED)
nginx     6843     png    3u  IPv4 286299      0t0  TCP 127.0.0.1:80->127.0.0.1:57939 (ESTABLISHED)
nginx     6843     png   17u  IPv4 286300      0t0  TCP 127.0.0.1:58518->127.0.0.1:9000 (ESTABLISHED)
php-fpm   6865     png    3u  IPv4 288877      0t0  TCP 127.0.0.1:9000->127.0.0.1:58518 (ESTABLISHED)
</code>

firefox通过端口57939访问nginx的80端口.
nginx则通过端口58518访问php-fpm的9000端口.
ESTABLISHED表示连接是keep-alive的.

WireShark中监听lo设备或者用tcpdump抓包分析:
sudo tcpdump -s 0 -i lo -w data.pcap port 80 or 9000
WireShark里可以用下面的Filter进行过滤分析:
tcp.port==57939 or tcp.port==58518

57939 > http [SYN]
http > 57939 [SYN, ACK]
57939 > http [ACK]
上面三个包代表firefox和nginx的三次握手.

GET /app/buffer.php HTTP/1.1
http > 57939 [ACK]
这两个包代表firefox向nginx请求一个URL.

58518 > cslistener [SYN]
cslistener > 58518 [SYN, ACK]
58518 > cslistener [ACK]
上面三个包代表nginx和php-fpm的三次握手.

58518 > cslistener [PSH, ACK]
cslistener > 58518 [ACK]
上面两个包代表nginx将firefox的请求转发给php-fpm.

cslistener > 58518 [PSH, ACK] php-fpm向nginx推送数据
58518 > cslistener [ACK] nginx收到数据传输给firefox
[TCP segment of a reassembled PDU]
57939 > http [ACK] firefox收到数据
cslistener > 58518 [PSH, ACK] php-fpm继续向nginx推送数据,进入循环.

cslistener > 58518 [FIN, ACK] php-fpm关闭响应
58518 > cslistener [FIN, ACK] nginx关闭响应
cslistener > 58518 [ACK] php-fpm响应
HTTP/1.1 200 OK (text/html)
57939 > http [ACK] firefox响应

buffer.php测试代码:

<code><?php ignore_user_abort(true);
set_time_limit(0);
ob_end_clean();
ob_start();
for($i=10;$i>0;$i--){
    echo date('H:i:s').'<br>';
    echo str_repeat(' ', 1024*4);
    ob_flush();
    flush();
    sleep(1);
}
echo 'Stop.';
ob_end_flush();
</code>

另外注意: Nginx的gzip可能会进行输出缓存,这将导致flush()函数产生的结果不会立即被发送到客户端浏览器.在Nginx+PHP-FPM下还要注意Nginx的fastcgi buffer,比如:
fastcgi_buffer_size 128k;
fastcgi_buffers 8 128k;
表示Nginx会缓冲PHP-FPM输出的信息,当达到128k时才会将缓冲区的数据发送给客户端,那么我们首先需要将这个缓冲区调小:
fastcgi_buffer_size 4k;
fastcgi_buffers 8 4k;
并且,必须禁用gzip:
gzip off;
然后,在php中,在ob_flush和flush前,输出一段达到4k的内容,例如:
echo str_repeat(' ', 1024*4);
到此,PHP就可以正常通过ob_flush和flush逐行输出需要的内容了.

Statement:
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