nginx源码阅读(十三).新建连接并处理就绪事件

前言

本小节主要讨论事件模块中如何接受新连接,其中涉及到了惊群以及负载均衡的处理。

如何建立新连接

之前在分析ngx_event_process_init函数时,将所有空闲连接形成链表之后,它会遍历所有监听端口并将其读事件的回调函数设置为ngx_event_accept

接着会把监听连接的读事件添加到ngx_epoll_module模块中。当执行ngx_epoll_process_events时,如果有新连接事件出现,则会调用ngx_event_accept来建立新的连接。

建立新连接的回调函数

建立新连接的回调函数是ngx_event_accept,每个监听连接的读事件的handler都在ngx_event_process_init中设置为ngx_event_accept
下面直接看它的源码(省略了不必要的部分):

void
ngx_event_accept(ngx_event_t *ev)
{
    socklen_t          socklen;
    ngx_err_t          err;
    ngx_log_t         *log;
    ngx_socket_t       s;
    ngx_event_t       *rev, *wev;
    ngx_listening_t   *ls;
    ngx_connection_t  *c, *lc;
    ngx_event_conf_t  *ecf;
    u_char             sa[NGX_SOCKADDRLEN];
    ......

    //获取ngx_event_core_module模块的配置项结构体指针
    ecf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_event_core_module);

    if (ngx_event_flags & NGX_USE_RTSIG_EVENT) {
        ev->available = 1;

    } else if (!(ngx_event_flags & NGX_USE_KQUEUE_EVENT)) {
        ev->available = ecf->multi_accept;
    }

    lc = ev->data;
    ls = lc->listening;
    ev->ready = 0;

    ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
                   "accept on %V, ready: %d", &ls->addr_text, ev->available);

    /* 这个循环以available标志位作为判断条件
     * 当该标志位被置1,则代表每次尽可能的多建立新连接
     * 否则每次调用ngx_event_accept只建立一个新连接
     */
    do {           
        socklen = NGX_SOCKADDRLEN;
        ......
        //调用accept接受新连接
        s = accept(lc->fd, (struct sockaddr *) sa, &socklen);


        if (s == -1) {
            err = ngx_socket_errno;

            if (err == NGX_EAGAIN) {
                ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, err,
                               "accept() not ready");
                return;
            }


            ngx_log_error((ngx_uint_t) ((err == NGX_ECONNABORTED) ?
                                             NGX_LOG_ERR : NGX_LOG_ALERT),
                          ev->log, err, "accept() failed");

            if (err == NGX_ECONNABORTED) {
                if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
                    ev->available--;
                }

                if (ev->available) {
                    continue;
                }
            }

            return;
        }
        .....

        /* 这一步操作是设置负载均衡的阀值
         * ngx_accept_disabled的初值是负数,为总连接的7/8
         * 当ngx_accept_disabled为负数时,
         * 则不会触发负载均衡的操作
         * 当ngx_accept_disabled是正数时,就会触发负载均衡的操作了(当前进程不会处理新连接,而是将ngx_accept_disabled减1)
         */
        ngx_accept_disabled =  ngx_cycle->connection_n / 8
                              - ngx_cycle->free_connection_n;

        //获取一个空闲连接
        c = ngx_get_connection(s, ev->log);

        if (c == NULL) {
            if (ngx_close_socket(s) == -1) {
                ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
                              ngx
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值