結構
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;
}
初始化客戶端鏈接的套接字