zoukankan      html  css  js  c++  java
  • 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图。 

        

       

  • 相关阅读:
    hdu 5119 Happy Matt Friends
    hdu 5128 The E-pang Palace
    hdu 5131 Song Jiang's rank list
    hdu 5135 Little Zu Chongzhi's Triangles
    hdu 5137 How Many Maos Does the Guanxi Worth
    hdu 5122 K.Bro Sorting
    Human Gene Functions
    Palindrome(最长公共子序列)
    A Simple problem
    Alignment ( 最长上升(下降)子序列 )
  • 原文地址:https://www.cnblogs.com/chenyangyao/p/libuv_handle.html
Copyright © 2011-2022 走看看