ngx_connection

上一节说了ngx_event 对于底层事件封装,这节来看下ngx_connection
先来看下ngx_connection结构体

struct ngx_connection_s {
    void               *data;//关联的模型 在空闲链表的时候是next 比如在http的时候就是http_request
    ngx_event_t        *read;//读取事件
    ngx_event_t        *write;//写事件

    ngx_socket_t        fd; //fd

    ngx_recv_pt         recv;//读方法
    ngx_send_pt         send;//写方法
    ngx_recv_chain_pt   recv_chain;//读链方法
    ngx_send_chain_pt   send_chain;//写链方法

    ngx_listening_t    *listening;//listen

    off_t               sent;//用于设置该连接已发送或者已接收数据的数量

    ngx_log_t          *log;//写日志的

    ngx_pool_t         *pool;//内存池

    struct sockaddr    *sockaddr;//客户端的sockaddr
    socklen_t           socklen;
    ngx_str_t           addr_text;

    ngx_str_t           proxy_protocol_addr;

#if (NGX_SSL)
    ngx_ssl_connection_t  *ssl;
#endif

    struct sockaddr    *local_sockaddr;
    socklen_t           local_socklen;

    ngx_buf_t          *buffer;//buffer

    ngx_queue_t         queue;//队列 主要用在reuseable_connection_queue那

    ngx_atomic_uint_t   number;//使用次数

    ngx_uint_t          requests;//处理次数

    unsigned            buffered:8;

    unsigned            log_error:3;     /* ngx_connection_log_error_e */

    unsigned            unexpected_eof:1;//为1表示不期待借宿
    unsigned            timedout:1;//是否超时
    unsigned            error:1;//有米有出错
    unsigned            destroyed:1;//是不是销毁了

    unsigned            idle:1;//是不是空闲的
    unsigned            reusable:1;//是否可重用
    unsigned            close:1;//是不是关闭

    unsigned            sendfile:1;//是不是正在发送文件
    unsigned            sndlowat:1;
    unsigned            tcp_nodelay:2;   /* ngx_connection_tcp_nodelay_e */
    unsigned            tcp_nopush:2;    /* ngx_connection_tcp_nopush_e */

    unsigned            need_last_buf:1;

#if (NGX_HAVE_IOCP)
    unsigned            accept_context_updated:1;
#endif

#if (NGX_HAVE_AIO_SENDFILE)
    unsigned            aio_sendfile:1;
    unsigned            busy_count:2;
    ngx_buf_t          *busy_sendfile;
#endif

#if (NGX_THREADS)
    ngx_atomic_t        lock;
#endif
};

ngx_connection主要是存储了连接的信息和读写事件。

第一个获取ngx_connection

static void
ngx_drain_connections(void)//释放长连接
{
    ngx_int_t          i;
    ngx_queue_t       *q;
    ngx_connection_t  *c;

    for (i = 0; i < 32; i++) {
        if (ngx_queue_empty(&ngx_cycle->reusable_connections_queue)) {//reusable_connections_queue里面有没有
            break;
        }

        q = ngx_queue_last(&ngx_cycle->reusable_connections_queue);
        c = ngx_queue_data(q, ngx_connection_t, queue);

        ngx_log_debug0(NGX_LOG_DEBUG_CORE, c->log, 0,
                       "reusing connection");

        c->close = 1;//设置关闭
        c->read->handler(c->read);//收尾
    }
}


ngx_connection_t *
ngx_get_connection(ngx_socket_t s, ngx_log_t *log)//传入参数 socket log
{
    ngx_uint_t         instance;
    ngx_event_t       *rev, *wev;
    ngx_connection_t  *c;

    /* disable warning: Win32 SOCKET is u_int while UNIX socket is int */

    if (ngx_cycle->files && (ngx_uint_t) s >= ngx_cycle->files_n) {
        ngx_log_error(NGX_LOG_ALERT, log, 0,
                      "the new socket has number %d, "
                      "but only %ui files are available",
                      s, ngx_cycle->files_n);
        return NULL;
    }

    /* ngx_mutex_lock */

    c = ngx_cycle->free_connections;//获得free_connections

    if (c == NULL) {
        ngx_drain_connections();//释放长连接
        c = ngx_cycle->free_connections;
    }

    if (c == NULL) {//没有了
        ngx_log_error(NGX_LOG_ALERT, log, 0,
                      "%ui worker_connections are not enough",
                      ngx_cycle->connection_n);

        /* ngx_mutex_unlock */

        return NULL;
    }

    ngx_cycle->free_connections = c->data;//next
    ngx_cycle->free_connection_n--;//数量--

    /* ngx_mutex_unlock */

    if (ngx_cycle->files) {
        ngx_cycle->files[s] = c;
    }

    rev = c->read;//read
    wev = c->write;//write

    ngx_memzero(c, sizeof(ngx_connection_t));

    c->read = rev;
    c->write = wev;
    c->fd = s;//设置socket
    c->log = log;

    instance = rev->instance;

    ngx_memzero(rev, sizeof(ngx_event_t));
    ngx_memzero(wev, sizeof(ngx_event_t));

    rev->instance = !instance;
    wev->instance = !instance;

    rev->index = NGX_INVALID_INDEX;
    wev->index = NGX_INVALID_INDEX;

    rev->data = c;
    wev->data = c;

    wev->write = 1;

    return c;
}

ngx_connection的创建是在ngx_event模块的ngx_event_process_init的时候,这个内容会在说模块的时候具体说下。

获取过程很简单,就是从检查free_connections 有的话就直接获取,没有的话就尝试释放一下长连接队列。

free connection

void
ngx_free_connection(ngx_connection_t *c)
{
    /* ngx_mutex_lock */

    c->data = ngx_cycle->free_connections;//加入free_connection链表
    ngx_cycle->free_connections = c;
    ngx_cycle->free_connection_n++;

    /* ngx_mutex_unlock */

    if (ngx_cycle->files) {
        ngx_cycle->files[c->fd] = NULL;
    }
}

free的话就很简单,放入链表就好。

关闭链接

void
ngx_close_connection(ngx_connection_t *c)
{
    ngx_err_t     err;
    ngx_uint_t    log_error, level;
    ngx_socket_t  fd;

    if (c->fd == (ngx_socket_t) -1) {//没有fd
        ngx_log_error(NGX_LOG_ALERT, c->log, 0, "connection already closed");
        return;
    }

    if (c->read->timer_set) {//有time事件
        ngx_del_timer(c->read);
    }

    if (c->write->timer_set) {//有time事件
        ngx_del_timer(c->write);
    }

    if (ngx_del_conn) {//关闭
        ngx_del_conn(c, NGX_CLOSE_EVENT);

    } else {
        if (c->read->active || c->read->disabled) {
            ngx_del_event(c->read, NGX_READ_EVENT, NGX_CLOSE_EVENT);
        }

        if (c->write->active || c->write->disabled) {
            ngx_del_event(c->write, NGX_WRITE_EVENT, NGX_CLOSE_EVENT);
        }
    }

#if (NGX_THREADS)

    /*
     * we have to clean the connection information before the closing
     * because another thread may reopen the same file descriptor
     * before we clean the connection
     */

    ngx_mutex_lock(ngx_posted_events_mutex);

    if (c->read->prev) {//加入了postedevent
        ngx_delete_posted_event(c->read);
    }

    if (c->write->prev) {
        ngx_delete_posted_event(c->write);
    }

    c->read->closed = 1;//关闭
    c->write->closed = 1;

    ngx_unlock(&c->lock);
    c->read->locked = 0;
    c->write->locked = 0;

    ngx_mutex_unlock(ngx_posted_events_mutex);

#else

    if (c->read->prev) {
        ngx_delete_posted_event(c->read);
    }

    if (c->write->prev) {
        ngx_delete_posted_event(c->write);
    }

    c->read->closed = 1;
    c->write->closed = 1;

#endif

    ngx_reusable_connection(c, 0);//不重用

    log_error = c->log_error;

    ngx_free_connection(c);//假如到free队列

    fd = c->fd;
    c->fd = (ngx_socket_t) -1;

    if (ngx_close_socket(fd) == -1) {//释放soket

        err = ngx_socket_errno;

        if (err == NGX_ECONNRESET || err == NGX_ENOTCONN) {

            switch (log_error) {

            case NGX_ERROR_INFO:
                level = NGX_LOG_INFO;
                break;

            case NGX_ERROR_ERR:
                level = NGX_LOG_ERR;
                break;

            default:
                level = NGX_LOG_CRIT;
            }

        } else {
            level = NGX_LOG_CRIT;
        }

        /* we use ngx_cycle->log because c->log was in c->pool */

        ngx_log_error(level, ngx_cycle->log, err,
                      ngx_close_socket_n " %d failed", fd);
    }
}

关闭的删除time事件,从底层事件监听里面移除,如果有postevent,就删除,然后设置ngx_event的关闭,如果在重用队列,就从重用队列移除。最后关闭socket。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值