Lighttpd工作流程

 Lighttpd工作流程

一.    Lighttpd主工作模式

Lighttpd的工作模式是可以配置的,一般是多进程的,一个监控进程,其他是工作进程。在配置文件lighttpd.conf中,如果有配置项server.max-worker=6(举例为6),即lighttpd启动后会创建6个工作进程,1个监控进程;如果server.max-worker=0,或者该项没有,则只创建一个工作进程,没有监控进程。

具体代码如下:

#ifdefHAVE_FORK

      /* start watcher and workers */

      num_childs = srv->srvconf.max_worker; //取得配置的工作进程数目,如果为0则直接跳过以下的代码,只有一个进程。

      if (num_childs > 0) {

             int child = 0;

             while (!child &&!srv_shutdown && !graceful_shutdown) {

                    if (num_childs > 0) {

                           switch (fork()) {

                           case -1:

                                  return -1;

                           case 0:

                                  child = 1;//子进程,将跳出循环往下执行

                                  break;

                           default:

                                  num_childs--;//父进程,将待创建的进程数减小,父进程的child还为0

                                  break;

                           }

                    } else {//此处父进程创建完所有的工作进程后等待

                           int status;

 

                           if (-1 !=wait(&status)) {

                                  /**

                                   * one of our workers went away

                                   */

                                  num_childs++;//父进程保持睡眠,但是一旦发现有子进程退出,父进程就苏醒,将待创建的子进程数数目增1,下一个while循环将创建新的工作子进程

                           } else {

                                  switch(errno) {

                                  case EINTR:

                                         /**

                                          * if we receive a SIGHUP we have to close ourlogs ourself as we don't

                                          * have the mainloop who can help us here

                                          */

                                         if(handle_sig_hup) {

                                                handle_sig_hup= 0;

 

                                                log_error_cycle(srv);

 

                                                /**

                                                 * forward to all procs in the process-group

                                                 *

                                                 * we also send it ourself

                                                 */

                                                if(!forwarded_sig_hup) {

                                                       forwarded_sig_hup= 1;

                                                       kill(0,SIGHUP);

                                                }

                                         }

                                         break;

                                  default:

                                         break;

                                  }

                           }

                    }

             }

 

             /**

              * for the parent this is the exit-point

              */

             if (!child) {父进程执行到这,表示服务器程序要退出了,于是作一些清理的工作,包括终止所有的工作进程。

                    /**

                     * kill all children too

                     */

                    if (graceful_shutdown) {

                           kill(0, SIGINT);

                    } else if (srv_shutdown) {

                           kill(0, SIGTERM);

                    }

 

                    log_error_close(srv);

                    network_close(srv);

                    connections_free(srv);

                    plugins_free(srv);

                    server_free(srv);

                    return 0;

             }

      }

#endif

二.Lighttpd的处理状态机

Lighttpd启动后进入监听模式,如果有新的连接请求,则创建一个数据结构管理该连接,该连接被赋予不同的11个连接状态,如下图所示,以下具体详细描述不同的状态:

序列

状态

状态CON_STATE_

含义

1

connect

CONNECT

等待连接

2

reqstart

REQUEST_START

等待读

3

read

READ

HTTP请求头数据

4

reqend

REQUEST_END

解析客户端请求数据

5

readpost

READ_POST

HTTP请求体数据

6

handlereq

HANDLE_REQUEST

内部处理请求,可能导致等待子请求

7

respstart

RESPONSE_START

准备响应头数据

8

write

WRITE

写响应数据,包括响应头和响应体

9

respend

RESPONSE_END

响应完成,进行清理及日志工作

10

error

ERROR

重置连接,包括关闭

11

close

CLOSE

关闭连接

 

三.Lighttpd的多路复用

Lighttpd主循环支持多种多路复用技术,本文只探讨linuxepoll模型。

3.1模型初始化

如下所示:fdevents*fdevent_init(server *srv, size_t maxfds, fdevent_handler_t type)

{

………

      caseFDEVENT_HANDLER_LINUX_SYSEPOLL:

             if(0 != fdevent_linux_sysepoll_init(ev)) {

                    log_error_write(srv,__FILE__, __LINE__, "S",

                           "event-handlerlinux-sysepoll failed, try to set server.event-handler = \"poll\" or\"select\"");

                    gotoerror;

             }

             returnev;

………

}

3.2注册回调函数

int network_register_fdevents(server *srv){

      size_ti;

 

      if(-1 == fdevent_reset(srv->ev)) {

             return-1;

      }

      /*register fdevents after reset */

      for(i = 0; i < srv->srv_sockets.used; i++) {

             server_socket*srv_socket = srv->srv_sockets.ptr[i];

 

             fdevent_register(srv->ev,srv_socket->fd, network_server_handle_fdevent, srv_socket);

             fdevent_event_set(srv->ev,&(srv_socket->fde_ndx), srv_socket->fd, FDEVENT_IN);

      }

      return0;

}

3.2模型主框架

             if((n = fdevent_poll(srv->ev, 1000)) > 0) {//suyi kernel poll

                    /*n is the number of events */

                    intrevents;

                    intfd_ndx;

                    fd_ndx= -1;

                    do{

                           fdevent_handlerhandler;

                           void*context;

                           handler_tr;

 

                           fd_ndx = fdevent_event_next_fdndx (srv->ev,fd_ndx);//遍历整个触发的事件

                           if(-1 == fd_ndx) break; /* not all fdevent handlers know how many fds got anevent */

 

                           revents= fdevent_event_get_revent (srv->ev, fd_ndx);

                           fd     = fdevent_event_get_fd     (srv->ev, fd_ndx);

                           handler= fdevent_get_handler(srv->ev, fd); //此处的handler3.2中的函数进行注册

                           context= fdevent_get_context(srv->ev, fd);

 

                           switch(r =(*handler)(srv, context, revents)) {//回调函数执行

                           caseHANDLER_FINISHED:

                           caseHANDLER_GO_ON:

                           caseHANDLER_WAIT_FOR_EVENT:

                           caseHANDLER_WAIT_FOR_FD:

                                  break;

                           caseHANDLER_ERROR:

                                  /*should never happen */

                                  SEGFAULT();

                                  break;

                           default:

                                  log_error_write(srv,__FILE__, __LINE__, "d", r);

                                  break;

                           }

                    }while (--n > 0); //epoll_wait返回的触发事件的个数

             }else if (n < 0 && errno != EINTR) { //epoll_wait发生错误

                    log_error_write(srv,__FILE__, __LINE__, "ss",

                                  "fdevent_pollfailed:",

                                  strerror(errno));

             }

 

你可能感兴趣的:(Lighttpd工作流程)