上一节说了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。