结构
ngx_listening_s :监听套接字文件描述
struct ngx_listening_s {
ngx_socket_t fd; //套接字
struct sockaddr *sockaddr; //监听的地址
socklen_t socklen; /* 地址长度*/
size_t addr_text_max_len; '存储ip地址的字符串 addr_text 最大长度'
ngx_str_t addr_text; '以字符串存储的ip地址'
int type; //套接字类型。types是SOCK_STREAM时,表示是tcp
int backlog; '记录监听套接字的链接数大小(2个队列:完成3次链接和未完成3次链接)'
int rcvbuf; //套接字接收进程缓冲区大小
int sndbuf; //套接字发送进程缓冲区大小
#if (NGX_HAVE_KEEPALIVE_TUNABLE)
int keepidle;
int keepintvl;
int keepcnt;
#endif
/* handler of accepted connection */
ngx_connection_handler_pt handler; '当新的tcp链接成功创建后的处理方法 '
void *servers; '目前主要用于HTTP或者mail等模块,用于保存当前监听端口对应着的全部主机名 '
ngx_log_t log;
ngx_log_t *logp;
size_t pool_size; '若是为新的tcp链接建立内存池,则内存池的初始大小应该是pool_size'
/* should be here because of the AcceptEx() preread */
size_t post_accept_buffer_size; '接受事件的buffer大小'
/* should be here because of the deferred accept */
ngx_msec_t post_accept_timeout; '接受事件的超时时间'
ngx_listening_t *previous; '前一个ngx_listening_t结构,用于组成单链表'
ngx_connection_t *connection; '监听链接池的第一个指针'
ngx_uint_t worker; '工做进程的个数'
unsigned open:1; '当前套接字,为1表示监听句柄有效,为0表示正常关闭 '
unsigned remain:1; '为1表示不关闭原先打开的监听端口,为0表示关闭曾经打开的监听端口'
unsigned ignore:1; '为1表示跳过设置当前ngx_listening_t结构体中的套接字,为0时正常初始化套接字 '
unsigned bound:1; '是否已绑定'
unsigned inherited:1; '是否从上一个进程中继承'
unsigned nonblocking_accept:1; '是否非阻塞接受'
unsigned listen:1; '是否为1表示当前结构体对应的套接字已经监听 '
unsigned nonblocking:1; '是否非阻塞接受'
unsigned shared:1; /* shared between threads or processes */
unsigned addr_ntop:1; '为1表示将网络地址转变为字符串形式的地址'
unsigned wildcard:1;
unsigned reuseport:1;
unsigned add_reuseport:1;
unsigned keepalive:2;
unsigned deferred_accept:1;
unsigned delete_deferred:1;
unsigned add_deferred:1;
#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
char *accept_filter;
#endif
#if (NGX_HAVE_SETFIB)
int setfib;
#endif
#if (NGX_HAVE_TCP_FASTOPEN)
int fastopen;
#endif
};
- backlog:半链接状态和全链接状态两种队列大小
- 半链接状态为:服务器处于Listen状态时收到客户端SYN=1报文时放入半链接队列中,即SYN queue(服务器端口状态为:SYN_RCVD)。
- 全链接状态为:TCP的链接状态从服务器 (SYN+ACK) 响应客户端后,到客户端的ACK报文到达服务器以前,则一直保留在半链接状态中;当服务器接收到客户端的ACK报文后,该条目将从半链接队列搬到全链接队列尾部,即 accept queue (服务器端口状态为:ESTABLISHED)。
ngx_connection_s 链接套接字
// 事件结构
struct ngx_connection_s {
void *data; //链接未使用时,data用于充当链接池中空闲链表中的next指针。有链接套接字使用时,由模块而定:http中,data指向ngx_http_connection_t
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_send_chain_pt send_chain; //链表来表示发送网络字符流的方法
ngx_listening_t *listening; //链接对应的ngx_listening_t监听的对象,此链接由listening监听端口的事件创建
off_t sent; //链接上已发送的字符数
ngx_log_t *log; //日志对象
ngx_pool_t *pool; //内存池
int type; //
struct sockaddr *sockaddr; //链接客户端的sockaddr
socklen_t socklen; //sockaddr结构体的长度
ngx_str_t addr_text; //链接客户端字符串形式的IP地址
ngx_str_t proxy_protocol_addr; //协议地址
in_port_t proxy_protocol_port; //协议端口
#if (NGX_SSL || NGX_COMPAT)
ngx_ssl_connection_t *ssl;
#endif
struct sockaddr *local_sockaddr; //本机监听端口对应的sockaddr结构体,其实是listening监听对象的sockaddr对象
socklen_t local_socklen; //监听端口个数
//用户接受、缓存客户端发来的字符流
//buffer是由链接内池分配,大小自由决定
ngx_buf_t *buffer;
//用来将当前链接以双向链表元素的形式添加到ngx_cycle_t核心结构体的reuseable_connection_queue双向链表中,表示能够重用的链接
ngx_queue_t queue;
ngx_atomic_uint_t number; //链接使用次数。ngx_connection_t结构体每次创建一条来自客户端的链接,或主动向后端服务器发起链接时,number都会加1
ngx_uint_t requests; //处理请求的次数
unsigned buffered:8; //缓存业务类型
unsigned log_error:3; /* ngx_connection_log_error_e */
unsigned timedout:1;//为1表示链接已经超时
unsigned error:1;//为1表示链接处理过程当中出现错误
unsigned destroyed:1;//为1表示链接已经销毁
unsigned idle:1;//为1表示链接处于空闲状态,如keepalive两次请求中间的状态
unsigned reusable:1;//为1表示链接可重用,与上面的queue字段对应使用
unsigned close:1;//为1表示链接关闭
unsigned shared:1;
unsigned sendfile:1;//为1表示正在将文件中的数据发往链接的另外一端
unsigned sndlowat:1;
unsigned tcp_nodelay:2; /* ngx_connection_tcp_nodelay_e */
unsigned tcp_nopush:2; /* ngx_connection_tcp_nopush_e */
/*为1表示只有链接套接字对应的发送缓冲区必须知足最低设置的大小阀值时,
事件驱动模块才会分发该事件。这与ngx_handle_write_event方法中的lowat参数是对应的*/
unsigned need_last_buf:1;
#if (NGX_HAVE_AIO_SENDFILE || NGX_COMPAT)
unsigned busy_count:2;
#endif
#if (NGX_THREADS || NGX_COMPAT)
ngx_thread_task_t *sendfile_task;
#endif
};
函数
建立监听套接字配置空间:主要是在初始化的cycle时,建立的配置空间
/**
ngx_conf_t:配置文件
sockaddr:监听地址
socklen:地址长度
*/
ngx_listening_t *
ngx_create_listening(ngx_conf_t *cf, struct sockaddr *sockaddr,
socklen_t socklen)
{
size_t len;
ngx_listening_t *ls;
struct sockaddr *sa;
u_char text[NGX_SOCKADDR_STRLEN];
ls = ngx_array_push(&cf->cycle->listening);
if (ls NULL) {
return NULL;
}
ngx_memzero(ls, sizeof(ngx_listening_t));
sa = ngx_palloc(cf->pool, socklen);
if (sa NULL) {
return NULL;
}
ngx_memcpy(sa, sockaddr, socklen);
ls->sockaddr = sa;
ls->socklen = socklen;
len = ngx_sock_ntop(sa, socklen, text, NGX_SOCKADDR_STRLEN, 1);
ls->addr_text.len = len;
switch (ls->sockaddr->sa_family) {
#if (NGX_HAVE_INET6)
case AF_INET6:
ls->addr_text_max_len = NGX_INET6_ADDRSTRLEN;
break;
#endif
#if (NGX_HAVE_UNIX_DOMAIN)
case AF_UNIX:
ls->addr_text_max_len = NGX_UNIX_ADDRSTRLEN;
len++;
break;
#endif
case AF_INET:
ls->addr_text_max_len = NGX_INET_ADDRSTRLEN;
break;
default:
ls->addr_text_max_len = NGX_SOCKADDR_STRLEN;
break;
}
ls->addr_text.data = ngx_pnalloc(cf->pool, len);
if (ls->addr_text.data NULL) {
return NULL;
}
ngx_memcpy(ls->addr_text.data, text, len);
ls->fd = (ngx_socket_t) -1;
ls->type = SOCK_STREAM;
ls->backlog = NGX_LISTEN_BACKLOG;
ls->rcvbuf = -1;
ls->sndbuf = -1;
#if (NGX_HAVE_SETFIB)
ls->setfib = -1;
#endif
#if (NGX_HAVE_TCP_FASTOPEN)
ls->fastopen = -1;
#endif
return ls;
}
初始化客户端链接的套接字