上一篇我们探讨了lighttpd对监听socket的处理,这次我们看看连接socket的处理,以及相关超时的处理。
lighttpd和客户端建立连接的过程:
1.lighttpd检测监听socket的IO事件,如果有可读事件发生,那么表示有新的连接请求,于是调用network.c/network_server_handle_fdevent()来处理连接请求。
2.network_server_handle_fdevent()函数调用connections.c/connection_accept() 接受客户端的请求,建立连接,得到连接socket的fd,也就是accept函数的返回值。
3.建立连接后,这个连接对应的状态机状态被设置为CON_STATE_REQUEST_START,即开始读取客户端发过来的request。
4.从connection_accept函数返回到network_server_handle_fdevent()函数的for循环中后,程序调用connection_state_machine()函数,这个函数是根据当前连接的状态机状态来设置状态机的下一个状态,CON_STATE_REQUEST_START的下一个状态是CON_STATE_READ,这个状态表示连接正在读取客户端发送的数据。
5.当连接的状态机被设置成CON_STATE_READ后,在connection_state_machine()函数中有这样一个switch语句:
switch (con->state)
{
case CON_STATE_READ_POST:
case CON_STATE_READ:
case CON_STATE_CLOSE:
fdevent_event_add(srv->ev, &(con->fde_ndx), con->fd, FDEVENT_IN);
break;
case CON_STATE_WRITE:
/*
* request write-fdevent only if we really need it
* - if we have data to write
* - if the socket is not writable yet
*/
if (!chunkqueue_is_empty(con->write_queue) && (con->is_writable == 0) &&(con->traffic_limit_reached == 0))
{
fdevent_event_add(srv->ev, &(con->fde_ndx), con->fd, FDEVENT_OUT);
}
else
{
fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd);
}
break;
default:
fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd);
break;
}
它将状态处在CON_STATE_READ_POST,CON_STATE_READ和CON_STATE_CLOSE的连接对应的连接socket fd加入到fdevent系统中,并监听【可读】事件。将处CON_STATE_WRITE状态且有数据要写的连接对应的socket fd加入到fdevent系统中,并监听【可写】事件。其他状态的连接则把对应的fd从fdevent系统中删除,因为这些连接不会有IO事件发生。
这样,连接socket fd就被加入到了fdevent系统中,之后等待IO事件的发生,这一部分在上一篇已经说明过了:
//启动事件轮询。底层使用的是IO多路转接。
if ((n = fdevent_poll(srv->ev, 1000)) > 0)
{
/* n是事件的数量 */
int revents;
int fd_ndx = -1;
/* 逐个处理已经准备好的请求,直到所有的请求处理结束 */
do
{
fdevent_handler handler;
void *context;
handler_t r;
fd_ndx = fdevent_event_next_fdndx(srv->ev, fd_ndx); //获得发生了 I/O 事件的文件描述符在 fdarray 中的索引
revents = fdevent_event_get_revent(srv->ev, fd_ndx); //获得该文件描述符上发生的 I/O 事件类型
fd = fdevent_event_get_fd(srv->ev, fd_ndx); //获得该文件描述符
handler = fdevent_get_handler(srv->ev, fd); //获得 I/O 事件处理的回调函数
context = fdevent_get_context(srv->ev, fd); //获得 I/O 事件处理的上下文环境
/*
* connection_handle_fdevent needs a joblist_append
*/
/**
* 调用回调函数进行I/O事件处理,并传入相关参数
*/
switch (r = (*handler) (srv, context, rev