Nginx学习笔记(十九):Nginx连接

前言


       上篇笔记记录了事件处理框架,以及事件的结构定义。这篇笔记开始Nginx连接定义。Nginx定义了基本的数据结构ngx_connection_t来表示连接。由客户端主动发起、Nginx服务器被动接收的TCP连接,这类可以称为被动连接。还有一类连接,在某些请求的处理过程中,Nginx会试图主动向其他上游服务器建立连接,并以此连接与上游服务器通信,Nginx定义ngx_peer_connection_t结构来表示,这类可以称为主动连接。本质上来说,主动连接是以ngx_connection_t结构体为基础实现的。

ngx_connection_t被动连接


       直接看结构:
struct ngx_connection_s {
	/* 连接未使用时,data成员相当于链表的next指针。当连接被使用时,data由使用该连接的Nginx的模块定义,比如HTTP模块data指向请求 */
    void               *data;
    
    ngx_event_t        *read;   // 连接对应的读事件
    ngx_event_t        *write;  // 连接对应的写事件

    ngx_socket_t        fd;     // 套接字句柄

    ngx_recv_pt         recv;   // 直接接收网络字节流的方法
    ngx_send_pt         send;   // 直接发送网络字节流的方法
    ngx_recv_chain_pt   recv_chain;  // 以ngx_chain_t链表为参数来接收网络字节流的方法
    ngx_send_chain_pt   send_chain;  // 以ngx_chain_t链表为参数来发送网络字节流的方法

    ngx_listening_t    *listening;   // 该连接对应ngx_listening_t监听对象,此连接由listening监听端口的事件建立

    off_t               sent;   // 该连接上已发送出去的字节数 

    ngx_log_t          *log;    // 日志

	/* 内存池。一般在accept一个新连接时,会创建一个内存池,而在这个连接结束时将其销毁 */
    ngx_pool_t         *pool;

	/* 连接客户端的socket信息 */
    struct sockaddr    *sockaddr;
    socklen_t           socklen;
    ngx_str_t           addr_text;

    struct sockaddr    *local_sockaddr;  // 本地socket结构

    ngx_buf_t          *buffer;  // 用于节后、缓存客户端发送过来的字节流

    ngx_queue_t         queue;   // 将当前连接添加到ngx_cycle_t核心结构中的reuseable_connections_queue双向链表中,表示可重用连接

    ngx_atomic_uint_t   number;  // 连接使用次数

    ngx_uint_t          requests;  // 处理请求次数

    unsigned            buffered:8;  // 缓存中的业务类型,至多可以同时标识8个不同业务

    unsigned            log_error:3;     /* ngx_connection_log_error_e */

    unsigned            unexpected_eof: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 */

#if (NGX_HAVE_AIO_SENDFILE)
    unsigned            aio_sendfile:1;  // 使用异步I/O方式发送磁盘文件
    ngx_buf_t          *busy_sendfile;   // 该缓冲区保存待发送的文件信息
#endif
};

ngx_peer_connection_t主动连接


       Nginx主动想后端服务器发起的连接称作主动连接,用ngx_peer_connection_t结构表示,其实质是对ngx_connection_t作了一层封装。
/* 通过该方法由连接池中获取一个新连接 */
typedef ngx_int_t (*ngx_event_get_peer_pt)(ngx_peer_connection_t *pc,
    void *data);
    
/* 通过该方法将使用完毕的连接释放给连接池 */
typedef void (*ngx_event_free_peer_pt)(ngx_peer_connection_t *pc, void *data,
    ngx_uint_t state);

具体结构如下:
struct ngx_peer_connection_s {
	/* 主动连接实际上需要被动连接结构的大部分成员,相当于重用 */
    ngx_connection_t                *connection;

	/* 远端服务器socket信息 */
    struct sockaddr                 *sockaddr;
    socklen_t                        socklen;
    ngx_str_t                       *name;

	/* 连接失败后可以重试的次数 */
    ngx_uint_t                       tries;

	/* 从连接池中获取长连接,必须使用该方法 */
    ngx_event_get_peer_pt            get;
    ngx_event_free_peer_pt           free;
    
    /* 该data成员作为上面方法的传递参数 */
    void                            *data;

	/* 本地地址信息 */
    ngx_addr_t                      *local;

	/* 接收缓冲区大小 */
    int                              rcvbuf;

    ngx_log_t                       *log;

	/* 标识该连接已经缓存 */
    unsigned                         cached:1;

    /* ngx_connection_log_error_e */
    unsigned                         log_error:2;
};

ngx_connection_t连接池


       Nginx在接受客户端的连接所使用的ngx_connection_t结构都是在启动阶段就预分配好的,使用时只需从连接池中获取。书中图示如下:

        Nginx学习笔记(十九):Nginx连接_第1张图片

       ngx_cycle_t中的connections和free_connections俩成员构成一个连接池。其中,connections指向整个连接池数组首部,free_connections指向第一个ngx_connection_t空闲连接。所有空闲连接ngx_connection_t都以data成员作为next指针串联成一个单链表。这样,一旦有用户发起连接就从free_connections指向的链表头获取一个空闲连接。在连接释放时,只需把该连接再插入到free_connections链表头即可。

       同时,ngx_cycle_t核心结构还有一套事件池,即Nginx认为每一个连接至少需要一个读事件和一个写事件,有多少个连接就分配多少个读、写事件。这里,读、写、连接池都是由三个大小相同的数组组成,根据数组下标就可将每一个连接、读、写事件对应起来。这三个数组的大小都由nginx.conf的connections配置项决定。

总结


       对Nginx中的连接做下笔记,尤其是Nginx中启动阶段就预分配好的连接池以及它的封装方法的技巧。

主要参考

《深入理解Nginx》


你可能感兴趣的:(深入理解Nginx,Nginx学习笔记系列)