<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>潘锦的空间 &#187; FastCGI</title>
	<atom:link href="https://www.phppan.com/tag/fastcgi/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.phppan.com</link>
	<description>SaaS SaaS架构 团队管理 技术管理 技术架构 PHP 内核 扩展 项目管理</description>
	<lastBuildDate>Sun, 12 Apr 2026 03:47:23 +0000</lastBuildDate>
	<language>zh-CN</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=3.9.40</generator>
	<item>
		<title>TIPI020203-FastCGI</title>
		<link>https://www.phppan.com/2011/01/tipi020203-fastcgi/</link>
		<comments>https://www.phppan.com/2011/01/tipi020203-fastcgi/#comments</comments>
		<pubDate>Fri, 28 Jan 2011 06:22:17 +0000</pubDate>
		<dc:creator><![CDATA[admin]]></dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[CGI]]></category>
		<category><![CDATA[FastCGI]]></category>
		<category><![CDATA[TIPI]]></category>
		<category><![CDATA[深入理解PHP内核]]></category>

		<guid isPermaLink="false">http://www.phppan.com/?p=1253</guid>
		<description><![CDATA[FastCGI简介 什么是CGI CGI全称是“通用网关接口”(Common Gateway Interfac [&#8230;]]]></description>
				<content:encoded><![CDATA[<h2 style="font-weight: bold; font-family: 'Microsoft YaHei', Helvetica, Arial, sans-serif; font-size: 1.2em; color: #333333;">FastCGI简介</h2>
<hr style="border: 1px dashed #cccccc;" />
<h3 style="font-weight: bold; font-family: 'Microsoft YaHei', Helvetica, Arial, sans-serif; font-size: 1.1em; color: #333333;">什么是CGI</h3>
<p style="text-indent: 2em;">CGI全称是“通用网关接口”(Common Gateway Interface)， 它可以让一个客户端，从网页浏览器向执行在Web服务器上的程序，请求数据。 CGI描述了客户端和这个程序之间传输数据的一种标准。 CGI的一个目的是要独立于任何语言的，所以CGI可以用任何一种语言编写，只要这种语言具有标准输入、输出和环境变量。如php,perl,tcl等</p>
<h3 style="font-weight: bold; font-family: 'Microsoft YaHei', Helvetica, Arial, sans-serif; font-size: 1.1em; color: #333333;">什么是FastCGI</h3>
<p style="text-indent: 2em;">FastCGI像是一个常驻(long-live)型的CGI，它可以一直执行着，只要激活后，不会每次都要花费时间去fork一次(这是CGI最为人诟病的fork-and-execute 模式)。它还支持分布式的运算, 即 FastCGI 程序可以在网站服务器以外的主机上执行并且接受来自其它网站服务器来的请求。</p>
<p style="text-indent: 2em;">FastCGI是语言无关的、可伸缩架构的CGI开放扩展，其主要行为是将CGI解释器进程保持在内存中并因此获得较高的性能。众所周知，CGI解释器的反复加载是CGI性能低下的主要原因，如果CGI解释器保持在内存中并接受FastCGI进程管理器调度，则可以提供良好的性能、伸缩性、Fail- Over特性等等。</p>
<h3 style="font-weight: bold; font-family: 'Microsoft YaHei', Helvetica, Arial, sans-serif; font-size: 1.1em; color: #333333;">FastCGI的工作原理</h3>
<ol>
<li>Web Server启动时载入FastCGI进程管理器（IIS ISAPI或Apache Module)</li>
<li>FastCGI进程管理器自身初始化，启动多个CGI解释器进程(可见多个php-cgi)并等待来自Web Server的连接。</li>
<li>当客户端请求到达Web Server时，FastCGI进程管理器选择并连接到一个CGI解释器。Web server将CGI环境变量和标准输入发送到FastCGI子进程php-cgi。</li>
<li>FastCGI子进程完成处理后将标准输出和错误信息从同一连接返回Web Server。当FastCGI子进程关闭连接时，请求便告处理完成。FastCGI子进程接着等待并处理来自FastCGI进程管理器(运行在Web Server中)的下一个连接。 在CGI模式中，php-cgi在此便退出了。</li>
</ol>
<h2 style="font-weight: bold; font-family: 'Microsoft YaHei', Helvetica, Arial, sans-serif; font-size: 1.2em; color: #333333;">PHP中的CGI实现</h2>
<hr style="border: 1px dashed #cccccc;" />
<p style="text-indent: 2em;">PHP的cgi实现本质是是以socket编程实现一个tcp或udp协议的服务器，当启动时，创建tcp/udp协议的服务器的socket监听，并接收相关请求进行处理。这只是请求的处理，在此基础上添加模块初始化，sapi初始化，模块关闭，sapi关闭等就构成了整个cgi的生命周期。 程序是从cgi_main.c文件的main函数开始，而在main函数中调用了定义在fastcgi.c文件中的初始化，监听等函数。我们从main函数开始，看看PHP对于fastcgi的实现。</p>
<p style="text-indent: 2em;">这里将整个流程分为初始化操作，请求处理，关闭操作三个部分。 我们就整个流程进行简单的说明，并在其中穿插介绍一些用到的重要函数。</p>
<h3 style="font-weight: bold; font-family: 'Microsoft YaHei', Helvetica, Arial, sans-serif; font-size: 1.1em; color: #333333;">初始化操作</h3>
<p style="text-indent: 2em;">过程说明见代码注释</p>
<pre style="background-color: #333333; color: #ffffff; font: normal normal normal 13px/normal 'Bitstream Vera Sans Mono', 'DejaVu Sans Mono', 'Courier New', monospace; overflow-x: auto; overflow-y: auto; padding: 10px;"><span style="color: #bd48b3; font-style: italic;">/* {{{ main
 */</span>
<span style="color: #1299da;">int</span> main<span style="color: #ffffff;">(</span><span style="color: #1299da;">int</span> argc<span style="color: #e0882f;">,</span> <span style="color: #1299da;">char</span> <span style="color: #e0882f;">*</span>argv<span style="color: #ffffff;">[</span><span style="color: #ffffff;">]</span><span style="color: #ffffff;">)</span>
<span style="color: #ffffff;">{</span>
...
<span style="color: #ffffff;">sapi_startup</span><span style="color: #ffffff;">(</span><span style="color: #e0882f;">&amp;</span>cgi_sapi_module<span style="color: #ffffff;">)</span><span style="color: #e0882f;">;</span> <span style="color: #bc9458; font-style: italic;">//  1512行 启动sapi,调用sapi全局构造函数，初始化sapi_globals_struct结构体</span>
... <span style="color: #bc9458; font-style: italic;">//  根据启动参数，初始化信息</span>

<span style="color: #ff8400;">if</span> <span style="color: #ffffff;">(</span>cgi_sapi_module.<span style="color: #ffffff;">startup</span><span style="color: #ffffff;">(</span><span style="color: #e0882f;">&amp;</span>cgi_sapi_module<span style="color: #ffffff;">)</span> <span style="color: #e0882f;">==</span> FAILURE<span style="color: #ffffff;">)</span> <span style="color: #ffffff;">{</span> <span style="color: #bc9458; font-style: italic;">//  模块初始化 调用php_cgi_startup方法</span>
...
<span style="color: #ffffff;">}</span>

...
<span style="color: #ff8400;">if</span> <span style="color: #ffffff;">(</span>bindpath<span style="color: #ffffff;">)</span> <span style="color: #ffffff;">{</span>
    fcgi_fd <span style="color: #e0882f;">=</span> fcgi_listen<span style="color: #ffffff;">(</span>bindpath<span style="color: #e0882f;">,</span> <span style="color: #1299da;">128</span><span style="color: #ffffff;">)</span><span style="color: #e0882f;">;</span>   <span style="color: #bc9458; font-style: italic;">//  实现socket监听，调用fcgi_init初始化</span>
    ...
<span style="color: #ffffff;">}</span>

<span style="color: #ff8400;">if</span> <span style="color: #ffffff;">(</span>fastcgi<span style="color: #ffffff;">)</span> <span style="color: #ffffff;">{</span>
    ...
    <span style="color: #bd48b3; font-style: italic;">/* library is already initialized, now init our request */</span>
    fcgi_init_request<span style="color: #ffffff;">(</span><span style="color: #e0882f;">&amp;</span>request<span style="color: #e0882f;">,</span> fcgi_fd<span style="color: #ffffff;">)</span><span style="color: #e0882f;">;</span>   <span style="color: #bc9458; font-style: italic;">//  request内存分配，初始化变量</span>
<span style="color: #ffffff;">}</span></pre>
<p style="text-indent: 2em;">fcgi_listen函数主要用于创建、绑定socket并开始监听</p>
<pre style="background-color: #333333; color: #ffffff; font: normal normal normal 13px/normal 'Bitstream Vera Sans Mono', 'DejaVu Sans Mono', 'Courier New', monospace; overflow-x: auto; overflow-y: auto; padding: 10px;">    <span style="color: #ff8400;">if</span> <span style="color: #ffffff;">(</span><span style="color: #ffffff;">(</span>listen_socket <span style="color: #e0882f;">=</span> socket<span style="color: #ffffff;">(</span>sa.<span style="color: #ffffff;">sa</span>.<span style="color: #ffffff;">sa_family</span><span style="color: #e0882f;">,</span> SOCK_STREAM<span style="color: #e0882f;">,</span> <span style="color: #1299da;">0</span><span style="color: #ffffff;">)</span><span style="color: #ffffff;">)</span> <span style="color: #e0882f;">&lt;</span> <span style="color: #1299da;">0</span> <span style="color: #e0882f;">||</span>
        ...
        <span style="color: #ffffff;">bind</span><span style="color: #ffffff;">(</span>listen_socket<span style="color: #e0882f;">,</span> <span style="color: #ffffff;">(</span><span style="color: #1299da;">struct</span> sockaddr <span style="color: #e0882f;">*</span><span style="color: #ffffff;">)</span> <span style="color: #e0882f;">&amp;</span>sa<span style="color: #e0882f;">,</span> sock_len<span style="color: #ffffff;">)</span> <span style="color: #e0882f;">&lt;</span> <span style="color: #1299da;">0</span> <span style="color: #e0882f;">||</span>
        listen<span style="color: #ffffff;">(</span>listen_socket<span style="color: #e0882f;">,</span> backlog<span style="color: #ffffff;">)</span> <span style="color: #e0882f;">&lt;</span> <span style="color: #1299da;">0</span><span style="color: #ffffff;">)</span> <span style="color: #ffffff;">{</span>
        ...
    <span style="color: #ffffff;">}</span></pre>
<h3 style="font-weight: bold; font-family: 'Microsoft YaHei', Helvetica, Arial, sans-serif; font-size: 1.1em; color: #333333;">请求处理操作流程</h3>
<p style="text-indent: 2em;">过程说明见代码注释</p>
<pre style="background-color: #333333; color: #ffffff; font: normal normal normal 13px/normal 'Bitstream Vera Sans Mono', 'DejaVu Sans Mono', 'Courier New', monospace; overflow-x: auto; overflow-y: auto; padding: 10px;">    <span style="color: #ff8400;">while</span> <span style="color: #ffffff;">(</span>parent<span style="color: #ffffff;">)</span> <span style="color: #ffffff;">{</span>
        <span style="color: #ff8400;">do</span> <span style="color: #ffffff;">{</span>
            pid <span style="color: #e0882f;">=</span> fork<span style="color: #ffffff;">(</span><span style="color: #ffffff;">)</span><span style="color: #e0882f;">;</span>   <span style="color: #bc9458; font-style: italic;">//  生成新的子进程</span>
            <span style="color: #ff8400;">switch</span> <span style="color: #ffffff;">(</span>pid<span style="color: #ffffff;">)</span> <span style="color: #ffffff;">{</span>
            <span style="color: #ff8400;">case</span> <span style="color: #1299da;">0</span><span style="color: #e0882f;">:</span> <span style="color: #bc9458; font-style: italic;">//  子进程</span>
                parent <span style="color: #e0882f;">=</span> <span style="color: #1299da;">0</span><span style="color: #e0882f;">;</span>

                <span style="color: #bd48b3; font-style: italic;">/* don't catch our signals */</span>
                sigaction<span style="color: #ffffff;">(</span>SIGTERM<span style="color: #e0882f;">,</span> <span style="color: #e0882f;">&amp;</span>old_term<span style="color: #e0882f;">,</span> <span style="color: #1299da;">0</span><span style="color: #ffffff;">)</span><span style="color: #e0882f;">;</span>   <span style="color: #bc9458; font-style: italic;">//  终止信号</span>
                sigaction<span style="color: #ffffff;">(</span>SIGQUIT<span style="color: #e0882f;">,</span> <span style="color: #e0882f;">&amp;</span>old_quit<span style="color: #e0882f;">,</span> <span style="color: #1299da;">0</span><span style="color: #ffffff;">)</span><span style="color: #e0882f;">;</span>   <span style="color: #bc9458; font-style: italic;">//  终端退出符</span>
                sigaction<span style="color: #ffffff;">(</span>SIGINT<span style="color: #e0882f;">,</span>  <span style="color: #e0882f;">&amp;</span>old_int<span style="color: #e0882f;">,</span>  <span style="color: #1299da;">0</span><span style="color: #ffffff;">)</span><span style="color: #e0882f;">;</span>   <span style="color: #bc9458; font-style: italic;">//  终端中断符</span>
                <span style="color: #cc7833;">break</span><span style="color: #e0882f;">;</span>
                ...
                <span style="color: #ff8400;">default</span><span style="color: #e0882f;">:</span>
                <span style="color: #bd48b3; font-style: italic;">/* Fine */</span>
                running<span style="color: #e0882f;">++;</span>
                <span style="color: #cc7833;">break</span><span style="color: #e0882f;">;</span>
        <span style="color: #ffffff;">}</span> <span style="color: #ff8400;">while</span> <span style="color: #ffffff;">(</span>parent <span style="color: #e0882f;">&amp;&amp;</span> <span style="color: #ffffff;">(</span>running <span style="color: #e0882f;">&lt;</span> children<span style="color: #ffffff;">)</span><span style="color: #ffffff;">)</span><span style="color: #e0882f;">;</span>

    ...
        <span style="color: #ff8400;">while</span> <span style="color: #ffffff;">(</span><span style="color: #e0882f;">!</span>fastcgi <span style="color: #e0882f;">||</span> fcgi_accept_request<span style="color: #ffffff;">(</span><span style="color: #e0882f;">&amp;</span>request<span style="color: #ffffff;">)</span> <span style="color: #e0882f;">&gt;=</span> <span style="color: #1299da;">0</span><span style="color: #ffffff;">)</span> <span style="color: #ffffff;">{</span>
        SG<span style="color: #ffffff;">(</span>server_context<span style="color: #ffffff;">)</span> <span style="color: #e0882f;">=</span> <span style="color: #ffffff;">(</span><span style="color: #1299da;">void</span> <span style="color: #e0882f;">*</span><span style="color: #ffffff;">)</span> <span style="color: #e0882f;">&amp;</span>request<span style="color: #e0882f;">;</span>
        init_request_info<span style="color: #ffffff;">(</span>TSRMLS_C<span style="color: #ffffff;">)</span><span style="color: #e0882f;">;</span>
        CG<span style="color: #ffffff;">(</span>interactive<span style="color: #ffffff;">)</span> <span style="color: #e0882f;">=</span> <span style="color: #1299da;">0</span><span style="color: #e0882f;">;</span>
                    ...
            <span style="color: #ffffff;">}</span></pre>
<p style="text-indent: 2em;">在fcgi_accept_request函数中，处理连接请求，忽略受限制客户的请求，调用fcgi_read_request函数（定义在fastcgi.c文件），分析请求的信息，将相关的变量写到对应的变量中。 其中在读取请求内容时调用了safe_read方法。如下所示： <strong>[main() -&gt; fcgi_accept_request() -&gt; fcgi_read_request() -&gt; safe_read()]</strong></p>
<pre style="background-color: #333333; color: #ffffff; font: normal normal normal 13px/normal 'Bitstream Vera Sans Mono', 'DejaVu Sans Mono', 'Courier New', monospace; overflow-x: auto; overflow-y: auto; padding: 10px;"><span style="color: #1299da;">static</span> <span style="color: #cc7833;">inline</span> ssize_t safe_read<span style="color: #ffffff;">(</span>fcgi_request <span style="color: #e0882f;">*</span>req<span style="color: #e0882f;">,</span> <span style="color: #1299da;">const</span> <span style="color: #1299da;">void</span> <span style="color: #e0882f;">*</span>buf<span style="color: #e0882f;">,</span> size_t count<span style="color: #ffffff;">)</span>
<span style="color: #ffffff;">{</span>
    size_t n <span style="color: #e0882f;">=</span> <span style="color: #1299da;">0</span><span style="color: #e0882f;">;</span>
    <span style="color: #ff8400;">do</span> <span style="color: #ffffff;">{</span>
    ... <span style="color: #bc9458; font-style: italic;">//  省略  对win32的处理</span>
        ret <span style="color: #e0882f;">=</span> read<span style="color: #ffffff;">(</span>req<span style="color: #e0882f;">-&gt;</span>fd<span style="color: #e0882f;">,</span> <span style="color: #ffffff;">(</span><span style="color: #ffffff;">(</span><span style="color: #1299da;">char</span><span style="color: #e0882f;">*</span><span style="color: #ffffff;">)</span>buf<span style="color: #ffffff;">)</span><span style="color: #e0882f;">+</span>n<span style="color: #e0882f;">,</span> count<span style="color: #e0882f;">-</span>n<span style="color: #ffffff;">)</span><span style="color: #e0882f;">;</span>   <span style="color: #bc9458; font-style: italic;">//  非win版本的读操作</span>
    ... <span style="color: #bc9458; font-style: italic;">//  省略</span>
    <span style="color: #ffffff;">}</span> <span style="color: #ff8400;">while</span> <span style="color: #ffffff;">(</span>n <span style="color: #e0882f;">!=</span> count<span style="color: #ffffff;">)</span><span style="color: #e0882f;">;</span>

<span style="color: #ffffff;">}</span></pre>
<p style="text-indent: 2em;">在请求初始化完成，读取请求完毕后，就该处理请求的PHP文件了。假设此次请求为PHP_MODE_STANDARD则会调用php_execute_script执行PHP文件。 在此函数中它先初始化此文件相关的一些内容，然后再调用zend_execute_scripts函数，对PHP文件进行词法分析和语法分析，生成中间代码， 并执行zend_execute函数，从而执行这些中间代码。关于整个脚本的执行请参见第三节 脚本的执行。</p>
<h3 style="font-weight: bold; font-family: 'Microsoft YaHei', Helvetica, Arial, sans-serif; font-size: 1.1em; color: #333333;">关闭操作流程</h3>
<p style="text-indent: 2em;">过程说明代码注释</p>
<pre style="background-color: #333333; color: #ffffff; font: normal normal normal 13px/normal 'Bitstream Vera Sans Mono', 'DejaVu Sans Mono', 'Courier New', monospace; overflow-x: auto; overflow-y: auto; padding: 10px;">...
<span style="color: #ffffff;">php_request_shutdown</span><span style="color: #ffffff;">(</span><span style="color: #ffffff;">(</span><span style="color: #1299da;">void</span> <span style="color: #e0882f;">*</span><span style="color: #ffffff;">)</span> <span style="color: #1299da;">0</span><span style="color: #ffffff;">)</span><span style="color: #e0882f;">;</span>   <span style="color: #bc9458; font-style: italic;">//  php请求关闭函数</span>
...
<span style="color: #ffffff;">fcgi_shutdown</span><span style="color: #ffffff;">(</span><span style="color: #ffffff;">)</span><span style="color: #e0882f;">;</span>    <span style="color: #bc9458; font-style: italic;">//  fcgi的关闭 销毁fcgi_mgmt_vars变量</span>
php_module_shutdown<span style="color: #ffffff;">(</span>TSRMLS_C<span style="color: #ffffff;">)</span><span style="color: #e0882f;">;</span>  <span style="color: #bc9458; font-style: italic;">//  模块关闭    清空sapi,关闭zend引擎 销毁内存，清除垃圾等</span>
sapi_shutdown<span style="color: #ffffff;">(</span><span style="color: #ffffff;">)</span><span style="color: #e0882f;">;</span>    <span style="color: #bc9458; font-style: italic;">//  sapi关闭  sapi全局变量关闭等</span>
...</pre>
<h2 style="font-weight: bold; font-family: 'Microsoft YaHei', Helvetica, Arial, sans-serif; font-size: 1.2em; color: #333333;">参考资料</h2>
<hr style="border: 1px dashed #cccccc;" />
<p style="text-indent: 2em;">以下为本篇文章对于一些定义引用的参考资料：</p>
<p>http://www.fastcgi.com/drupal/node/2</p>
<p>http://baike.baidu.com/view/641394.htm</p>
<p style="text-indent: 2em;">作者：TIPI团队</p>
]]></content:encoded>
			<wfw:commentRss>https://www.phppan.com/2011/01/tipi020203-fastcgi/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
