VConnection
代码中的描述: 一个提供IO功能的类, 是所有connection类的基类. VConnection类是一个单向或双向数据管道的一个抽象表示, 由Processor返回. 从某种意义上来说, VConnection起到和文件描述符相同的目的. VConnection是一个定义了执行IO方法的基类, 同时VConnection也是一个可以让Processor回调的Continuation
/* 通过VConnection读取数据, 状态机调用这个函数来读取数据, 实现读取功能时需要取出锁, 把数据放到buf中, 在释放锁之前回调continuation以便状态机处理转移方案 在回调continuation时, VConnection会使用如下的事件码: VC_EVENT_READ_READY 数据已经放到了buf中或者这个buf已经满了 VC_EVENT_READ_COMPLETE 由nbytes标示的需要读取的数据总数已经全部读到buf中了 VC_EVENT_EOS 数据的读取通道已经被关闭 VC_EVENT_ERROR 数据在读取期间发生错误 continuation在实现回调函数时, 也需要考虑到如上列出的状态码来分别实现处理逻辑 @param c 用来回调的Continuation, 回调时需要携带事件码 @param nbytes 需要读取的数据总数, 如果不确定需要读取多少, 则必须设置为INT64_MAX @param buf 数据读取到的缓冲区 @return VIO 代表已被调度的IO操作, 参数buf会被设置到返回的VIO中成员变量buffer中, 以便被continuation使用 */ VIO *do_io_read(Continuation *c = NULL, int64_t nbytes = INT64_MAX, MIOBuffer *buf = 0) /* 写数据到这个VConnection中, 状态机调用下面这个方法来将数据写入到这个VConnection中 在回调continuation时, VConnection会使用如下的事件码: VC_EVENT_WRITE_READY 数据已经写入VConnection或者没有更多的空间可以被写入? VC_EVENT_WRITE_COMPLETE 由nbytes标示的数据总数已经全部写入到VConnection VC_EVENT_INACTIVITY_TIMEOUT 一段时间内这个VConnection没有没有任何的动静 VC_EVENT_ACTIVE_TIMEOUT 写操作超过了一个时间限制 VC_EVENT_ERROR 写期间发生错误 @param c 用来回调的Continuation, VConnection需要携带事件码来回调 @param nbytes 写入数据的总数, 如果不确定是多少, 则必须设置为INT64_MAX @param buf 写入数据的来源 @return VIO 代表已被调度的IO操作 */ VIO *do_io_write(Continuation *c=NULL,int64_t nbytes=INT64_MAX, IOBufferReader *buf=0) /* 标识VConnection已经不再被使用 当状态机已经结束了对VConnection的使用, 那么它必须调用这个函数来标识这个VConnection可以被回收. 在close操作被调用之后, VConnection不可以再发送任何与VConnection相关的事件给状态机. 同样的, 调用这个方法后, 状态机也不允许再访问它包含的VConnection或任何VIO @param lerrno 指示close操作是一个正常的关闭还是异常的关闭, 正常或异常的区别取决于子类的具体实现 */ void do_io_close(int lerrno = -1) /* 结束VConnection的单向或双向上的数据通道 此方法被调用之后, 结束的方向上不允许再有任何I/O操作, VConnection不允许再给状态机发送任何事件, 状态机也不允许再使用关闭方向上的VIO. 即使VConnection的两个方向都被关闭,状态机依然可以调用do_io_close来回收这个VConnection 参数howto的取值: IO_SHUTDOWN_READ 表示这个VConnection不可以再产生任何和读有关的事件给状态机 IO_SHUTDOWN_WRITE 表示这个VConnection不可以再产生任何和写有关的事件给状态机 IO_SHUTDOWN_READWRITE 表示这个VConnection不可以再产生任何读/写的事件给状态机 */ void do_io_shutdown(ShutdownHowTo_t howto) /* 让一个IO操作继续, 一般在程序中是通过VIO::reenable()这个接口来调用这个方法. UnixNetVConnection这个类的reenable()的实现逻辑就是将连接描述符再次加入到epoll调度集合中去调度 */ void reenable(VIO *vio)
VIO
代码中的描述: VIO是一个IO操作的描述符, 通过VConnection::do_io_read()或do_io_write()方法返回. TS中的状态机可以通过VIO来监控某个IO操作的进度,并当数据准备好时通过VIO来reenable这个IO操作. 实际上VConnection会把一些属性值记录在VIO中, 比如需要唤醒的状态机、读/写进度等
/*
指向VConnection的指针, 在reenable函数中会用到
*/
VConnection *vc_server
/*
用于回调的continuation, 表示对本VIO操作来讲, VConnection需要给哪个continuation发事件码
*/
Continuation * _cont
/*
本VIO操作需要完成的字节总数
*/
int64_t nbytes
/*
本VIO已经完成的字节数
*/
int64_t ndone
/*
本VIO的操作类型
*/
int op
/*
本VIO操作需要使用到的reader或writer
如果是写操作, 那么指向一个IOBufferReader, 表示VConnection内部会从这个IOBufferReader中读取数据然后做真正的写
如果是读操作, 那么指向一个MIOBuffer, 表示VConnection会将真正读取到的数据写入到MIObuffer中
*/
MIOBufferAccessor buffer
/*
指向状态机的mutex
*/
Ptr mutex
UnixNetVConnection
UnixNetVConnection是VConnection的一个子类,主要用来处理真正的socket连接, 类的定义中存在read和write两个包含VIO的成员变量. reenable()函数的实现就是将参数中指定的VIO对应的文件描述符再次放入epoll调度集合去调度.
一个典型的处理逻辑如下描述:
1. accept到请求的连接之后, 会创建一个新的HttpSM状态机, HttpSM会使用UnixNetVConnection来完成请求数据的读取.
2. HttpSM会调用UnixNetVConnection的do_io_read方法, 这个方法除了会设置一些VIO的成员之外, 还会将连接描述符添加到epoll调度集合中调度
3. epoll调度返回之后,连接描述符对应的UnixNetVConnection会做真正的read操作, 将数据写入到之前VIO指定的buf中, 然后唤醒HttpSM状态机往下走
4. HttpSM状态机会在state_read_client_request_header()函数中解析请求, 如果解析请求成功,则HttpSM继续后面的处理, 如果解析不成功(Header不完整), 则会调用VIO::reenable() -> UnixNetVConnection::reenable()函数,让UnixNetVConnection将连接描述符再次加入到epoll调度集合中调度