<?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; CGI</title>
	<atom:link href="https://www.phppan.com/tag/cgi/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.phppan.com</link>
	<description>SaaS SaaS架构 团队管理 技术管理 技术架构 PHP 内核 扩展 项目管理</description>
	<lastBuildDate>Sat, 20 Jun 2026 10:07:52 +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>PHP的CGI实现</title>
		<link>https://www.phppan.com/2011/05/php-cgi/</link>
		<comments>https://www.phppan.com/2011/05/php-cgi/#comments</comments>
		<pubDate>Thu, 12 May 2011 06:48:18 +0000</pubDate>
		<dc:creator><![CDATA[admin]]></dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[CGI]]></category>
		<category><![CDATA[PHP源码]]></category>

		<guid isPermaLink="false">http://www.phppan.com/?p=1369</guid>
		<description><![CDATA[FastCGI简介 CGI全称是“通用网关接口”(Common Gateway Interface)， 它可以 [&#8230;]]]></description>
				<content:encoded><![CDATA[<div>
<h2 style="font-weight: bold; font-family: 'Microsoft YaHei', Helvetica, Arial, sans-serif; font-size: 1.2em; color: #333333; padding-top: 5px; padding-right: 0px; padding-bottom: 5px; padding-left: 0px; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #888888;">FastCGI简介<a name="FastCGI简介"></a></h2>
<p style="text-indent: 2em;"><a style="color: #1299da; text-decoration: underline;" href="http://zh.wikipedia.org/wiki/CGI">CGI</a>全称是“通用网关接口”(Common Gateway Interface)， 它可以让一个客户端，从网页浏览器向执行在Web服务器上的程序请求数据。 CGI描述了客户端和这个程序之间传输数据的一种标准。 CGI的一个目的是要独立于任何语言的，所以CGI可以用任何一种语言编写，只要这种语言具有标准输入、输出和环境变量。如php,perl,tcl等</p>
<p style="text-indent: 2em;"><a style="color: #1299da; text-decoration: underline;" href="http://baike.baidu.com/view/641394.htm">FastCGI</a>像是一个常驻(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>
<p style="text-indent: 2em;">一般情况下，FastCGI的整个工作流程是这样的。</p>
<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; padding-top: 5px; padding-right: 0px; padding-bottom: 5px; padding-left: 0px; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #888888;">PHP中的CGI实现<a name="PHP中的CGI实现"></a></h2>
<p style="text-indent: 2em;">PHP的CGI实现本质是是以socket编程实现一个TCP或UDP协议的服务器，当启动时，创建TCP/UDP协议的服务器的socket监听， 并接收相关请求进行处理。这只是请求的处理，在此基础上添加模块初始化，sapi初始化，模块关闭，sapi关闭等就构成了整个CGI的生命周期。</p>
<p style="text-indent: 2em;">以TCP为例，在TCP的服务端，一般会执行这样几个操作步骤：</p>
<ol>
<li>调用socket函数创建一个TCP用的流式套接字；</li>
<li>调用bind函数将服务器的本地地址与前面创建的套接字绑定；</li>
<li>调用listen函数将新创建的套接字作为监听，等待客户端发起的连接，当客户端有多个连接连接到这个套接字时，可能需要排队处理；</li>
<li>服务器进程调用accept函数进入阻塞状态，直到有客户进程调用connect函数而建立起一个连接；</li>
<li>当与客户端创建连接后，服务器调用read_stream函数读取客户的请求；</li>
<li>处理完数据后，服务器调用write函数向客户端发送应答。</li>
</ol>
<p style="text-indent: 2em;">TCP上客户-服务器事务的时序如图2.6所示：</p>
<p style="text-indent: 2em;"><img class="aligncenter size-full wp-image-1371" title="TCP上客户-服务器事务的时序" src="http://www.phppan.com/wp-content/uploads/2011/05/02-02-03-tcp.jpg" alt="TCP上客户-服务器事务的时序" width="643" height="737" /></p>
<p style="text-indent: 2em;">PHP的CGI实现从cgi_main.c文件的main函数开始，在main函数中调用了定义在fastcgi.c文件中的初始化，监听等函数。 对比TCP的流程，我们查看PHP对TCP协议的实现，虽然PHP本身也实现了这些流程，但是在main函数中一些过程被封装成一个函数实现。 对应TCP的操作流程，PHP首先会执行创建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; border-top-left-radius: 4px 4px; border-top-right-radius: 4px 4px; border-bottom-right-radius: 4px 4px; border-bottom-left-radius: 4px 4px; -webkit-box-shadow: #a0a0a0 2px 2px 5px; box-shadow: #a0a0a0 2px 2px 5px; padding: 10px; border: 1px solid #eeeeee;"><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></pre>
<p style="text-indent: 2em;">在fastcgi.c文件中，fcgi_listen函数主要用于创建、绑定socket并开始监听，它走完了前面所列TCP流程的前三个阶段，</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; border-top-left-radius: 4px 4px; border-top-right-radius: 4px 4px; border-bottom-right-radius: 4px 4px; border-bottom-left-radius: 4px 4px; -webkit-box-shadow: #a0a0a0 2px 2px 5px; box-shadow: #a0a0a0 2px 2px 5px; padding: 10px; border: 1px solid #eeeeee;">    <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>
<p style="text-indent: 2em;">当服务端初始化完成后，进程调用accept函数进入阻塞状态，在main函数中我们看到如下代码：</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; border-top-left-radius: 4px 4px; border-top-right-radius: 4px 4px; border-bottom-right-radius: 4px 4px; border-bottom-left-radius: 4px 4px; -webkit-box-shadow: #a0a0a0 2px 2px 5px; box-shadow: #a0a0a0 2px 2px 5px; padding: 10px; border: 1px solid #eeeeee;">    <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函数中，程序会调用accept函数阻塞新创建的进程。 当用户的请求到达时，fcgi_accept_request函数会判断是否处理用户的请求，其中会过滤某些连接请求，忽略受限制客户的请求， 如果程序受理用户的请求，它将分析请求的信息，将相关的变量写到对应的变量中。 其中在读取请求内容时调用了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; border-top-left-radius: 4px 4px; border-top-right-radius: 4px 4px; border-bottom-right-radius: 4px 4px; border-bottom-left-radius: 4px 4px; -webkit-box-shadow: #a0a0a0 2px 2px 5px; box-shadow: #a0a0a0 2px 2px 5px; padding: 10px; border: 1px solid #eeeeee;"><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;">如上对应服务器端读取用户的请求数据。</p>
<p style="text-indent: 2em;">在请求初始化完成，读取请求完毕后，就该处理请求的PHP文件了。 假设此次请求为PHP_MODE_STANDARD则会调用php_execute_script执行PHP文件。 在此函数中它先初始化此文件相关的一些内容，然后再调用zend_execute_scripts函数，对PHP文件进行词法分析和语法分析，生成中间代码， 并执行zend_execute函数，从而执行这些中间代码。关于整个脚本的执行请参见第三节 脚本的执行。</p>
<p style="text-indent: 2em;">在处理完用户的请求后，服务器端将返回信息给客户端，此时在main函数中调用的是fcgi_finish_request(&amp;request, 1); fcgi_finish_request函数定义在fastcgi.c文件中，其代码如下：</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; border-top-left-radius: 4px 4px; border-top-right-radius: 4px 4px; border-bottom-right-radius: 4px 4px; border-bottom-left-radius: 4px 4px; -webkit-box-shadow: #a0a0a0 2px 2px 5px; box-shadow: #a0a0a0 2px 2px 5px; padding: 10px; border: 1px solid #eeeeee;"><span style="color: #1299da;">int</span> fcgi_finish_request<span style="color: #ffffff;">(</span>fcgi_request <span style="color: #e0882f;">*</span>req<span style="color: #e0882f;">,</span> <span style="color: #1299da;">int</span> force_close<span style="color: #ffffff;">)</span>
<span style="color: #ffffff;">{</span>
<span style="color: #1299da;">int</span> ret <span style="color: #e0882f;">=</span> <span style="color: #1299da;">1</span><span style="color: #e0882f;">;</span>

<span style="color: #ff8400;">if</span> <span style="color: #ffffff;">(</span>req<span style="color: #e0882f;">-&gt;</span>fd <span style="color: #e0882f;">&gt;=</span> <span style="color: #1299da;">0</span><span style="color: #ffffff;">)</span> <span style="color: #ffffff;">{</span>
    <span style="color: #ff8400;">if</span> <span style="color: #ffffff;">(</span><span style="color: #e0882f;">!</span>req<span style="color: #e0882f;">-&gt;</span>closed<span style="color: #ffffff;">)</span> <span style="color: #ffffff;">{</span>
        ret <span style="color: #e0882f;">=</span> fcgi_flush<span style="color: #ffffff;">(</span>req<span style="color: #e0882f;">,</span> <span style="color: #1299da;">1</span><span style="color: #ffffff;">)</span><span style="color: #e0882f;">;</span>
        req<span style="color: #e0882f;">-&gt;</span>closed <span style="color: #e0882f;">=</span> <span style="color: #1299da;">1</span><span style="color: #e0882f;">;</span>
    <span style="color: #ffffff;">}</span>
    fcgi_close<span style="color: #ffffff;">(</span>req<span style="color: #e0882f;">,</span> force_close<span style="color: #e0882f;">,</span> <span style="color: #1299da;">1</span><span style="color: #ffffff;">)</span><span style="color: #e0882f;">;</span>
<span style="color: #ffffff;">}</span>
<span style="color: #ff8400;">return</span> ret<span style="color: #e0882f;">;</span>
<span style="color: #ffffff;">}</span></pre>
<p style="text-indent: 2em;">如上，当socket处于打开状态，并且请求未关闭，则会将执行后的结果刷到客户端，并将请求的关闭设置为真。 将数据刷到客户端的程序调用的是fcgi_flush函数。在此函数中，关键是在于答应头的构造和写操作。 程序的写操作是调用的safe_write函数，而safe_write函数中对于最终的写操作针对win和linux环境做了区分， 在Win32下，如果是TCP连接则用send函数，如果是非TCP则和非win环境一样使用write函数。如下代码：</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; border-top-left-radius: 4px 4px; border-top-right-radius: 4px 4px; border-bottom-right-radius: 4px 4px; border-bottom-left-radius: 4px 4px; -webkit-box-shadow: #a0a0a0 2px 2px 5px; box-shadow: #a0a0a0 2px 2px 5px; padding: 10px; border: 1px solid #eeeeee;"><span style="color: #bd48b3; font-style: italic;">#ifdef _WIN32</span>
<span style="color: #ff8400;">if</span> <span style="color: #ffffff;">(</span><span style="color: #e0882f;">!</span>req<span style="color: #e0882f;">-&gt;</span>tcp<span style="color: #ffffff;">)</span> <span style="color: #ffffff;">{</span>
    ret <span style="color: #e0882f;">=</span> write<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: #ffffff;">}</span> <span style="color: #ff8400;">else</span> <span style="color: #ffffff;">{</span>
    ret <span style="color: #e0882f;">=</span> send<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: #e0882f;">,</span> <span style="color: #1299da;">0</span><span style="color: #ffffff;">)</span><span style="color: #e0882f;">;</span>
    <span style="color: #ff8400;">if</span> <span style="color: #ffffff;">(</span>ret <span style="color: #e0882f;">&lt;=</span> <span style="color: #1299da;">0</span><span style="color: #ffffff;">)</span> <span style="color: #ffffff;">{</span>
            errno <span style="color: #e0882f;">=</span> WSAGetLastError<span style="color: #ffffff;">(</span><span style="color: #ffffff;">)</span><span style="color: #e0882f;">;</span>
    <span style="color: #ffffff;">}</span>
<span style="color: #ffffff;">}</span>
<span style="color: #bd48b3; font-style: italic;">#else</span>
ret <span style="color: #e0882f;">=</span> write<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: #bd48b3; font-style: italic;">#endif</span></pre>
<p style="text-indent: 2em;">在发送了请求的应答后，服务器端将会执行关闭操作，仅限于CGI本身的关闭，程序执行的是fcgi_close函数。 fcgi_close函数在前面提的fcgi_finish_request函数中，在请求应答完后执行。同样，对于win平台和非win平台有不同的处理。 其中对于非win平台调用的是write函数。</p>
<p style="text-indent: 2em;">以上是一个TCP服务器端实现的简单说明。这只是我们PHP的CGI模式的基础，在这个基础上PHP增加了更多的功能。 在前面的章节中我们提到了每个SAPI都有一个专属于它们自己的sapi_module_struct结构：cgi_sapi_module，其代码定义如下：</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; border-top-left-radius: 4px 4px; border-top-right-radius: 4px 4px; border-bottom-right-radius: 4px 4px; border-bottom-left-radius: 4px 4px; -webkit-box-shadow: #a0a0a0 2px 2px 5px; box-shadow: #a0a0a0 2px 2px 5px; padding: 10px; border: 1px solid #eeeeee;"><span style="color: #bd48b3; font-style: italic;">/* {{{ sapi_module_struct cgi_sapi_module
 */</span>
<span style="color: #1299da;">static</span> sapi_module_struct cgi_sapi_module <span style="color: #e0882f;">=</span> <span style="color: #ffffff;">{</span>
<span style="color: #99ff00;">"cgi-fcgi"</span><span style="color: #e0882f;">,</span>                     <span style="color: #bd48b3; font-style: italic;">/* name */</span>
<span style="color: #99ff00;">"CGI/FastCGI"</span><span style="color: #e0882f;">,</span>                  <span style="color: #bd48b3; font-style: italic;">/* pretty name */</span>

php_cgi_startup<span style="color: #e0882f;">,</span>                <span style="color: #bd48b3; font-style: italic;">/* startup */</span>
php_module_shutdown_wrapper<span style="color: #e0882f;">,</span>    <span style="color: #bd48b3; font-style: italic;">/* shutdown */</span>

sapi_cgi_activate<span style="color: #e0882f;">,</span>              <span style="color: #bd48b3; font-style: italic;">/* activate */</span>
sapi_cgi_deactivate<span style="color: #e0882f;">,</span>            <span style="color: #bd48b3; font-style: italic;">/* deactivate */</span>

sapi_cgibin_ub_write<span style="color: #e0882f;">,</span>           <span style="color: #bd48b3; font-style: italic;">/* unbuffered write */</span>
sapi_cgibin_flush<span style="color: #e0882f;">,</span>              <span style="color: #bd48b3; font-style: italic;">/* flush */</span>
<span style="color: #cc7833;">NULL</span><span style="color: #e0882f;">,</span>                           <span style="color: #bd48b3; font-style: italic;">/* get uid */</span>
sapi_cgibin_getenv<span style="color: #e0882f;">,</span>             <span style="color: #bd48b3; font-style: italic;">/* getenv */</span>

php_error<span style="color: #e0882f;">,</span>                      <span style="color: #bd48b3; font-style: italic;">/* error handler */</span>

<span style="color: #cc7833;">NULL</span><span style="color: #e0882f;">,</span>                           <span style="color: #bd48b3; font-style: italic;">/* header handler */</span>
sapi_cgi_send_headers<span style="color: #e0882f;">,</span>          <span style="color: #bd48b3; font-style: italic;">/* send headers handler */</span>
<span style="color: #cc7833;">NULL</span><span style="color: #e0882f;">,</span>                           <span style="color: #bd48b3; font-style: italic;">/* send header handler */</span>

sapi_cgi_read_post<span style="color: #e0882f;">,</span>             <span style="color: #bd48b3; font-style: italic;">/* read POST data */</span>
sapi_cgi_read_cookies<span style="color: #e0882f;">,</span>          <span style="color: #bd48b3; font-style: italic;">/* read Cookies */</span>

sapi_cgi_register_variables<span style="color: #e0882f;">,</span>    <span style="color: #bd48b3; font-style: italic;">/* register server variables */</span>
sapi_cgi_log_message<span style="color: #e0882f;">,</span>           <span style="color: #bd48b3; font-style: italic;">/* Log message */</span>
<span style="color: #cc7833;">NULL</span><span style="color: #e0882f;">,</span>                           <span style="color: #bd48b3; font-style: italic;">/* Get request time */</span>
<span style="color: #cc7833;">NULL</span><span style="color: #e0882f;">,</span>                           <span style="color: #bd48b3; font-style: italic;">/* Child terminate */</span>

STANDARD_SAPI_MODULE_PROPERTIES
<span style="color: #ffffff;">}</span><span style="color: #e0882f;">;</span>
<span style="color: #bd48b3; font-style: italic;">/* }}} */</span></pre>
<p style="text-indent: 2em;">同样，以读取cookie为例，当我们在CGI环境下，在PHP中调用读取Cookie时， 最终获取的数据的位置是在激活SAPI时。它所调用的方法是read_cookies。</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; border-top-left-radius: 4px 4px; border-top-right-radius: 4px 4px; border-bottom-right-radius: 4px 4px; border-bottom-left-radius: 4px 4px; -webkit-box-shadow: #a0a0a0 2px 2px 5px; box-shadow: #a0a0a0 2px 2px 5px; padding: 10px; border: 1px solid #eeeeee;">SG<span style="color: #ffffff;">(</span>request_info<span style="color: #ffffff;">)</span>.<span style="color: #ffffff;">cookie_data</span> <span style="color: #e0882f;">=</span> sapi_module.<span style="color: #ffffff;">read_cookies</span><span style="color: #ffffff;">(</span>TSRMLS_C<span style="color: #ffffff;">)</span><span style="color: #e0882f;">;</span></pre>
<p style="text-indent: 2em;">对于每一个服务器在加载时，我们都指定了sapi_module，在第一小节的Apache模块方式中， sapi_module是apache2_sapi_module，其对应read_cookies方法的是php_apache_sapi_read_cookies函数， 而在我们这里，读取cookie的函数是sapi_cgi_read_cookies。 再次说明定义SAPI结构的理由：统一接口，面向接口的编程，具有更好的扩展性和适应性。</p>
<h2 style="font-weight: bold; font-family: 'Microsoft YaHei', Helvetica, Arial, sans-serif; font-size: 1.2em; color: #333333; padding-top: 5px; padding-right: 0px; padding-bottom: 5px; padding-left: 0px; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #888888;">参考资料<a name="参考资料"></a></h2>
<ul>
<li>http://www.fastcgi.com/drupal/node/2</li>
<li>http://baike.baidu.com/view/641394.htm</li>
</ul>
</div>
<p>这是<a style="color: #1299da; text-decoration: underline;" href="http://www.php-internal.com/">TIPI项目</a>第二章第三小节修改后的版本内容，虽然还有一些问题，但是较之前的版本还是有所进步， 至少我们在努力&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>https://www.phppan.com/2011/05/php-cgi/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<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>
