<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                fdevent系統主要是處理各種IO事件,在web服務器中,主要就是向socket寫數據和從socket讀數據。 web服務器是IO密集型程序,因此,大部分的web服務器都采用非阻塞IO進行數據的讀寫。 lighttpd通過fdevent系統,采用類似OO中面向對象的方式將對IO事件的處理進行封裝,對于不同的IO系統,提供一個統一的接口。 lighttpd采用了所謂的Reactor模式,也就是非阻塞IO加多路復用(non-blocking IO + IO multiplexing)。在多路復用上,lighttpd通過fdevent將各種不同的實現進行封裝。 fdevent.h中fdevents結構體相當于一個虛基類,其中的函數指針是純虛函數。對于每種實現,則相當于繼承了這個基類并實現了其中的純虛函數,也就是給函數指針賦一個函數地址值: ~~~ typedef struct fdevents { fdevent_handler_t type; //多路IO類型 fdnode **fdarray; //文件描述符數組 size_t maxfds; //最大的文件描述符數 #ifdef USE_LINUX_SIGIO int in_sigio; int signum; sigset_t sigset; siginfo_t siginfo; bitset *sigbset; #endif #ifdef USE_LINUX_EPOLL int epoll_fd; struct epoll_event *epoll_events; #endif #ifdef USE_POLL struct pollfd *pollfds; //描述符及其狀態的結構體數組 size_t size; //數組中數據的個數 size_t used; //數組的大小 //用于存儲pollfds中為使用的位置。 //由于可能的刪除操作,會是pollfds中存在空檔,將這些空檔 //的索引存在unused中,便于下次插入操作時直接使用這些空檔 //減少空間的浪費。 buffer_int unused; #endif #ifdef USE_SELECT //三個文件描述符集合 fd_set select_read; //可讀,對應FDEVENT_IN fd_set select_write; //可寫,對應FDEVENT_OUT fd_set select_error; //處于異常條件,對應FDEVENT_ERR //由于select函數會修改上面的三個集合, //因此,在這里保存一個初始的副本。 fd_set select_set_read; fd_set select_set_write; fd_set select_set_error; int select_max_fd; //最大的文件描述符數。 #endif #ifdef USE_SOLARIS_DEVPOLL int devpoll_fd; struct pollfd *devpollfds; #endif #ifdef USE_FREEBSD_KQUEUE int kq_fd; struct kevent *kq_results; bitset *kq_bevents; #endif #ifdef USE_SOLARIS_PORT int port_fd; #endif //統一的操作接口,與后面的函數聲明對應。 int (*reset) (struct fdevents * ev); void (*free) (struct fdevents * ev); int (*event_add) (struct fdevents * ev, int fde_ndx, int fd, int events); int (*event_del) (struct fdevents * ev, int fde_ndx, int fd); int (*event_get_revent) (struct fdevents * ev, size_t ndx); int (*event_get_fd) (struct fdevents * ev, size_t ndx); int (*event_next_fdndx) (struct fdevents * ev, int ndx); int (*poll) (struct fdevents * ev, int timeout_ms); int (*fcntl_set) (struct fdevents * ev, int fd); } fdevents; ~~~ 結構體的第一個成員是一個枚舉類型fdevent_handler_t: ~~~ typedef enum { FDEVENT_HANDLER_UNSET, //未定義 FDEVENT_HANDLER_SELECT, //select FDEVENT_HANDLER_POLL, //poll FDEVENT_HANDLER_LINUX_RTSIG, //rtsig FDEVENT_HANDLER_LINUX_SYSEPOLL, //sysepoll FDEVENT_HANDLER_SOLARIS_DEVPOLL, //devpoll FDEVENT_HANDLER_FREEBSD_KQUEUE, //kqueue FDEVENT_HANDLER_SOLARIS_PORT //port } fdevent_handler_t; ~~~ 結構體中的第二個成員fdnode **fdarray是一個fdnode類型變量的數組。fdnode的定義如下: ~~~ typedef struct _fdnode { fdevent_handler handler; //處理函數指針 void *ctx; //文件描述符的context int fd; //文件描述符 struct _fdnode *prev, *next; //指針 } fdnode; ~~~ fdevent_handler handler是一個函數指針,用來存儲這個描述符處理函數的地址,其定義為 ~~~ typedef handler_t(*fdevent_handler) (void *srv, void *ctx, int revents); ~~~ 從最后兩個變量可以看出,這應該是一個鏈表的節點,但是,這個結構體是以數組的形式存儲的,也就是fdevents中的fdarray變量,這樣可以提高查詢的效率。 函數指針: ~~~ /* * 重置和釋放fdevent系統。 */ int fdevent_reset(fdevents * ev); void fdevent_free(fdevents * ev); /* * 將fd增加到fd event系統中。events是要對fd要監聽的事件。 * fde_ndx是fd對應的fdnode在ev->fdarray中的下標值的指針。 * 如果fde_ndx==NULL,則表示在fd event系統中增加fd。如果不為NULL,則表示這個 * fd已經在系統中存在,這個函數的功能就變為將對fd監聽的事件變為events。 */ int fdevent_event_add(fdevents * ev, int *fde_ndx, int fd, int events); /* * 從fd event系統中刪除fd。 fde_ndx的內容和上面的一致。 */ int fdevent_event_del(fdevents * ev, int *fde_ndx, int fd); /* * 返回ndx對應的fd所發生的事件。 * 這里的ndx和上面的fde_ndx不一樣,這個ndx是ev->epoll_events中epoll_event結構體的下標。 * 第一次調用的時候,通常ndx為-1。 * 這個ndx和其對應的fd沒有關系。而fde_ndx等于其對應的fd。 */ int fdevent_event_get_revent(fdevents * ev, size_t ndx); /* * 返回ndx對應的fd。 */ int fdevent_event_get_fd(fdevents * ev, size_t ndx); /* * 返回下一個發生IO事件的fd。 */ int fdevent_event_next_fdndx(fdevents * ev, int ndx); /* * 開始等待IO事件。timeout_ms是超時限制。 */ int fdevent_poll(fdevents * ev, int timeout_ms); /** * 設置fd的狀態,通常是設置為運行exec在子進程中關閉和非阻塞。 */ int fdevent_fcntl_set(fdevents * ev, int fd); ~~~ 在fdevent.c文件中,這些函數的實現基本上都是簡單的調用fdevents結構體中對應的函數指針。對于lighttpd,通過調用上面的這些函數完成IO事件的處理,對于具體到底是誰處理了這些事件,lighttpd并不知道,也不關心。 其他的函數聲明: ~~~ /* * 返回fd對應的事件處理函數地址。也就是fdnode中handler的值。 */ fdevent_handler fdevent_get_handler(fdevents * ev, int fd); /* * 返回fd對應的環境。也就是fdnode中ctx的值。 */ void *fdevent_get_context(fdevents * ev, int fd); /* * 注冊和取消注冊fd。 * 就是生成一個fdnode,然后保存在ev->fdarray中。或者刪除之。 */ int fdevent_register(fdevents * ev, int fd, fdevent_handler handler, void *ctx); int fdevent_unregister(fdevents * ev, int fd); /** * 初始化各種多路IO。 */ int fdevent_select_init(fdevents * ev); int fdevent_poll_init(fdevents * ev); int fdevent_linux_rtsig_init(fdevents * ev); int fdevent_linux_sysepoll_init(fdevents * ev); int fdevent_solaris_devpoll_init(fdevents * ev); int fdevent_freebsd_kqueue_init(fdevents * ev); ~~~ 文件fdevent.h中聲明的一系列函數就是fdevent系統對外的接口,這相當于類的公有函數。lighttpd通過調用這些函數來實現IO事件的處理。在這些函數的具體實現僅僅是簡單的調用了fdevents結構體中的函數指針。而這些函數指針所對應的函數分別定義在以fdevent_開頭的.c文件中。從這些文件的名字可以看出其所對應的IO系統。在這些文件中,函數大多是static,這就相當于類的私有函數,起到隱藏具體實現的效果。 舉個例子: 對外接口fdevent_event_add (相當于公有函數)調用結構體中的函數 (*event_add) , 而函數指針 event_add (純虛函數)指向以fdevent_開頭的.c文件中的相應函數(如fdevent_linux_sysepoll_event_add,私有函數)。 如此一來,具體使用了哪一個IO系統是完全對外隱藏的。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看