Nodejs事件引擎libuv源碼剖析之:句柄(handle)結構的設計剖析


     聲明:本文為原創博文,轉載請注明出處。

     句柄(handle)代表一種對持有資源的索引,句柄的叫法在window上較多,在unix/linux等系統上大多稱之為描述符,為了抽象不同平台的差異,libuv使用統一的結構封裝了不同平台的實現,接下來就看看這個抽象的過程。由於句柄的實現和系統平台有很大關系,本文只針對unix平台作源碼分析。

一、抽象的開始----封裝、繼承、多態

     libuv是用純c語言寫的(排除里面有幾處內聯匯編的用法),怎么還有繼承呢?繼承不都是c++、java、python等這些更高級語言才有的特性嗎?不錯,類似c++這些高級語言,從語言層面就支持了面向對象的三大特性:繼承、封裝與多態,c語言作為一門歷史悠久、簡潔高效的語言,雖然沒有從語言層次提供復雜的對象管理機制,但是通過巧妙的設計也可以寫出面向對象的思想,這在linux內核中體現的淋漓盡致,比如在內核的驅動部分,我們通常在編寫一個字符設備驅動程序時,一定會操作的一個結構體:file_operations(定義在下方),就在一個struct中實現了方法和屬性的封裝,相應的還有其他結構定義充分的利用了“組合”來實現面向對象的“繼承”特性。

 1 struct file_operations {
 2   struct module *owner;
 3   loff_t(*llseek) (struct file *, loff_t, int);
 4   ssize_t(*read) (struct file *, char __user *, size_t, loff_t *);
 5   ssize_t(*aio_read) (struct kiocb *, char __user *, size_t, loff_t);
 6   ssize_t(*write) (struct file *, const char __user *, size_t, loff_t *);
 7   ssize_t(*aio_write) (struct kiocb *, const char __user *, size_t,
 8          loff_t);
 9   int (*readdir) (struct file *, void *, filldir_t);
10   unsigned int (*poll) (struct file *, struct poll_table_struct *);
11   int (*ioctl) (struct inode *, struct file *, unsigned int,
12         unsigned long);
13   ..............
14 }

     總結一下,經過上面的論述,用c語言實現面向對象編程,無外乎兩種方法:在struct中通過“組合”實現面向對象的封裝特性,通過“函數指針”來實現對象方法的封裝,通過工廠方法也可以實現“偽多態”的效果。

     有了上面的理論基礎,來看看libuv是怎么運用這些特性的吧。

二、抽象基類

     libuv中,所有的handle都會有一個共同的抽象基類(這里所說的抽象基類,只是一種稱呼,不要和c++與java中的概念混淆),他就是uv_handle_s,下面來看一下它的定義。

1 /* 所有句柄的抽象基類. */
2 struct uv_handle_s {
3   UV_HANDLE_FIELDS
4 };

     其中,將UV_HANDLE_FIELDS宏展開之后,再次列出:

 1 struct uv_handle_s {
 2   /* public */                                                                \
 3   void* data;                                                                 \ //句柄攜帶的數據
 4   /* read-only */                                                             \
 5   uv_loop_t* loop;                                                            \ //句柄綁定的事件循環
 6   uv_handle_type type;                                                        \ //句柄類型
 7   /* private */                                                               \
 8   uv_close_cb close_cb;                                                       \ //句柄close時的回調
 9   void* handle_queue[2];                                                      \ //句柄隊列節點
10   union {                                                                     \
11     int fd;                                                                   \ //綁定的真實資源索引
12     void* reserved[4];                                                        \
13   } u;                                                                        \
14   UV_HANDLE_PRIVATE_FIELDS                                                    \
15 };

      在正式介紹其成員之前,先將宏UV_HANDLE_PRIVATE_FIELDS也展開(它是一個和平台相關的宏):    

 struct uv_handle_s {
 2   /* public */                                                                \
 3   void* data;                                                                 \ //句柄攜帶的數據
 4   /* read-only */                                                             \
 5   uv_loop_t* loop;                                                            \ //句柄綁定的事件循環
 6   uv_handle_type type;                                                        \ //句柄類型
 7   /* private */                                                               \
 8   uv_close_cb close_cb;                                                       \ //句柄close時的回調
 9   void* handle_queue[2];                                                      \ //句柄隊列節點
10   union {                                                                     \
11     int fd;                                                                   \ //綁定的真實資源索引
12     void* reserved[4];                                                        \
13   } u;                                                                        \
14                                                                               \
15   uv_handle_t* next_closing;                                                  \ //下一個要被關閉的句柄
16   unsigned int flags;                                                         \ //句柄標識
17 };

      以上就是unix平台下的uv_handle_s結構定義,從其成員定義可以看出所有句柄的共性是什么。首先,void *類型的data成員可以用來傳遞任何類型的數據,其上面的注釋“public”表示該數據可被用戶層訪問,而標有“provite”字樣的屬性(成員),則表示不是暴露給用戶使用的,它們只會在libuv內部使用。接下來,有一個uv_loop_t *的指針,從字面上可以看出,這是一個事件循環的指針,在上一篇論述線程池時,已經提及過Reactor線程模型,其中事件循環(loop)就是一個Reactor實例,主要提供了事件的注冊、注銷、dispatch事件的功能,如果你熟悉libevent,它就類似於eventbase,如果你熟悉java中的netty,它就類似於eventloop,好了,這里的loop指針表示這個句柄(handle)是被綁定在哪個事件循環上的;uv_handle_type表示這個句柄的類型,它的取值可以有:UV_TCP、UV_NAMED_PIPE、UV_TTY、UV_UDP、UV_POLL等等;close_cb表示該句柄在關閉時調用的回調函數;handle_queue,作為一個QUEUE節點,會掛載在綁定的loop循環中的handle_queue隊列上;u是一個聯合體,表示句柄綁定的真實的資源索引(真實的句柄或者描述符),但是我們知道,libuv抽象出來的句柄並不一定都有真實的物理資源對應,比如定時器句柄就不沒有一個對應的描述符,因此此時可以使用reserved來占位;next_closing用來將要被關閉的句柄串接成單向鏈表,該鏈表會掛載在綁定的loop上的closing_handles指針上。flags,表示該句柄的狀態,可以為UV_CLOSING、UV_CLOSED、UV_STREAM_READING、UV_STREAM_SHUTTING、UV_STREAM_SHUT、UV_STREAM_READABLE、UV_STREAM_WRITABLE、UV_STREAM_BLOCKING、UV_STREAM_READ_PARTIAL、UV_STREAM_READ_EOF、UV_TCP_NODELAY、UV_TCP_KEEPALIVE、UV_TCP_SINGLE_ACCEPT、UV_HANDLE_IPV6、UV_UDP_PROCESSING。

     至此,所有句柄的抽象基類基本上說清楚了,所以其他類型的句柄都是這個基類的直接或者間接子類,那么libuv都定義了哪些句柄類型呢?在uv.h中,可以看到如下定義:

 1 /* Handle types. */
 2 typedef struct uv_loop_s uv_loop_t;
 3 typedef struct uv_handle_s uv_handle_t;
 4 typedef struct uv_stream_s uv_stream_t;
 5 typedef struct uv_tcp_s uv_tcp_t;
 6 typedef struct uv_udp_s uv_udp_t;
 7 typedef struct uv_pipe_s uv_pipe_t;
 8 typedef struct uv_tty_s uv_tty_t;
 9 typedef struct uv_poll_s uv_poll_t;
10 typedef struct uv_timer_s uv_timer_t;
11 typedef struct uv_prepare_s uv_prepare_t;
12 typedef struct uv_check_s uv_check_t;
13 typedef struct uv_idle_s uv_idle_t;
14 typedef struct uv_async_s uv_async_t;
15 typedef struct uv_process_s uv_process_t;
16 typedef struct uv_fs_event_s uv_fs_event_t;
17 typedef struct uv_fs_poll_s uv_fs_poll_t;
18 typedef struct uv_signal_s uv_signal_t;

      句柄的類型大概上分為兩種:普通句柄和流句柄,普通的句柄就類似於信號、文件、定時器等,流式句柄比如代表一個tcp連接、pipe連接以及控制台連接等。為了表達清楚他們之間的關系,我現在以圖示的形式畫了一張偽UML圖。 

 

 

    

   

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM