Nginx学习之路(九)Nginx中的事件驱动过程详解-----connection事件的注册过程

在上一篇文章Nginx学习之路(八)Nginx中的事件驱动过程详解-----以listenfd注册过程为例中举了listenfd的注册过程来说明事件驱动中的事件注册过程,这是一个简单的过程,今天来说明下当浏览器发起一个http请求时,nginx是如何将这个事件注册到epoll中并处理的:

还记得上一篇文件说明了注册listenfd时,传入参数中的那个rev吧,今天再来详细的说明一下这个rev,在上篇文章中我们提到了rev中最关键的地方就是它的handler,这个handler的作用就是当一个event触发的时候,就会去调用这个handler上注册的回调函数,那么rev上注册的函数是什么呢?看看下面:

 rev->handler = ngx_event_accept;

也就是说,当listenfd就绪的时候,也就是有browser发起tcp请求并完成3次握手后,在listen()的连接队列里了,这时,就会调用ngx_event_accept函数,我们来看看这个函数,这个函数很长,我删除一些不重要的部分,只给个缩略班:

void
ngx_event_accept(ngx_event_t *ev)
{
    
//处理定时器超时,关于定时器的问题后面会细讲
    if (ev->timedout) {
        if (ngx_enable_accept_events((ngx_cycle_t *) ngx_cycle) != NGX_OK) {
            return;
        }

        ev->timedout = 0;
    }

  
    lc = ev->data;
    ls = lc->listening;
    ev->ready = 0;
//关键函数,将listen()就绪队列里的fd,accept出来
    s = accept(lc->fd, (struct sockaddr *) sa, &socklen);

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

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

            level = NGX_LOG_ALERT;

            if (err == NGX_ECONNABORTED) {
                level = NGX_LOG_ERR;

            } else if (err == NGX_EMFILE || err == NGX_ENFILE) {
                level = NGX_LOG_CRIT;
            }


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

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

        

//简单的负载均衡,之前有讲到过
        ngx_accept_disabled = ngx_cycle->connection_n / 8
                              - ngx_cycle->free_connection_n;
//从连接池里获取连接
        c = ngx_get_connection(s, ev->log);
//分配内存池

        c->pool = ngx_create_pool(ls->pool_size, ev->log);
        if (c->pool == NULL) {
            ngx_close_accepted_connection(c);
            return;
        }

//设置IO复用非阻塞   

        if (ngx_inherited_nonblocking) {
            if (ngx_event_flags & NGX_USE_AIO_EVENT) {
                if (ngx_blocking(s) == -1) {
                    ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
                                  ngx_blocking_n " failed");
                    ngx_close_accepted_connection(c);
                    return;
                }
            }

        } else {
            if (!(ngx_event_flags & (NGX_USE_AIO_EVENT|NGX_USE_RTSIG_EVENT))) {
                if (ngx_nonblocking(s) == -1) {
                    ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
                                  ngx_nonblocking_n " failed");
                    ngx_close_accepted_connection(c);
                    return;
                }
            }
        }

        *log = ls->log;
//连接的参数
        c->recv = ngx_recv;
        c->send = ngx_send;
        c->recv_chain = ngx_recv_chain;
        c->send_chain = ngx_send_chain;

        c->log = log;
        c->pool->log = log;

        c->socklen = socklen;
        c->listening = ls;
        c->local_sockaddr = ls->sockaddr;
        c->local_socklen = ls->socklen;

        c->unexpected_eof = 1;

//关键的部分来了,设置连接的读写事件,读事件就是browser有请求来,accept下来的connfd就绪了,调用的事件,写事件就是nginx这边把数据处理好,要发送给browser时调用的事件
        rev = c->read;
        wev = c->write;

        wev->ready = 1;

        if (ngx_event_flags & (NGX_USE_AIO_EVENT|NGX_USE_RTSIG_EVENT)) {
            /* rtsig, aio, iocp */
            rev->ready = 1;
        }

        if (ev->deferred_accept) {
            rev->ready = 1;
#if (NGX_HAVE_KQUEUE)
            rev->available = 1;
#endif
        }

        rev->log = log;
        wev->log = log;
        
        c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1);

.
.   
.


//关键的又来了,把这个连接注册到epoll中去,就完成了监听
        if (ngx_add_conn && (ngx_event_flags & NGX_USE_EPOLL_EVENT) == 0) {
            if (ngx_add_conn(c) == NGX_ERROR) {
                ngx_close_accepted_connection(c);
                return;
            }
        }      
      


    } while (ev->available);
}

这个函数完成的主要功能如下:accept一个连接,调用ngx_add_conn(这个回调的本身是ngx_epoll_module.c中的ngx_epoll_add_connection(ngx_connection_t *c))把连接注册到epoll中去,其余还做了一些负载均衡,filter等操作,这里先不关心它。至此,一起browser端的请求注册到epoll中过程就完成了

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Kubernetes Ingress-Nginx是一个在Kubernetes集群使用的开源Ingress控制器。它允许将外部流量引导到Kubernetes集群内部的服务。下面是它的一些主要特点和详解: 1. 灵活性:Ingress-Nginx支持多种配置方式,包括基于注解的配置、自定义资源定义(CRD)以及基于配置文件的方式。这使得用户可以根据自己的需求选择最适合的方式来配置Ingress规则。 2. 可扩展性:Ingress-Nginx可以通过水平扩展来处理高负载的流量。它使用Nginx作为反向代理服务器,可以根据需要进行水平扩展,并通过负载均衡来分发请求。 3. SSL/TLS支持:Ingress-Nginx支持通过TLS/SSL来保护传输的数据。它可以配置证书和私钥,从而实现安全的通信。 4. 负载均衡:Ingress-Nginx可以根据不同的负载均衡算法来分发流量。它支持轮询、IP哈希、最少连接等负载均衡算法,并且可以根据需要进行自定义配置。 5. 基于名称的虚拟主机:Ingress-Nginx支持基于名称的虚拟主机(Virtual Host)。通过配置不同的主机名和路径规则,可以将流量引导到不同的服务。 6. HTTP/HTTPS重定向:Ingress-Nginx可以配置HTTP到HTTPS的重定向,从而确保所有的流量都是通过安全的通道传输。 7. 基于URI的请求路由:Ingress-Nginx可以根据请求的URI来进行路由。这使得可以根据不同的URI将流量引导到不同的后端服务。 8. 支持WebSocket:Ingress-Nginx对WebSocket协议有良好的支持。它可以转发WebSocket请求,并在需要时进行负载均衡。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值