当前位置: 首页 > 工具软件 > ngx_cc > 使用案例 >

nginx ngx_event_t结构体详解

叶越
2023-12-01

结构体

Event Handling | NGINX

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 *evngx_msec_t timer)

向nginx事件循环添加一个计时器。通常用于套接字上的超时,但也可以用作通用计时器。

  • ev – 产生超时的事件对象。
  • timer – 以毫秒为单位的超时时间。

void ngx_event_del_timer(ngx_event_t *ev)

从nginx事件循环中移除计时器。

  • ev - 计时器是一个的事件对象
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;
}

 类似资料: