lighttpd+fastcgi模块分析

一开始不怎么明白fastcgi和cgi的区别,查了资料说,fastcgi多了一个进程池,不要每次都fork和退出

这个不是重点,还是对着代码看吧

怎样在lighttpd运行php呢,需要下面这样配置

lighttpd+fastcgi模块分析_第1张图片

把fastcig模块的前面井号去掉,然后在下面加上这个相关的配置就可以

fastcgi.debug = 1
fastcgi.server = ( ".php" =>
( "localhost" =>
  (
  "host"=>"127.0.0.1",
  "port"=>4000,
  #"socket" => "/tmp/php.socket",
  "bin-path" => "/usr/bin/php-cgi"
  )
)

)

重启lighttpd,然后就可以访问了

用命令看一下cgi进程

[root@fire-16-168 ~]# ps aux|grep cgi
root 21614 0.0 0.1 471616 18276 ? Ss 15:29 0:00 /usr/bin/php-cgi
root 21615 0.0 0.1 471616 18280 ? Ss 15:29 0:00 /usr/bin/php-cgi
root 21616 0.0 0.1 471616 18276 ? Ss 15:29 0:00 /usr/bin/php-cgi
root 21617 0.0 0.1 471616 18280 ? Ss 15:29 0:00 /usr/bin/php-cgi
root 21619 0.0 0.0 471616 6092 ? S 15:29 0:00 /usr/bin/php-cgi
root 21620 0.0 0.0 471616 6088 ? S 15:29 0:00 /usr/bin/php-cgi
root 21625 0.0 0.0 471616 6088 ? S 15:29 0:00 /usr/bin/php-cgi
root 21628 0.0 0.0 471616 6088 ? S 15:29 0:00 /usr/bin/php-cgi

呵呵,总共有8个进程,

S Interruptible sleep (waiting for an event to complete)

s is a session leader

仔细观察,你会发现这些php-cgi的状态不尽相同,有的是Ss,有的是S,通过man ps你能找到这些状态的含义:

也就是说,Ss状态的进程都是主进程(max-procs代表的那些进程),而S状态的进程都是子进程(PHP_FCGI_CHILDREN代表的那些进程)。如果不相信,你可以使用命令核实一下数量:

再看看网络连接是怎样的

[root@fire-16-168 ~]# netstat -anp|grep cgi
tcp 0 0 127.0.0.1:4000 0.0.0.0:* LISTEN 21614/php-cgi
tcp 0 0 127.0.0.1:4001 0.0.0.0:* LISTEN 21615/php-cgi
tcp 0 0 127.0.0.1:4002 0.0.0.0:* LISTEN 21616/php-cgi
tcp 0 0 127.0.0.1:4003 0.0.0.0:* LISTEN 21617/php-cgi

其中只有4个进程在监听,为什么会这样,还是看代码吧

                for (n = 0; n < da_ext->value->used; n++) {
                    data_array *da_host = (data_array *)da_ext->value->data[n];

                    fcgi_extension_host *host;

                    config_values_t fcv[] = {
                        { "host",              NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 0 主机*/
                        { "docroot",           NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 1 端口*/
                        { "mode",              NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 2 */
                        { "socket",            NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 3 可以用unix套接字域去连接*/
                        { "bin-path",          NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 4 cgi的位置*/

                        { "check-local",       NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },      /* 5 */
                        { "port",              NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 6 */
                        { "min-procs-not-working",         NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 7 this is broken for now */
                        { "max-procs",         NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 8 最大cgi进程数*/
                        { "max-load-per-proc", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 9 */
                        { "idle-timeout",      NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 10 */
                        { "disable-time",      NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 11 */

                        { "bin-environment",   NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },        /* 12 这里是可以传给php-cgi的参数 */
                        { "bin-copy-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },     /* 13 */

                        { "broken-scriptfilename", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },  /* 14 */
                        { "allow-x-send-file",  NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },      /* 15 */
                        { "strip-request-uri",  NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },      /* 16 */
                        { "kill-signal",        NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },      /* 17 */
                        { "fix-root-scriptname",   NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },  /* 18 */

                        { NULL,                NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
                    };

                    if (da_host->type != TYPE_ARRAY) {
                        log_error_write(srv, __FILE__, __LINE__, "ssSBS",
                                "unexpected type for key:",
                                "fastcgi.server",
                                "[", da_host->key, "](string)");

                        return HANDLER_ERROR;
                    }
            #初始化host结构
                    host = fastcgi_host_init();

                    buffer_copy_string_buffer(host->id, da_host->key);
            #host默认值
                    host->check_local  = 1;
                    host->min_procs    = 4;
                    host->max_procs    = 4;
                    host->max_load_per_proc = 1;
                    host->idle_timeout = 60;
                    host->mode = FCGI_RESPONDER;
                    host->disable_time = 60;
                    host->break_scriptfilename_for_php = 0;
                    host->allow_xsendfile = 0; /* handle X-LIGHTTPD-send-file */
                    host->kill_signal = SIGTERM;
                    host->fix_root_path_name = 0;

                    fcv[0].destination = host->host;
                    fcv[1].destination = host->docroot;
                    fcv[2].destination = fcgi_mode;
                    fcv[3].destination = host->unixsocket;
                    fcv[4].destination = host->bin_path;

                    fcv[5].destination = &(host->check_local);
                    fcv[6].destination = &(host->port);
                    fcv[7].destination = &(host->min_procs);
                    fcv[8].destination = &(host->max_procs);
                    fcv[9].destination = &(host->max_load_per_proc);
                    fcv[10].destination = &(host->idle_timeout);
                    fcv[11].destination = &(host->disable_time);

                    fcv[12].destination = host->bin_env;
                    fcv[13].destination = host->bin_env_copy;
                    fcv[14].destination = &(host->break_scriptfilename_for_php);
                    fcv[15].destination = &(host->allow_xsendfile);
                    fcv[16].destination = host->strip_request_uri;
                    fcv[17].destination = &(host->kill_signal);
                    fcv[18].destination = &(host->fix_root_path_name);
            #进行配置文件替换
                    if (0 != config_insert_values_internal(srv, da_host->value, fcv)) {
                        return HANDLER_ERROR;
                    }
          #判断有没有设置端口和socket
                    if ((!buffer_is_empty(host->host) || host->port) &&
                        !buffer_is_empty(host->unixsocket)) {
                        log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
                                "either host/port or socket have to be set in:",
                                da->key, "= (",
                                da_ext->key, " => (",
                                da_host->key, " ( ...");

                        return HANDLER_ERROR;
                    }
                      #使用unix domain socket
                    if (!buffer_is_empty(host->unixsocket)) {
                        /* unix domain socket */
                        struct sockaddr_un un;

                        if (host->unixsocket->used > sizeof(un.sun_path) - 2) {
                            log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
                                    "unixsocket is too long in:",
                                    da->key, "= (",
                                    da_ext->key, " => (",
                                    da_host->key, " ( ...");

                            return HANDLER_ERROR;
                        }
                    } else {
                        /* tcp/ip */

                        if (buffer_is_empty(host->host) &&
                            buffer_is_empty(host->bin_path)) {
                            log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
                                    "host or binpath have to be set in:",
                                    da->key, "= (",
                                    da_ext->key, " => (",
                                    da_host->key, " ( ...");

                            return HANDLER_ERROR;
                        } else if (host->port == 0) {
                            log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
                                    "port has to be set in:",
                                    da->key, "= (",
                                    da_ext->key, " => (",
                                    da_host->key, " ( ...");

                            return HANDLER_ERROR;
                        }
                    }

                    if (!buffer_is_empty(host->bin_path)) {
                        /* a local socket + self spawning */
                        size_t pno;

                        /* HACK:  just to make sure the adaptive spawing is disabled */
                        host->min_procs = host->max_procs;

                        if (host->min_procs > host->max_procs) host->max_procs = host->min_procs;
                        if (host->max_load_per_proc < 1) host->max_load_per_proc = 0;

                        if (s->debug) {
                            log_error_write(srv, __FILE__, __LINE__, "ssbsdsbsdsd",
                                    "--- fastcgi spawning local",
                                    "\n\tproc:", host->bin_path,
                                    "\n\tport:", host->port,
                                    "\n\tsocket", host->unixsocket,
                                    "\n\tmin-procs:", host->min_procs,
                                    "\n\tmax-procs:", host->max_procs);
                        }
              #开始创建进程
                        for (pno = 0; pno < host->min_procs; pno++) {
                            fcgi_proc *proc;

                            proc = fastcgi_process_init();
                            proc->id = host->num_procs++;
                            host->max_id++;

                            if (buffer_is_empty(host->unixsocket)) {
                                proc->port = host->port + pno;
                            } else {
                                buffer_copy_string_buffer(proc->unixsocket, host->unixsocket);
                                buffer_append_string_len(proc->unixsocket, CONST_STR_LEN("-"));
                                buffer_append_long(proc->unixsocket, pno);
                            }

                            if (s->debug) {
                                log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd",
                                        "--- fastcgi spawning",
                                        "\n\tport:", host->port,
                                        "\n\tsocket", host->unixsocket,
                                        "\n\tcurrent:", pno, "/", host->min_procs);
                            }
                 #这个开始创建套接字
                            if (fcgi_spawn_connection(srv, p, host, proc)) {
                                log_error_write(srv, __FILE__, __LINE__, "s",
                                        "[ERROR]: spawning fcgi failed.");
                                return HANDLER_ERROR;
                            }

                            fastcgi_status_init(srv, p->statuskey, host, proc);

                            proc->next = host->first;
                            if (host->first)     host->first->prev = proc;

                            host->first = proc;
                        }
                    } else {
                        fcgi_proc *proc;

                        proc = fastcgi_process_init();
                        proc->id = host->num_procs++;
                        host->max_id++;
                        host->active_procs++;
                        proc->state = PROC_STATE_RUNNING;

                        if (buffer_is_empty(host->unixsocket)) {
                            proc->port = host->port;
                        } else {
                            buffer_copy_string_buffer(proc->unixsocket, host->unixsocket);
                        }

                        fastcgi_status_init(srv, p->statuskey, host, proc);

                        host->first = proc;

                        host->min_procs = 1;
                        host->max_procs = 1;
                    }

                    if (!buffer_is_empty(fcgi_mode)) {
                        if (strcmp(fcgi_mode->ptr, "responder") == 0) {
                            host->mode = FCGI_RESPONDER;
                        } else if (strcmp(fcgi_mode->ptr, "authorizer") == 0) {
                            host->mode = FCGI_AUTHORIZER;
                            if (buffer_is_empty(host->docroot)) {
                                log_error_write(srv, __FILE__, __LINE__, "s",
                                        "ERROR: docroot is required for authorizer mode.");
                                return HANDLER_ERROR;
                            }
                        } else {
                            log_error_write(srv, __FILE__, __LINE__, "sbs",
                                    "WARNING: unknown fastcgi mode:",
                                    fcgi_mode, "(ignored, mode set to responder)");
                        }
                    }

                    /* if extension already exists, take it */
                    fastcgi_extension_insert(s->exts, da_ext->key, host);
                }

 

ok,分析一下流程

1,读取配置文件

2,设置一下默认参数(如果我们某些属性没有设置的话,由系统参数去配置)例如 min-proc 系统默认为4个啊

3,创建套接字 根据fcgi_spawn_connection 这个函数

我们开始分析这个函数

  1 static int fcgi_spawn_connection(server *srv,
  2                  plugin_data *p,
  3                  fcgi_extension_host *host,
  4                  fcgi_proc *proc) {
  5     int fcgi_fd;
  6     int socket_type, status;
  7     struct timeval tv = { 0, 100 * 1000 };
  8 #ifdef HAVE_SYS_UN_H
  9     struct sockaddr_un fcgi_addr_un;
 10 #endif
 11     struct sockaddr_in fcgi_addr_in;
 12     struct sockaddr *fcgi_addr;
 13 
 14     socklen_t servlen;
 15 
 16 #ifndef HAVE_FORK
 17     return -1;
 18 #endif
 19 
 20     if (p->conf.debug) {
 21         log_error_write(srv, __FILE__, __LINE__, "sdb",
 22                 "new proc, socket:", proc->port, proc->unixsocket);
 23     }
 24      #如果unixsocket套接字不为空,也就是有设置啦
 25     if (!buffer_is_empty(proc->unixsocket)) {
 26         memset(&fcgi_addr, 0, sizeof(fcgi_addr));
 27 
 28 #ifdef HAVE_SYS_UN_H
 29         fcgi_addr_un.sun_family = AF_UNIX;
 30         strcpy(fcgi_addr_un.sun_path, proc->unixsocket->ptr);
 31 
 32 #ifdef SUN_LEN
 33         servlen = SUN_LEN(&fcgi_addr_un);
 34 #else
 35         /* stevens says: */
 36         servlen = proc->unixsocket->used + sizeof(fcgi_addr_un.sun_family);
 37 #endif
 38         socket_type = AF_UNIX;
 39         fcgi_addr = (struct sockaddr *) &fcgi_addr_un;
 40 
 41         buffer_copy_string_len(proc->connection_name, CONST_STR_LEN("unix:"));
 42         buffer_append_string_buffer(proc->connection_name, proc->unixsocket);
 43 
 44 #else
 45         log_error_write(srv, __FILE__, __LINE__, "s",
 46                 "ERROR: Unix Domain sockets are not supported.");
 47         return -1;
 48 #endif
 49     } else { #这里就是走tcp模式
 50         fcgi_addr_in.sin_family = AF_INET;
 51 
 52         if (buffer_is_empty(host->host)) {
 53             fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
 54         } else {
 55             struct hostent *he;
 56 
 57             /* set a useful default */
 58             fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
 59 
 60               #获取主机的真实地址
 61             if (NULL == (he = gethostbyname(host->host->ptr))) {
 62                 log_error_write(srv, __FILE__, __LINE__,
 63                         "sdb", "gethostbyname failed: ",
 64                         h_errno, host->host);
 65                 return -1;
 66             }
 67 
 68             if (he->h_addrtype != AF_INET) {
 69                 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-type != AF_INET: ", he->h_addrtype);
 70                 return -1;
 71             }
 72 
 73             if (he->h_length != sizeof(struct in_addr)) {
 74                 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-length != sizeof(in_addr): ", he->h_length);
 75                 return -1;
 76             }
 77 
 78             memcpy(&(fcgi_addr_in.sin_addr.s_addr), he->h_addr_list[0], he->h_length);
 79 
 80         }
#绑定端口
81 fcgi_addr_in.sin_port = htons(proc->port); 82 servlen = sizeof(fcgi_addr_in); 83 84 socket_type = AF_INET; 85 fcgi_addr = (struct sockaddr *) &fcgi_addr_in; 86 87 buffer_copy_string_len(proc->connection_name, CONST_STR_LEN("tcp:")); 88 if (!buffer_is_empty(host->host)) { 89 buffer_append_string_buffer(proc->connection_name, host->host); 90 } else { 91 buffer_append_string_len(proc->connection_name, CONST_STR_LEN("localhost")); 92 } 93 buffer_append_string_len(proc->connection_name, CONST_STR_LEN(":")); 94 buffer_append_long(proc->connection_name, proc->port); 95 } 96 #建立socket 97 if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) { 98 log_error_write(srv, __FILE__, __LINE__, "ss", 99 "failed:", strerror(errno)); 100 return -1; 101 } 102 #连接socket 103 if (-1 == connect(fcgi_fd, fcgi_addr, servlen)) { 104 /* server is not up, spawn it 连接失败,则说明服务器还没有起来 */ 105 pid_t child; 106 int val; 107 108 if (errno != ENOENT && 109 !buffer_is_empty(proc->unixsocket)) { 110 unlink(proc->unixsocket->ptr); 111 } 112 113 close(fcgi_fd); 114 115 /* reopen socket 重新打开socket */ 116 if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) { 117 log_error_write(srv, __FILE__, __LINE__, "ss", 118 "socket failed:", strerror(errno)); 119 return -1; 120 } 121 122 val = 1; 123 if (setsockopt(fcgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) { 124 log_error_write(srv, __FILE__, __LINE__, "ss", 125 "socketsockopt failed:", strerror(errno)); 126 return -1; 127 } 128 129 /* create socket */ 130 if (-1 == bind(fcgi_fd, fcgi_addr, servlen)) { 131 log_error_write(srv, __FILE__, __LINE__, "sbs", 132 "bind failed for:", 133 proc->connection_name, 134 strerror(errno)); 135 return -1; 136 } 137 #监听socket 138 if (-1 == listen(fcgi_fd, 1024)) { 139 log_error_write(srv, __FILE__, __LINE__, "ss", 140 "listen failed:", strerror(errno)); 141 return -1; 142 } 143 144 #ifdef HAVE_FORK 开始生产进程 145 switch ((child = fork())) { 146 case 0: { 147 size_t i = 0; 148 char *c; 149 char_array env; 150 char_array arg; 151 152 /* create environment */ 153 env.ptr = NULL; 154 env.size = 0; 155 env.used = 0; 156 157 arg.ptr = NULL; 158 arg.size = 0; 159 arg.used = 0; 160 161 if(fcgi_fd != FCGI_LISTENSOCK_FILENO) { 162 close(FCGI_LISTENSOCK_FILENO); 163 dup2(fcgi_fd, FCGI_LISTENSOCK_FILENO); 164 close(fcgi_fd); 165 } 166 167 openDevNull(STDERR_FILENO); 168 169 /* we don't need the client socket */ 170 for (i = 3; i < 256; i++) { 171 close(i); 172 } 173 174 /* build clean environment */ 175 if (host->bin_env_copy->used) { 176 for (i = 0; i < host->bin_env_copy->used; i++) { 177 data_string *ds = (data_string *)host->bin_env_copy->data[i]; 178 char *ge; 179 180 if (NULL != (ge = getenv(ds->value->ptr))) { 181 env_add(&env, CONST_BUF_LEN(ds->value), ge, strlen(ge)); 182 } 183 } 184 } else { 185 for (i = 0; environ[i]; i++) { 186 char *eq; 187 188 if (NULL != (eq = strchr(environ[i], '='))) { 189 env_add(&env, environ[i], eq - environ[i], eq+1, strlen(eq+1)); 190 } 191 } 192 } 193 194 /* create environment */ 195 for (i = 0; i < host->bin_env->used; i++) { 196 data_string *ds = (data_string *)host->bin_env->data[i]; 197 198 env_add(&env, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value)); 199 } 200 201 for (i = 0; i < env.used; i++) { 202 /* search for PHP_FCGI_CHILDREN */ 203 if (0 == strncmp(env.ptr[i], "PHP_FCGI_CHILDREN=", sizeof("PHP_FCGI_CHILDREN=") - 1)) break; 204 } 205 206 /* not found, add a default */ 207 if (i == env.used) { 208 env_add(&env, CONST_STR_LEN("PHP_FCGI_CHILDREN"), CONST_STR_LEN("1")); 209 } 210 211 env.ptr[env.used] = NULL; 212 #处理cgi程序名字 213 parse_binpath(&arg, host->bin_path); 214 215 /* chdir into the base of the bin-path, 216 * search for the last / */ 217 if (NULL != (c = strrchr(arg.ptr[0], '/'))) { 218 *c = '\0'; 219 220 /* change to the physical directory */ 221 if (-1 == chdir(arg.ptr[0])) { 222 *c = '/'; 223 log_error_write(srv, __FILE__, __LINE__, "sss", "chdir failed:", strerror(errno), arg.ptr[0]); 224 } 225 *c = '/'; 226 } 227 228 229 /* exec the cgi 开始执行cgi */ 230 execve(arg.ptr[0], arg.ptr, env.ptr); 231 232 /* log_error_write(srv, __FILE__, __LINE__, "sbs", 233 "execve failed for:", host->bin_path, strerror(errno)); */ 234 235 exit(errno); 236 237 break; 238 } 239 case -1: 240 /* error */ 241 break; 242 default: 243 /* father */ 244 245 /* wait */ 246 select(0, NULL, NULL, NULL, &tv); 247 248 switch (waitpid(child, &status, WNOHANG)) { 249 case 0: 250 /* child still running after timeout, good */ 251 break; 252 case -1: 253 /* no PID found ? should never happen */ 254 log_error_write(srv, __FILE__, __LINE__, "ss", 255 "pid not found:", strerror(errno)); 256 return -1; 257 default: 258 log_error_write(srv, __FILE__, __LINE__, "sbs", 259 "the fastcgi-backend", host->bin_path, "failed to start:"); 260 /* the child should not terminate at all */ 261 if (WIFEXITED(status)) { 262 log_error_write(srv, __FILE__, __LINE__, "sdb", 263 "child exited with status", 264 WEXITSTATUS(status), host->bin_path); 265 log_error_write(srv, __FILE__, __LINE__, "s", 266 "If you're trying to run PHP as a FastCGI backend, make sure you're using the FastCGI-enabled version.\n" 267 "You can find out if it is the right one by executing 'php -v' and it should display '(cgi-fcgi)' " 268 "in the output, NOT '(cgi)' NOR '(cli)'.\n" 269 "For more information, check http://trac.lighttpd.net/trac/wiki/Docs%3AModFastCGI#preparing-php-as-a-fastcgi-program" 270 "If this is PHP on Gentoo, add 'fastcgi' to the USE flags."); 271 } else if (WIFSIGNALED(status)) { 272 log_error_write(srv, __FILE__, __LINE__, "sd", 273 "terminated by signal:", 274 WTERMSIG(status)); 275 276 if (WTERMSIG(status) == 11) { 277 log_error_write(srv, __FILE__, __LINE__, "s", 278 "to be exact: it segfaulted, crashed, died, ... you get the idea." ); 279 log_error_write(srv, __FILE__, __LINE__, "s", 280 "If this is PHP, try removing the bytecode caches for now and try again."); 281 } 282 } else { 283 log_error_write(srv, __FILE__, __LINE__, "sd", 284 "child died somehow:", 285 status); 286 } 287 return -1; 288 } 289 290 /* register process */ 291 proc->pid = child; 292 proc->last_used = srv->cur_ts; 293 proc->is_local = 1; 294 295 break; 296 } 297 #endif 298 } else { 299 proc->is_local = 0; 300 proc->pid = 0; 301 302 if (p->conf.debug) { 303 log_error_write(srv, __FILE__, __LINE__, "sb", 304 "(debug) socket is already used; won't spawn:", 305 proc->connection_name); 306 } 307 } 308 309 proc->state = PROC_STATE_RUNNING; 310 host->active_procs++; 311 312 close(fcgi_fd); 313 314 return 0; 315 }

上面的流程是这样的

1根据配置文件判断用哪一种方式通讯,有tcp,有unix自身套接字(这个有个局限性,要cgi在同一台机器才能用的

2,连接服务端,如果失败的话则为服务端创建套接字

if(fcgi_fd != FCGI_LISTENSOCK_FILENO) {
close(FCGI_LISTENSOCK_FILENO);
dup2(fcgi_fd, FCGI_LISTENSOCK_FILENO);
close(fcgi_fd);
}

FCGI_LISTENSOCK_FILENO 这个是什么来的

根据fast-cgi协议是这样说的

当应用开始执行时,Web服务器留下一个打开的文件描述符,FCGI_LISTENSOCK_FILENO。该描述符引用Web服务器创建的一个正在监听的socket。

FCGI_LISTENSOCK_FILENO等于STDIN_FILENO。当应用开始执行时,标准的描述符STDOUT_FILENO和STDERR_FILENO被关闭。一个用于应用确定它是用CGI调用的还是用FastCGI调用的可靠方法是调用getpeername(FCGI_LISTENSOCK_FILENO),对于FastCGI应用,它返回-1,并设置errno为ENOTCONN。

Web服务器对于可靠传输的选择,Unix流式管道(AF_UNIX)或TCP/IP(AF_INET),是内含于FCGI_LISTENSOCK_FILENO socket的内部状态中的

呵呵

我们可以看到, 代码把fcgi_fd重定向到FCGI_LISTENSOCK_FILENO 这个身上,这个值为0,巧妙的地方就在这里了

我一直很奇怪在这里找不到accept,实在太笨啦,lighttpd相对于cgi只不过是一个客户端而已,不可能在lighttpd自己身上accept

所以唯一的办法就是把刚刚的套接字传递给cgi

 

为了证明这个东西,我们翻看了php-cgi的代码

 1 int fcgi_fd = 0;
 2 
 3 fastcgi = fcgi_is_fastcgi();
 4     if (bindpath) {
 5         fcgi_fd = fcgi_listen(bindpath, 128);
 6         if (fcgi_fd < 0) {
 7             fprintf(stderr, "Couldn't create FastCGI listen socket on port %s\n", bindpath);
 8 #ifdef ZTS
 9             tsrm_shutdown();
10 #endif
11             return FAILURE;
12         }
13         fastcgi = fcgi_is_fastcgi();
14     }
15     if (fastcgi) {
16         /* How many times to run PHP scripts before dying */
17         if (getenv("PHP_FCGI_MAX_REQUESTS")) {
18             max_requests = atoi(getenv("PHP_FCGI_MAX_REQUESTS"));
19             if (max_requests < 0) {
20                 fprintf(stderr, "PHP_FCGI_MAX_REQUESTS is not valid\n");
21                 return FAILURE;
22             }
23         }
24 
25         /* make php call us to get _ENV vars */
26         php_php_import_environment_variables = php_import_environment_variables;
27         php_import_environment_variables = cgi_php_import_environment_variables;
28 
29         /* library is already initialized, now init our request */
30         request = fcgi_init_request(fcgi_fd);

 

ok,bindpath是何方神圣,通常我们是这样启动cgi的

php-cgi -b 127.0.0.1:9000,我们在上面根本没有传递这个参数给php-cgi,所以判断不成立

在看看fastcgi这个变量是怎样判断的,我们看看这个函数

1 int fcgi_is_fastcgi(void)
2 {
3     if (!is_initialized) {
4         return fcgi_init();
5     } else {
6         return is_fastcgi;
7     }
8 }

 

 1 int fcgi_init(void)
 2 {
 3     if (!is_initialized) {
 4 #ifndef _WIN32
 5         sa_t sa;
 6         socklen_t len = sizeof(sa);
 7 #endif
 8         zend_hash_init(&fcgi_mgmt_vars, 0, NULL, fcgi_free_mgmt_var_cb, 1);
 9         fcgi_set_mgmt_var("FCGI_MPXS_CONNS", sizeof("FCGI_MPXS_CONNS")-1, "0", sizeof("0")-1);
10 
11         is_initialized = 1;
12 #ifdef _WIN32
13 # if 0
14         /* TODO: Support for TCP sockets */
15         WSADATA wsaData;
16 
17         if (WSAStartup(MAKEWORD(2,0), &wsaData)) {
18             fprintf(stderr, "Error starting Windows Sockets.  Error: %d", WSAGetLastError());
19             return 0;
20         }
21 # endif
22         if ((GetStdHandle(STD_OUTPUT_HANDLE) == INVALID_HANDLE_VALUE) &&
23             (GetStdHandle(STD_ERROR_HANDLE)  == INVALID_HANDLE_VALUE) &&
24             (GetStdHandle(STD_INPUT_HANDLE)  != INVALID_HANDLE_VALUE)) {
25             char *str;
26             DWORD pipe_mode = PIPE_READMODE_BYTE | PIPE_WAIT;
27             HANDLE pipe = GetStdHandle(STD_INPUT_HANDLE);
28 
29             SetNamedPipeHandleState(pipe, &pipe_mode, NULL, NULL);
30 
31             str = getenv("_FCGI_SHUTDOWN_EVENT_");
32             if (str != NULL) {
33                 HANDLE shutdown_event = (HANDLE) atoi(str);
34                 if (!CreateThread(NULL, 0, fcgi_shutdown_thread,
35                                   shutdown_event, 0, NULL)) {
36                     return -1;
37                 }
38             }
39             str = getenv("_FCGI_MUTEX_");
40             if (str != NULL) {
41                 fcgi_accept_mutex = (HANDLE) atoi(str);
42             }
43             return is_fastcgi = 1;
44         } else {
45             return is_fastcgi = 0;
46         }
47 #else
48         errno = 0;
49         if (getpeername(0, (struct sockaddr *)&sa, &len) != 0 && errno == ENOTCONN) {
50             fcgi_setup_signals();
51             return is_fastcgi = 1;
52         } else {
53             return is_fastcgi = 0;
54         }
55 #endif
56     }
57     return is_fastcgi;
58 }

呵呵,注意49行用getpeername这个函数,传进去的是套接字是0,还记得我们刚才执行cgi的时候dup2吗,呵呵巧妙就在这里

也就是说如果我们fastcgi的话就直接采用fcgi_fd=0 这个套接字,谜底解开了吧

 

我们再次看看php-cgi是怎样accept的

 

  1 #ifndef PHP_WIN32
  2     /* Pre-fork, if required */
  3     if (getenv("PHP_FCGI_CHILDREN")) {
  4         char * children_str = getenv("PHP_FCGI_CHILDREN");
  5         children = atoi(children_str);
  6         if (children < 0) {
  7             fprintf(stderr, "PHP_FCGI_CHILDREN is not valid\n");
  8             return FAILURE;
  9         }
 10         fcgi_set_mgmt_var("FCGI_MAX_CONNS", sizeof("FCGI_MAX_CONNS")-1, children_str, strlen(children_str));
 11         /* This is the number of concurrent requests, equals FCGI_MAX_CONNS */
 12         fcgi_set_mgmt_var("FCGI_MAX_REQS",  sizeof("FCGI_MAX_REQS")-1,  children_str, strlen(children_str));
 13     } else {
 14         fcgi_set_mgmt_var("FCGI_MAX_CONNS", sizeof("FCGI_MAX_CONNS")-1, "1", sizeof("1")-1);
 15         fcgi_set_mgmt_var("FCGI_MAX_REQS",  sizeof("FCGI_MAX_REQS")-1,  "1", sizeof("1")-1);
 16     }
 17 
 18     if (children) {
 19         int running = 0;
 20         pid_t pid;
 21 
 22         /* Create a process group for ourself & children */
 23         setsid();
 24         pgroup = getpgrp();
 25 #ifdef DEBUG_FASTCGI
 26         fprintf(stderr, "Process group %d\n", pgroup);
 27 #endif
 28 
 29         /* Set up handler to kill children upon exit */
 30         act.sa_flags = 0;
 31         act.sa_handler = fastcgi_cleanup;
 32         if (sigaction(SIGTERM, &act, &old_term) ||
 33             sigaction(SIGINT,  &act, &old_int)  ||
 34             sigaction(SIGQUIT, &act, &old_quit)
 35         ) {
 36             perror("Can't set signals");
 37             exit(1);
 38         }
 39 
 40         if (fcgi_in_shutdown()) {
 41             goto parent_out;
 42         }
 43 
 44         while (parent) {
 45             do {
 46 #ifdef DEBUG_FASTCGI
 47                 fprintf(stderr, "Forking, %d running\n", running);
 48 #endif
 49                 pid = fork();
 50                 switch (pid) {
 51                 case 0:
 52                     /* One of the children.
 53                      * Make sure we don't go round the
 54                      * fork loop any more
 55                      */
 56                     parent = 0;
 57 
 58                     /* don't catch our signals */
 59                     sigaction(SIGTERM, &old_term, 0);
 60                     sigaction(SIGQUIT, &old_quit, 0);
 61                     sigaction(SIGINT,  &old_int,  0);
 62                     break;
 63                 case -1:
 64                     perror("php (pre-forking)");
 65                     exit(1);
 66                     break;
 67                 default:
 68                     /* Fine */
 69                     running++;
 70                     break;
 71                 }
 72             } while (parent && (running < children));
 73 
 74             if (parent) {
 75 #ifdef DEBUG_FASTCGI
 76                 fprintf(stderr, "Wait for kids, pid %d\n", getpid());
 77 #endif
 78                 parent_waiting = 1;
 79                 while (1) {
 80                     if (wait(&status) >= 0) {
 81                         running--;
 82                         break;
 83                     } else if (exit_signal) {
 84                         break;
 85                     }
 86                 }
 87                 if (exit_signal) {
 88 #if 0
 89                     while (running > 0) {
 90                         while (wait(&status) < 0) {
 91                         }
 92                         running--;
 93                     }
 94 #endif
 95                     goto parent_out;
 96                 }
 97             }
 98         }
 99     } else {
100         parent = 0;
101     }
102 
103 #endif /* WIN32 */
104     }

呵呵cgi会先根据获取回来的 PHP_FCGI_CHILDREN 的设置去生成子进程,

/* not found, add a default */
if (i == env.used) {
env_add(&env, CONST_STR_LEN("PHP_FCGI_CHILDREN"), CONST_STR_LEN("1"));
}

lighttpd会默认设置一个啦

所谓的pre-fork模式啦

关于上次怎样区别父进程执行那些代码,子进程执行那些代码相信读者会很容易发现

父进程进行wait,然后做一个管理子进程的多小

子进程就开始accept啦

 

  1         while (!fastcgi || fcgi_accept_request(request) >= 0) {
  2             SG(server_context) = fastcgi ? (void *) request : (void *) 1;
  3             init_request_info(request TSRMLS_CC);
  4             CG(interactive) = 0;
  5 
  6             if (!cgi && !fastcgi) {
  7                 while ((c = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 0, 2)) != -1) {
  8                     switch (c) {
  9 
 10                         case 'a':    /* interactive mode */
 11                             printf("Interactive mode enabled\n\n");
 12                             CG(interactive) = 1;
 13                             break;
 14 
 15                         case 'C': /* don't chdir to the script directory */
 16                             SG(options) |= SAPI_OPTION_NO_CHDIR;
 17                             break;
 18 
 19                         case 'e': /* enable extended info output */
 20                             CG(compiler_options) |= ZEND_COMPILE_EXTENDED_INFO;
 21                             break;
 22 
 23                         case 'f': /* parse file */
 24                             if (script_file) {
 25                                 efree(script_file);
 26                             }
 27                             script_file = estrdup(php_optarg);
 28                             no_headers = 1;
 29                             break;
 30 
 31                         case 'i': /* php info & quit */
 32                             if (script_file) {
 33                                 efree(script_file);
 34                             }
 35                             if (php_request_startup(TSRMLS_C) == FAILURE) {
 36                                 SG(server_context) = NULL;
 37                                 php_module_shutdown(TSRMLS_C);
 38                                 return FAILURE;
 39                             }
 40                             if (no_headers) {
 41                                 SG(headers_sent) = 1;
 42                                 SG(request_info).no_headers = 1;
 43                             }
 44                             php_print_info(0xFFFFFFFF TSRMLS_CC);
 45                             php_request_shutdown((void *) 0);
 46                             fcgi_shutdown();
 47                             exit_status = 0;
 48                             goto out;
 49 
 50                         case 'l': /* syntax check mode */
 51                             no_headers = 1;
 52                             behavior = PHP_MODE_LINT;
 53                             break;
 54 
 55                         case 'm': /* list compiled in modules */
 56                             if (script_file) {
 57                                 efree(script_file);
 58                             }
 59                             SG(headers_sent) = 1;
 60                             php_printf("[PHP Modules]\n");
 61                             print_modules(TSRMLS_C);
 62                             php_printf("\n[Zend Modules]\n");
 63                             print_extensions(TSRMLS_C);
 64                             php_printf("\n");
 65                             php_output_end_all(TSRMLS_C);
 66                             fcgi_shutdown();
 67                             exit_status = 0;
 68                             goto out;
 69 
 70 #if 0 /* not yet operational, see also below ... */
 71                         case '': /* generate indented source mode*/
 72                             behavior=PHP_MODE_INDENT;
 73                             break;
 74 #endif
 75 
 76                         case 'q': /* do not generate HTTP headers */
 77                             no_headers = 1;
 78                             break;
 79 
 80                         case 'v': /* show php version & quit */
 81                             if (script_file) {
 82                                 efree(script_file);
 83                             }
 84                             no_headers = 1;
 85                             if (php_request_startup(TSRMLS_C) == FAILURE) {
 86                                 SG(server_context) = NULL;
 87                                 php_module_shutdown(TSRMLS_C);
 88                                 return FAILURE;
 89                             }
 90                             if (no_headers) {
 91                                 SG(headers_sent) = 1;
 92                                 SG(request_info).no_headers = 1;
 93                             }
 94 #if ZEND_DEBUG
 95                             php_printf("PHP %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2013 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version());
 96 #else
 97                             php_printf("PHP %s (%s) (built: %s %s)\nCopyright (c) 1997-2013 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version());
 98 #endif
 99                             php_request_shutdown((void *) 0);
100                             fcgi_shutdown();
101                             exit_status = 0;
102                             goto out;
103 
104                         case 'w':
105                             behavior = PHP_MODE_STRIP;
106                             break;
107 
108                         case 'z': /* load extension file */
109                             zend_load_extension(php_optarg);
110                             break;
111 
112                         default:
113                             break;
114                     }
115                 }
116 
117                 if (script_file) {
118                     /* override path_translated if -f on command line */
119                     STR_FREE(SG(request_info).path_translated);
120                     SG(request_info).path_translated = script_file;
121                     /* before registering argv to module exchange the *new* argv[0] */
122                     /* we can achieve this without allocating more memory */
123                     SG(request_info).argc = argc - (php_optind - 1);
124                     SG(request_info).argv = &argv[php_optind - 1];
125                     SG(request_info).argv[0] = script_file;
126                 } else if (argc > php_optind) {
127                     /* file is on command line, but not in -f opt */
128                     STR_FREE(SG(request_info).path_translated);
129                     SG(request_info).path_translated = estrdup(argv[php_optind]);
130                     /* arguments after the file are considered script args */
131                     SG(request_info).argc = argc - php_optind;
132                     SG(request_info).argv = &argv[php_optind];
133                 }
134 
135                 if (no_headers) {
136                     SG(headers_sent) = 1;
137                     SG(request_info).no_headers = 1;
138                 }
139 
140                 /* all remaining arguments are part of the query string
141                  * this section of code concatenates all remaining arguments
142                  * into a single string, seperating args with a &
143                  * this allows command lines like:
144                  *
145                  *  test.php v1=test v2=hello+world!
146                  *  test.php "v1=test&v2=hello world!"
147                  *  test.php v1=test "v2=hello world!"
148                 */
149                 if (!SG(request_info).query_string && argc > php_optind) {
150                     int slen = strlen(PG(arg_separator).input);
151                     len = 0;
152                     for (i = php_optind; i < argc; i++) {
153                         if (i < (argc - 1)) {
154                             len += strlen(argv[i]) + slen;
155                         } else {
156                             len += strlen(argv[i]);
157                         }
158                     }
159 
160                     len += 2;
161                     s = malloc(len);
162                     *s = '\0';            /* we are pretending it came from the environment  */
163                     for (i = php_optind; i < argc; i++) {
164                         strlcat(s, argv[i], len);
165                         if (i < (argc - 1)) {
166                             strlcat(s, PG(arg_separator).input, len);
167                         }
168                     }
169                     SG(request_info).query_string = s;
170                     free_query_string = 1;
171                 }
172             } /* end !cgi && !fastcgi */
173 
174             /*
175                 we never take stdin if we're (f)cgi, always
176                 rely on the web server giving us the info
177                 we need in the environment.
178             */
179             if (SG(request_info).path_translated || cgi || fastcgi) {
180                 file_handle.type = ZEND_HANDLE_FILENAME;
181                 file_handle.filename = SG(request_info).path_translated;
182                 file_handle.handle.fp = NULL;
183             } else {
184                 file_handle.filename = "-";
185                 file_handle.type = ZEND_HANDLE_FP;
186                 file_handle.handle.fp = stdin;
187             }
188 
189             file_handle.opened_path = NULL;
190             file_handle.free_filename = 0;
191 
192             /* request startup only after we've done all we can to
193              * get path_translated */
194             if (php_request_startup(TSRMLS_C) == FAILURE) {
195                 if (fastcgi) {
196                     fcgi_finish_request(request, 1);
197                 }
198                 SG(server_context) = NULL;
199                 php_module_shutdown(TSRMLS_C);
200                 return FAILURE;
201             }
202             if (no_headers) {
203                 SG(headers_sent) = 1;
204                 SG(request_info).no_headers = 1;
205             }
206 
207             /*
208                 at this point path_translated will be set if:
209                 1. we are running from shell and got filename was there
210                 2. we are running as cgi or fastcgi
211             */
212             if (cgi || fastcgi || SG(request_info).path_translated) {
213                 if (php_fopen_primary_script(&file_handle TSRMLS_CC) == FAILURE) {
214                     zend_try {
215                         if (errno == EACCES) {
216                             SG(sapi_headers).http_response_code = 403;
217                             PUTS("Access denied.\n");
218                         } else {
219                             SG(sapi_headers).http_response_code = 404;
220                             PUTS("No input file specified.\n");
221                         }
222                     } zend_catch {
223                     } zend_end_try();
224                     /* we want to serve more requests if this is fastcgi
225                      * so cleanup and continue, request shutdown is
226                      * handled later */
227                     if (fastcgi) {
228                         goto fastcgi_request_done;
229                     }
230 
231                     STR_FREE(SG(request_info).path_translated);
232 
233                     if (free_query_string && SG(request_info).query_string) {
234                         free(SG(request_info).query_string);
235                         SG(request_info).query_string = NULL;
236                     }
237 
238                     php_request_shutdown((void *) 0);
239                     SG(server_context) = NULL;
240                     php_module_shutdown(TSRMLS_C);
241                     sapi_shutdown();
242 #ifdef ZTS
243                     tsrm_shutdown();
244 #endif
245                     return FAILURE;
246                 }
247             }
248 
249             if (CGIG(check_shebang_line)) {
250                 /* #!php support */
251                 switch (file_handle.type) {
252                     case ZEND_HANDLE_FD:
253                         if (file_handle.handle.fd < 0) {
254                             break;
255                         }
256                         file_handle.type = ZEND_HANDLE_FP;
257                         file_handle.handle.fp = fdopen(file_handle.handle.fd, "rb");
258                         /* break missing intentionally */
259                     case ZEND_HANDLE_FP:
260                         if (!file_handle.handle.fp ||
261                             (file_handle.handle.fp == stdin)) {
262                             break;
263                         }
264                         c = fgetc(file_handle.handle.fp);
265                         if (c == '#') {
266                             while (c != '\n' && c != '\r' && c != EOF) {
267                                 c = fgetc(file_handle.handle.fp);    /* skip to end of line */
268                             }
269                             /* handle situations where line is terminated by \r\n */
270                             if (c == '\r') {
271                                 if (fgetc(file_handle.handle.fp) != '\n') {
272                                     long pos = ftell(file_handle.handle.fp);
273                                     fseek(file_handle.handle.fp, pos - 1, SEEK_SET);
274                                 }
275                             }
276                             CG(start_lineno) = 2;
277                         } else {
278                             rewind(file_handle.handle.fp);
279                         }
280                         break;
281                     case ZEND_HANDLE_STREAM:
282                         c = php_stream_getc((php_stream*)file_handle.handle.stream.handle);
283                         if (c == '#') {
284                             while (c != '\n' && c != '\r' && c != EOF) {
285                                 c = php_stream_getc((php_stream*)file_handle.handle.stream.handle);    /* skip to end of line */
286                             }
287                             /* handle situations where line is terminated by \r\n */
288                             if (c == '\r') {
289                                 if (php_stream_getc((php_stream*)file_handle.handle.stream.handle) != '\n') {
290                                     long pos = php_stream_tell((php_stream*)file_handle.handle.stream.handle);
291                                     php_stream_seek((php_stream*)file_handle.handle.stream.handle, pos - 1, SEEK_SET);
292                                 }
293                             }
294                             CG(start_lineno) = 2;
295                         } else {
296                             php_stream_rewind((php_stream*)file_handle.handle.stream.handle);
297                         }
298                         break;
299                     case ZEND_HANDLE_MAPPED:
300                         if (file_handle.handle.stream.mmap.buf[0] == '#') {
301                             int i = 1;
302 
303                             c = file_handle.handle.stream.mmap.buf[i++];
304                             while (c != '\n' && c != '\r' && c != EOF) {
305                                 c = file_handle.handle.stream.mmap.buf[i++];
306                             }
307                             if (c == '\r') {
308                                 if (file_handle.handle.stream.mmap.buf[i] == '\n') {
309                                     i++;
310                                 }
311                             }
312                             file_handle.handle.stream.mmap.buf += i;
313                             file_handle.handle.stream.mmap.len -= i;
314                         }
315                         break;
316                     default:
317                         break;
318                 }
319             }
320 
321             switch (behavior) {
322                 case PHP_MODE_STANDARD:
323                     php_execute_script(&file_handle TSRMLS_CC);
324                     break;
325                 case PHP_MODE_LINT:
326                     PG(during_request_startup) = 0;
327                     exit_status = php_lint_script(&file_handle TSRMLS_CC);
328                     if (exit_status == SUCCESS) {
329                         zend_printf("No syntax errors detected in %s\n", file_handle.filename);
330                     } else {
331                         zend_printf("Errors parsing %s\n", file_handle.filename);
332                     }
333                     break;
334                 case PHP_MODE_STRIP:
335                     if (open_file_for_scanning(&file_handle TSRMLS_CC) == SUCCESS) {
336                         zend_strip(TSRMLS_C);
337                         zend_file_handle_dtor(&file_handle TSRMLS_CC);
338                         php_output_teardown();
339                     }
340                     return SUCCESS;
341                     break;
342                 case PHP_MODE_HIGHLIGHT:
343                     {
344                         zend_syntax_highlighter_ini syntax_highlighter_ini;
345 
346                         if (open_file_for_scanning(&file_handle TSRMLS_CC) == SUCCESS) {
347                             php_get_highlight_struct(&syntax_highlighter_ini);
348                             zend_highlight(&syntax_highlighter_ini TSRMLS_CC);
349                             if (fastcgi) {
350                                 goto fastcgi_request_done;
351                             }
352                             zend_file_handle_dtor(&file_handle TSRMLS_CC);
353                             php_output_teardown();
354                         }
355                         return SUCCESS;
356                     }
357                     break;
358 #if 0
359                 /* Zeev might want to do something with this one day */
360                 case PHP_MODE_INDENT:
361                     open_file_for_scanning(&file_handle TSRMLS_CC);
362                     zend_indent();
363                     zend_file_handle_dtor(&file_handle TSRMLS_CC);
364                     php_output_teardown();
365                     return SUCCESS;
366                     break;
367 #endif
368             }
369 
370 fastcgi_request_done:
371             {
372                 STR_FREE(SG(request_info).path_translated);
373 
374                 php_request_shutdown((void *) 0);
375 
376                 if (exit_status == 0) {
377                     exit_status = EG(exit_status);
378                 }
379 
380                 if (free_query_string && SG(request_info).query_string) {
381                     free(SG(request_info).query_string);
382                     SG(request_info).query_string = NULL;
383                 }
384             }
385 
386             if (!fastcgi) {
387                 if (benchmark) {
388                     repeats--;
389                     if (repeats > 0) {
390                         script_file = NULL;
391                         php_optind = orig_optind;
392                         php_optarg = orig_optarg;
393                         continue;
394                     }
395                 }
396                 break;
397             }
398 
399             /* only fastcgi will get here */
400             requests++;
401             if (max_requests && (requests == max_requests)) {
402                 fcgi_finish_request(request, 1);
403                 if (bindpath) {
404                     free(bindpath);
405                 }
406                 if (max_requests != 1) {
407                     /* no need to return exit_status of the last request */
408                     exit_status = 0;
409                 }
410                 break;
411             }
412             /* end of fastcgi loop */
413         }

 

 

最终会通过 php_execute_script(&file_handle TSRMLS_CC);  这个函数执行php脚本,到了这里我们可以回答我们上面的那个问题

 

num-procs = max-procs * ( 1 + PHP_FCGI_CHILDREN )  = 8个

本文玩,大家有什么疑问可以留言啊

 参考文章  http://www.360doc.com/content/12/1027/22/834950_244161021.shtml

                http://www.cppblog.com/woaidongmao/archive/2011/06/21/149101.html   fast-cgi协议

                 http://blog.csdn.net/springfieldking/article/details/8204210   fast-cgi工作原理

 

转载于:https://www.cnblogs.com/simonlu/p/3978109.html

你可能感兴趣的:(php,网络,开发工具)