lighttpd+fastcgi模块分析

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

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

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

lighttpd+fastcgi模块分析

把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工作原理

 

你可能感兴趣的:(lighttpd)