nginx中的事件模块是一个很重要的模块,但这里作为初读,我们只简单看一下ngx_event的数据结构,至于模块和机制,留作之后再分析。
下面是结构体ngx_event_t的代码:
<span>typedef</span><span>struct</span> ngx_event_s ngx_event_t;
<span>struct</span> ngx_event_s {
<span>void</span> *data;
<span>/* 事件上下文数据,通常data都是指向ngx_connection_t连接对象。
* 开启文件异步I/O时,它可能会指向ngx_event_aio_t结构体。
* ... ngx_int_t ngx_handle_write_event(ngx_event_t *wev, size_t lowat) {
ngx_connection_t *c;
if (lowat) {
c = wev->data; // 在这里event的data就指向了connection_t,直接用指针获取
if (ngx_send_lowat(c, lowat) == NGX_ERROR) {
return NGX_ERROR;
}
}...} ...
unsigned write:1;
/* 标志位,为1时表示事件是可写的。通常它表示对应的TCP连接可写,也就是连接处于可以发送网络包的状态。*/</span><span>unsigned</span> accept:<span>1</span>;
<span>/* 标志位,为1时表示为此事件可以建立新的连接。通常在ngx_cycle_t中的listening动态数组中,
每一个监听对象ngx_listening_t,对应的读事件中的accept标志位才会是1。*/</span><span>unsigned</span> instance:<span>1</span>;
<span>/* used to detect the stale events in kqueue, rtsig, and epoll
* 这个标志位用于区分当前事件是否过期,它仅仅是给事件驱动模块使用的,而事件消费模块可不用关心。
* 为什么需要这个标志位呢?当开始处理一批事件时,处理前面的事件可能会关闭一些连接,
而这些连接有可能影响这批事件中还未处理到的后面的事件,这时可通过instance来避免处理后面的过期事件。
*/</span><span>unsigned</span> active:<span>1</span>;
<span>/* the event was passed or would be passed to a kernel;
* in aio mode - operation was posted.
* 标志位,为1表示当前事件是活跃的,为0表示事件是不活跃的。
* 这个状态对应着事件驱动模块处理方式的不同。例如,在添加事件,删除事件和处理事件时,
active标志位的不同都会对应着不同的处理方式。在使用事件时,一般不会直接改变active标志位。
* ... if (!rev->delayed) {
if (rev->active && !rev->ready) {
ngx_add_timer(rev, p->read_timeout);
} else if (rev->timer_set) {
ngx_del_timer(rev);
}
} ...
*/</span><span>unsigned</span> disabled:<span>1</span>;
<span>/* 标志位,为1表示禁用事件,仅在kqueue或者rtsig事件驱动模块中有效,对于epoll事件驱动模块则没有意义。
* ... if (c->read->active || c->read->disabled) {
ngx_del_event(c->read, NGX_READ_EVENT, NGX_CLOSE_EVENT);
} ... // 位于close_connection函数中
*/</span> /
<span>unsigned</span> ready:<span>1</span>;
<span>/* the ready event; in aio mode 0 means that no operation can be posted
* 标志位,为1表示当前事件准备就绪,也就是说,允许这个事件的handler处理这个事件。
* 在HTTP框架中,经常会检查事件的ready标志位,以确定是否可以接收请求或者发送相应。
* ... if (rev->ready) {
if (ngx_use_accept_mutex) {
ngx_post_event(rev, &ngx_posted_events);
return;
}
rev->handler(rev);
return;
} ...
*/</span><span>unsigned</span> oneshot:<span>1</span>;
<span>/* 该标志位仅对kqueue,eventport等模块有意义,而对于linux上的epoll事件驱动模块则是无意义的。*/</span><span>unsigned</span> complete:<span>1</span>;
<span>/* aio operation is complete
* 用于异步aio事件的处理 */</span><span>unsigned</span> eof:<span>1</span>;
<span>unsigned</span> error:<span>1</span>;
<span>/* 标志位,eof表示当前处理的字符流已经结束,error表示事件处理过程出错了。
* ... flags = (rev->eof || rev->error) ? NGX_CLOSE_EVENT : 0; ...
*/</span><span>unsigned</span> timedout:<span>1</span>;
<span>/* 标志位,为1表示这个事件超时,用以提示handler做超时处理,它与timer_set都用了定时器
* ... if (wev->timedout) {
wev->timedout = 0;
ngx_http_perl_handle_request(r);
return;
} ...
*/</span><span>unsigned</span> timer_set:<span>1</span>;
<span>/* 标志位,为1表示这个事件存在于定时器中
* ... if (!ngx_cleaner_event.timer_set) {
ngx_add_timer(&ngx_cleaner_event, 30000);
ngx_cleaner_event.timer_set = 1;
} ...
*/</span><span>unsigned</span> delayed:<span>1</span>;
<span>/* 标志位,delayed为1表示需要延迟处理这个事件,它仅用于限速功能 */</span><span>unsigned</span> deferred_accept:<span>1</span>;
<span>/* 标志位,为1表示延迟建立TCP连接,也就是TCP三次握手后并不建立连接,而是等到真正收到数据包后才建连接 */</span><span>unsigned</span> pending_eof:<span>1</span>;
<span>/* the pending eof reported by kqueue, epoll or in aio chain operation
* 标志位,为1表示等待字符流结束,它只与kqueue和aio事件驱动机制有关 */</span><span>unsigned</span> posted:<span>1</span>;
<span>#if (NGX_WIN32)</span><span>/* setsockopt(SO_UPDATE_ACCEPT_CONTEXT) was successful */</span><span>unsigned</span> accept_context_updated:<span>1</span>;
<span>#endif</span><span>// 下面这部分都是因不同事件管理机制而不同的,先不看了</span><span>#if (NGX_HAVE_KQUEUE)</span><span>unsigned</span> kq_vnode:<span>1</span>;
<span>/* the pending errno reported by kqueue */</span><span>int</span> kq_errno;
<span>#endif</span><span>/*
* kqueue only:
* accept: number of sockets that wait to be accepted
* read: bytes to read when event is ready
* or lowat when event is set with NGX_LOWAT_EVENT flag
* write: available space in buffer when event is ready
* or lowat when event is set with NGX_LOWAT_EVENT flag
*
* iocp: TODO
*
* otherwise:
* accept: 1 if accept many, 0 otherwise
*/</span><span>#if (NGX_HAVE_KQUEUE) || (NGX_HAVE_IOCP)</span><span>int</span> available;
<span>#else</span><span>unsigned</span> available:<span>1</span>;
<span>#endif</span> ngx_event_handler_pt handler;
<span>/* 这个事件发生时的处理方法,每个事件处理模块都会重新实现它 */</span><span>#if (NGX_HAVE_AIO)</span><span>// win下的一种事件驱动模型</span><span>#if (NGX_HAVE_IOCP) </span>
ngx_event_ovlp_t ovlp;
<span>#else </span><span>// 在linux中定义的aio结构体 </span><span>struct</span> aiocb aiocb;
<span>#endif</span><span>#endif</span> ngx_uint_t index;
<span>/* epoll 事件驱动方式不使用index */</span> ngx_log_t *<span>log</span>;
<span>/* 记录当前event的log对象 */</span> ngx_rbtree_node_t timer;
<span>/* 定时器节点,用于定时器红黑树中 */</span><span>/* the posted queue */</span>
ngx_queue_t <span>queue</span>;
<span>unsigned</span> closed:<span>1</span>;
<span>/* to test on worker exit */</span><span>unsigned</span> channel:<span>1</span>;
<span>unsigned</span> resolver:<span>1</span>;
<span>unsigned</span> cancelable:<span>1</span>;
<span>#if 0</span><span>/* the threads support */</span><span>/*
* the event thread context, we store it here
* if $(CC) does not understand __thread declaration
* and pthread_getspecific() is too costly
*/</span><span>void</span> *thr_ctx;
<span>#if (NGX_EVENT_T_PADDING)</span><span>/* event should not cross cache line in SMP */</span> uint32_t padding[NGX_EVENT_T_PADDING];
<span>#endif</span><span>#endif</span>
}; 我们再看一下event.h里一个数据结构:
<span>typedef</span><span>struct</span> {
ngx_int_t (*add)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);
ngx_int_t (*del)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);
<span>/* 添加/移出事件方法,负责把事件添加/移出到操作系统提供的事件驱动机制(如epoll,kqueue等)中,
这样在事件发生之后,将可以/无法调用下面的process_envets时获取这个事件。*/</span> ngx_int_t (*enable)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);
ngx_int_t (*disable)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);
<span>/* 启用/禁用一个事件,目前事件框架不会调用,大部分事件驱动模块对该方法的实现都与add/del完全一致 */</span> ngx_int_t (*add_conn)(ngx_connection_t *c);
ngx_int_t (*del_conn)(ngx_connection_t *c, ngx_uint_t flags);
<span>/* 向事件驱动机制中添加/移除一个新的连接,这意味着连接上的读写事件都添加到/移出事件驱动机制中了 */</span> ngx_int_t (*process_events)(ngx_cycle_t *cycle, ngx_msec_t timer,
ngx_uint_t flags);
<span>/* 在正常的工作循环中,将通过调用process_events方法来处理事件。
* 这个方法仅在ngx_process_events_and_timers方法中调用,它是处理分发事件的核心。*/</span> ngx_int_t (*init)(ngx_cycle_t *cycle, ngx_msec_t timer);
<span>void</span> (*done)(ngx_cycle_t *cycle);
<span>/* 初始化和退出事件驱动模块的方法 */</span>
} ngx_event_actions_t;
<span>extern</span> ngx_event_actions_t ngx_event_actions;作为nginx中比较重要的一个驱动,event当然是很复杂的,第一遍看反正怎么也不容易懂,后续刨析了nginx的各种机制和流程应该就很容易懂了,先放过它,继续往下看。
贴个链接:https://segmentfault.com/a/1190000002715203
').addClass('pre-numbering').hide(); $(this).addClass('has-numbering').parent().append($numbering); for (i = 1; i ').text(i)); }; $numbering.fadeIn(1700); }); });以上就介绍了nginx源码初读(8)--让烦恼从main开始ngx_event,包括了方面的内容,希望对PHP教程有兴趣的朋友有所帮助。
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号