wifidog源码分析Lighttpd1.4.20源码分析之fdevent系统(3) -----使用(1)

栏目: 服务器 · 发布时间: 8年前

内容简介:wifidog源码分析Lighttpd1.4.20源码分析之fdevent系统(3) -----使用(1)

前面讲了lighttpd的fdevent系统的初始化过程。这篇要看一看lighttpd是怎样使用fdevent系统的。讲解的过程中,会详细的分析fdevent的源代码。首先还是从server.c的main函数入手。在程序的初始化过程中,当完成fdevent的初始化之后,第一个需要fdevent处理的事情就是将在初始化网络的过程中得到的监听fd(socket函数的返回值)注册的fdevent系统中。调用的是network_register_fdevents()函数,定义在network.c文件中:

/**
 * 在fd events系统中注册监听socket。
 * 这个函数在子进程中被调用。
 */
 int network_register_fdevents(server * srv)
{
	size_t i;
	if (-1 == fdevent_reset(srv->ev)){return -1;}
	/*
	 * register fdevents after reset
	 */
	for (i = 0; i < srv->srv_sockets.used; i++)
	{
		server_socket *srv_socket = srv->srv_sockets.ptr[i];
		fdevent_register(srv->ev, srv_socket->fd, network_server_handle_fdevent, srv_socket);
		fdevent_event_add(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd, FDEVENT_IN);
	}
	return 0;
}

函数的重点是for循环,它遍历所有的监听fd并将其注册到fdevent系统中。在初始化网络的过程中,调用socket函数之后,将其返回值(监听fd)保存在server结构体的srv_sockets成员中,这个成员是一个server_socket_array结构体,而server_socket_array结构体是server_socket结构体的指针数组。server_socket结构体定义如下:

typedef struct
{
        sock_addr addr;           //socket fd对应的的地址。
         int fd;                     //socket()函数返回的监听fd
         int fde_ndx;                 //和fd相同。
         buffer *ssl_pemfile;
        buffer *ssl_ca_file;
        buffer *ssl_cipher_list;
        unsigned short ssl_use_sslv2;
        unsigned short use_ipv6;    //标记是否使用ipv6
         unsigned short is_ssl;
        buffer *srv_token;
#ifdef USE_OPENSSL
        SSL_CTX *ssl_ctx;
 #endif
        unsigned short is_proxy_ssl;
} server_socket;

这里我们主要看前三个成员,前两个成员很简单,对于第三个成员,作者的本意应该是保存fd对应的fdnode在fdevents结构体中fdarray数组中的下标,但是程序在存储fdnode时候是以fd最为下标存储的(后面的fdevent_register函数中),所以通常fde_ndx==fd。下面看一看fdevent_register()函数,在fdevent.c中定义:

int fdevent_register(fdevents * ev, int fd, fdevent_handler handler, void *ctx)
{
	fdnode *fdn;
	fdn = fdnode_init();
	fdn->handler = handler;
	fdn->fd = fd;
	fdn->ctx = ctx;
	ev->fdarray[fd] = fdn; //使用文件描述符作为数组的下标。可以将查询
 //的时间变为 O(1)
	 return 0;
}

在这个函数中,创建了一个fdnode结构体的实例,然后对其成员赋值。最后,以fd为下标将这个实例存如fdevents结构体中的fdarray数组中。关于第三个参数:fdevent_handler handler,这是一个函数指针,其定义为typedef handler_t(*fdevent_handler) (void *srv, void *ctx, int revents)。这个函数指针对应XXX_handle_fdevent()类型的函数。比如network.c/ network_server_handle_fdevent() ,connections.c/ connection_handle_fdevent()。这些函数的作用是在fdevent系统检测到fd有IO事件发生时,处理这些IO事件。比如,network_server_handle_fdevent()处理监听fd(socket函数的返回值)发生的IO事件,connection_handle_fdevent()处理连接fd(accept函数的返回值)发生的IO事件。除了上面的两个函数,还有stat_cacahe.c/stat_cache_handle_fdevent(),mod_cgi.c/cgi_handle_fdevent(),mod_fastcgi.c/ fcgi_handle_fdevent(),mod_proxy.c/ proxy_handle_fdevent()和mod_scgi.c/scgi_handle_fdevent()等。在后面的讲解中,主要围绕network_server_handle_fdevent()和connection_handle_fdevent(),其他的函数有兴趣的读者可以自行查看。接着,在for循环中调用(fdevent.c)fdevent_event_add()函数:

int fdevent_event_add(fdevents * ev, int *fde_ndx, int fd, int events)
{
	int fde = fde_ndx ? *fde_ndx : -1;
	if (ev->event_add)
		fde = ev->event_add(ev, fde, fd, events)
	if (fde_ndx)
		*fde_ndx = fde;
	return 0;
}

函数中调用了fdevents结构体中event_add函数指针对应的函数。前面我们已经假设系统使用epoll,那么我们就去看看fdevent_linux_sysepoll.c中的fdevent_linux_sysepoll_event_add()函数,这个函数的地址在初始化的时候被赋给fdevents中的event_add指针:

static int fdevent_linux_sysepoll_event_add(fdevents * ev, int fde_ndx, int fd, int events)
{
    struct epoll_event ep;
    int add = 0;
    if (fde_ndx == -1) //描述符不在epoll的检测中,增加之。
         add = 1;
    memset(&ep, 0, sizeof(ep));
    ep.events = 0;
    /**
     * 在ep中设置需要监听的IO事件。
     * EPOLLIN : 描述符可读。
     * EPOLLOUT :描述符可写。
     * 其他的事件还有:EPOLLRDHUP , EPOLLPRI, EPOLLERR, EPOLLHUP, EPOLLET, EPOLLONESHOT等。
     */
    if (events & FDEVENT_IN)
        ep.events |= EPOLLIN;
    if (events & FDEVENT_OUT)
        ep.events |= EPOLLOUT;
    /*
     * EPOLLERR :描述符发生错误。
     * EPOLLHUP :描述符被挂断。通常是连接断开。
     */
    ep.events |= EPOLLERR | EPOLLHUP /* | EPOLLET */ ;
    ep.data.ptr = NULL;
    ep.data.fd = fd;
    /*
     * EPOLL_CTL_ADD : 增加描述符fd到ev->epoll_fd中,并关联ep中的事件到fd上。
     * EPOLL_CTL_MOD : 修改fd所关联的事件。
     */
    if (0 != epoll_ctl(ev->epoll_fd, add ?EPOLL_CTL_ADD : EPOLL_CTL_MOD, fd, &ep))
    {
        fprintf(stderr, "%s.%d: epoll_ctl failed: %s, dying\n",__FILE__,__LINE__, strerror(errno));
        SEGFAULT();
        return 0;
    }
    return fd;
}

本文章由 http://www.wifidog.pro/2015/04/21/wifidog%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90lighttpd%E4%BD%BF%E7%94%A8-1.html 整理编辑,转载请注明出处


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Joy of X

The Joy of X

Niall Mansfield / UIT Cambridge Ltd. / 2010-7-1 / USD 14.95

Aimed at those new to the system seeking an overall understanding first, and written in a clear, uncomplicated style, this reprint of the much-cited 1993 classic describes the standard windowing syste......一起来看看 《The Joy of X》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

MD5 加密
MD5 加密

MD5 加密工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具