ngx_event_t:为添加到循环event事件使用的event事件结构体。
typedef struct ngx_event_s ngx_event_t;结构体声明所在位置ngx_core.h。
ngx_event_s结构体所在位置ngx_event.h。
struct ngx_event_s {
// 事件上下文数据,通常data都是指向ngx_connection_t连接对象。
void *data;
// 表示对应的TCP连接可写,连接处于可以发送的状态。
unsigned write:1;
// 表示为此事件可以建立新的连接。通常在ngx_cycle_t中的listening动态数组中,
// 每一个监听对象ngx_listening_t,对应的读事件中的accept标志位才会是1。
unsigned accept:1;
// 用于检测kqueue、rtsig和epoll中的过时事件
unsigned instance:1;
// 标志位,为1表示当前事件是活跃的,为0表示事件是不活跃的
// the event was passed or would be passed to a kernel;
// in aio mode - operation was posted.
/* if (!rev->delayed) {
if (rev->active && !rev->ready) {
ngx_add_timer(rev, p->read_timeout);
} else if (rev->timer_set) {
ngx_del_timer(rev);
}
}
*/
unsigned active:1;
// 标志位表示禁用事件,仅在kqueue或者rtsig事件驱动模块中有效,对于epoll事件驱动模块则没有意义。
/*
例如在close_connection函数中
if (c->read->active || c->read->disabled) {
ngx_del_event(c->read, NGX_READ_EVENT, NGX_CLOSE_EVENT);
}
*/
unsigned disabled:1;
// 标志位表示当前事件准备就绪,允许这个事件的handler处理这个事件
/*
在HTTP框架中,经常会检查事件的ready标志位,以确定是否可以接收请求或者发送相应。
if (rev->ready) {
if (ngx_use_accept_mutex) {
ngx_post_event(rev, &ngx_posted_events);
return;
}
rev->handler(rev);
return;
}
*/
unsigned ready:1;
// 仅对kqueue,eventport等模块有意义 对于epoll事件驱动模块是无意义的
unsigned oneshot:1;
// 用于异步aio事件的处理
unsigned complete:1;
// eof表示当前处理的字符流已经结束,error表示事件处理过程出错了
// flags = (rev->eof || rev->error) ? NGX_CLOSE_EVENT : 0;
unsigned eof:1;
unsigned error:1;
// 表示这个事件超时,用以提示handler做超时处理,它与timer_set都用了定时器
/* if (wev->timedout) {
wev->timedout = 0;
ngx_http_perl_handle_request(r);
return;
}
*/
unsigned timedout:1;
// 表示这个事件存在于定时器中
unsigned timer_set:1;
// 表示需要延迟处理这个事件,它仅用于限速功能
unsigned delayed:1;
// 表示延迟建立TCP连接 三次握手后等到真正收到数据包后才建连
unsigned deferred_accept:1;
// 表示等待字符流结束 它只与kqueue和aio事件驱动机制有关
unsigned pending_eof:1;
unsigned posted:1;
#if (NGX_WIN32)
/* setsockopt(SO_UPDATE_ACCEPT_CONTEXT) was successful */
unsigned accept_context_updated:1;
#endif
#if (NGX_HAVE_KQUEUE)
unsigned kq_vnode:1;
/* the pending errno reported by kqueue */
int kq_errno;
#endif
/*
* 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
* read: bytes to read when event is ready, -1 if not known
*/
int available;
ngx_event_handler_pt handler;
ngx_event_handler_pt handler;
#if (NGX_HAVE_IOCP)
ngx_event_ovlp_t ovlp;
#endif
ngx_uint_t index;
ngx_log_t *log;
ngx_rbtree_node_t timer;
/* the posted queue */
ngx_queue_t queue;
#if 0
/* the threads support */
/*
* the event thread context, we store it here
* if $(CC) does not understand __thread declaration
* and pthread_getspecific() is too costly
*/
void *thr_ctx;
#if (NGX_EVENT_T_PADDING)
/* event should not cross cache line in SMP */
uint32_t padding[NGX_EVENT_T_PADDING];
#endif
#endif
};
void *data
:指向要传递给事件处理程序的数据的指针。通常这是一个指向
ngx_connection_t。
void (*ngx_event_handler_pt)(ngx_event_t *ev) handler:事件触发时调用的处理函数。
ngx_log_t * log:
指向事件要使用的日志对象的指针。
void ngx_add_timer
(ngx_event_t *ev, ngx_msec_t timer)
向nginx事件循环添加一个计时器。通常用于套接字上的超时,但也可以用作通用计时器。
void ngx_event_del_timer
(ngx_event_t *ev)
从nginx事件循环中移除计时器。
static ngx_event_t my_timer; static ngx_connection_t dumb_con; ngx_int_t ngx_my_init_process(ngx_cycle_t *cycle) { my_timer.handler = ngx_timer_fired; my_timer.log = cycle->log; my_timer.data = &dumb_con; dumb.fd = (ngx_socket_t) -1; } void ngx_timer_fired(ngx_event_t *ev) { ngx_log_error(NGX_LOG_DEBUG, ev->log, 0, "Event fired!"); }
例如在nginx处理请求头函数ngx_http_read_request_header()
static ssize_t
ngx_http_read_request_header(ngx_http_request_t *r)
{
ssize_t n;
ngx_event_t *rev;
ngx_connection_t *c;
ngx_http_core_srv_conf_t *cscf;
c = r->connection; // 当前请求对应的连接
rev = c->read; // 当前连接对应的读事件
n = r->header_in->last - r->header_in->pos;
// 若当前请求的接收缓冲区header_in中有未解析的数据,直接返回
if (n > 0) {
return n;
}
// 若当前读事件已就绪
if (rev->ready) {
// 循环调用recv()将内核套接字缓冲区中的数据复制到header_in中
n = c->recv(c, r->header_in->last,
r->header_in->end - r->header_in->last);
} else {
n = NGX_AGAIN;
}
if (n == NGX_AGAIN) {
if (!rev->timer_set) {
cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
// 将读事件加入到定时器中
ngx_add_timer(rev, cscf->client_header_timeout);
}
// 将读事件加入到epoll中
if (ngx_handle_read_event(rev, 0) != NGX_OK) {
ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
return NGX_ERROR;
}
return NGX_AGAIN;
}
// 若客户端关闭连接
if (n == 0) {
ngx_log_error(NGX_LOG_INFO, c->log, 0,
"client prematurely closed connection");
}
// 若客户端关闭连接或连接错误
if (n == 0 || n == NGX_ERROR) {
c->error = 1;
c->log->action = "reading client request headers";
ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
return NGX_ERROR;
}
r->header_in->last += n;
return n;
}