nginx 이벤트 모듈 의 클 라 이언 트 연결 및 시간 초과 관리
9187 단어 nginx 소스 코드 분석
연결 이벤트 관리
함수 ngxevent_process_init 에 서 는 읽 기 이벤트 의 반전 을 ngx 로 설정 합 니 다.event_accept。 이렇게 설정 하면 nginx 서버 에서 클 라 이언 트 의 연결 요청 을 감청 한 후 이 리 셋 이 실 행 됩 니 다. 클 라 이언 트 와 tcp 연결 을 만 드 는 데 사 용 됩 니 다.연결 이 구축 되면 클 라 이언 트 와 데이터 상호작용 을 정상적으로 할 수 있 습 니 다.
//ngx_event_core_module init_process 。 ngx_worker_process_init
static ngx_int_t ngx_event_process_init(ngx_cycle_t *cycle)
{
// , ( , ,
// , 、 ),
ls = cycle->listening.elts;
for (i = 0; i < cycle->listening.nelts; i++)
{
c = ngx_get_connection(ls[i].fd, cycle->log);
//
c->listening = &ls[i];
//
ls[i].connection = c;
rev = c->read;
// , ,
rev->handler = ngx_event_accept;
// work , epoll
// NULL, ngx_get_connection 0
if (ngx_add_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR)
{
return NGX_ERROR;
}
}
ngx_event_accept 는 클 라 이언 트 로부터 연결 요청 을 받 는 데 사 용 됩 니 다.tcp 가 만들어 진 후 연결 풀 에서 새 연결 대상 을 가 져 오고 읽 기, 쓰기 이 벤트 를 가 져 오 며 읽 기 이 벤트 를 epoll 에 추가 합 니 다.이 새로운 연결 대상 과 감청 대상 의 역할 은 다르다.감청 대상 은 클 라 이언 트 의 연결 을 감청 하 는 데 사 용 됩 니 다. 클 라 이언 트 와 연결 하기 전에 호출 되 지 않 았 습 니 다.이 새 연결 대상 은 tcp 연결 후 호출 되 어 클 라 이언 트 와 데이터 읽 기와 쓰기 에 사 용 됩 니 다.
//
void ngx_event_accept(ngx_event_t *ev)
{
do
{
//
s = accept(lc->fd, (struct sockaddr *) sa, &socklen);
//work , work 7/8 ,
// work 。 tcp ,
ngx_accept_disabled = ngx_cycle->connection_n / 8
- ngx_cycle->free_connection_n;
// ( , )
c = ngx_get_connection(s, ev->log);
//
c->pool = ngx_create_pool(ls->pool_size, ev->log);
c->sockaddr = ngx_palloc(c->pool, socklen);
ngx_memcpy(c->sockaddr, sa, socklen);
// , 。 ngx_os_io
// , 。 , 。
// , , ,
//
c->recv = ngx_recv;
c->send = ngx_send;
c->recv_chain = ngx_recv_chain;
c->send_chain = ngx_send_chain;
// ls, ls accept ,
//
c->listening = ls;
// , epoll
// , 。
// 5 socket, 5 。
// , 4 , 。 , 。
ls->handler(c); //ngx_http_init_connection
} while (ev->available);
}
함수 에서 ngx 호출listening_s 대상 의 handler 방법.이 방법 은 사실 ngxhttp_init_connection, ngxhttp_add_listening 함수 에 설정 되 어 있 습 니 다.
ngx_http_init_listening
---> ngx_http_add_listening
--->
// ngx_listening_t , 。
ngx_listening_t * ngx_http_add_listening(ngx_conf_t *cf, ngx_http_conf_addr_t *addr)
{
// ngx_listening_t
ls = ngx_create_listening(cf, &addr->opt.u.sockaddr, addr->opt.socklen);
//
ls->handler = ngx_http_init_connection;
}
ngx_http_init_connection 은 tcp 가 연결 을 만 든 후 http 요청 초기 화 전 단계 입 니 다. 새로 만 든 클 라 이언 트 연결 등록 읽 기 이벤트 에 ngxhttp_init_request, 이벤트 리 셋 ngxhttp_empty_handler, 동시에 읽 기 이벤트 의 시간 초과 이 벤트 를 레 드 블랙 트 리 가 구현 하 는 타이머 에 등록 합 니 다.마지막 으로 읽 기 이 벤트 를 epoll 에 넣 습 니 다.이 작업 이 실 행 된 후에 클 라 이언 트 로부터 데 이 터 를 받 을 수 있 습 니 다.
// ,ngx_event_accept ngx_listening_t handler,
// :
void ngx_http_init_connection(ngx_connection_t *c)
{
rev = c->read;
//
rev->handler = ngx_http_init_request;
// ,
c->write->handler = ngx_http_empty_handler;
// , ,post_accept_timeout
// nginx.conf client_header_timeout
ngx_add_timer(rev, c->listening->post_accept_timeout);
// epoll , epoll , ,
ngx_handle_read_event(rev, 0);
}
nginx 서버 는 클 라 이언 트 의 연결 요청 을 처리 한 후 워 크 프로 세 스 의 이벤트 순환 으로 돌 아 왔 습 니 다.새로 만 든 대상 을 감청 하고 클 라 이언 트 가 보 낸 데 이 터 를 기다 리 며 클 라 이언 트 와 데이터 상호작용 을 합 니 다.
//work
static void ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data)
{
for ( ;; )
{
ngx_process_events_and_timers(cycle);
}
}
2. 시간 초과 사건 관리
nginx 서버 는 클 라 이언 트 의 연결 요청 을 감청 한 후 클 라 이언 트 와 tcp 연결 을 만 들 고 이 새로운 연결 을 위해 읽 기와 쓰기 이 벤트 를 등록 하 며 읽 기 이벤트 의 시간 초과 이 벤트 를 빨간색 과 검은색 트 리 가 실현 하 는 타이머 에 추가 합 니 다.위 에서 의 ngxhttp_init_connection 함수 에서 이 동작 을 볼 수 있 고 읽 기 이 벤트 를 빨간색 과 검은색 트 리 가 실 현 된 타이머 에 추가 할 수 있 습 니 다.
// ,ngx_event_accept ngx_listening_t handler,
// :
void ngx_http_init_connection(ngx_connection_t *c)
{
rev = c->read;
//
rev->handler = ngx_http_init_request;
// ,
c->write->handler = ngx_http_empty_handler;
// , ,post_accept_timeout
// nginx.conf client_header_timeout
ngx_add_timer(rev, c->listening->post_accept_timeout);
// epoll
ngx_handle_read_event(rev, 0);
}
ngx_event_add_timer 는 이 벤트 를 붉 은 검 은 나무 가 실현 하 는 타이머 에 등록 하 는 것 을 책임 집 니 다.붉 은 검 은 나무 에 있 는 모든 시간 초과 사건 노드 는 ngx 를 통 해event_s 대상 의 timer 멤버 가 연결 되 어 있 습 니 다.타이머 에 있 는 모든 시간 초과 이벤트 노드 의 key 는 시간 초과 로 이 사건 의 시간 초과 시간 을 기록 합 니 다.
// ,timer
static ngx_inline void ngx_event_add_timer(ngx_event_t *ev, ngx_msec_t timer)
{
ngx_msec_t key;
ngx_msec_int_t diff;
key = ngx_current_msec + timer;
// ,
if (ev->timer_set)
{
ngx_del_timer(ev);
}
// id,
ev->timer.key = key;
//
ngx_rbtree_insert(&ngx_event_timer_rbtree, &ev->timer);
//
ev->timer_set = 1;
}
읽 기 이 벤트 를 레 드 블랙 트 리 타이머 에 추가 한 후, 다음 work 프로 세 스 는 이벤트 순환 에 들 어가 epoll 에 차단 합 니 다.wait 호출.그럼 epollwait 언제 돌아 올 까요?클 라 이언 트 의 데 이 터 를 받 은 후, 또는 모든 이벤트 의 정시 시간 이 되면 epollwait 복귀.다음은 epoll 을 어떻게 설정 하 는 지 보 겠 습 니 다.wait 의 시간 초과, 시간 초과 후 즉시 epollwait 복귀.
//work
void ngx_process_events_and_timers(ngx_cycle_t *cycle)
{
// , timer
timer = ngx_event_find_timer();
// epoll_wait
(void) ngx_process_events(cycle, timer, flags);
//epoll_wait ,
ngx_event_expire_timers();
}
붉 은 검 은 나 무 는 이 진 트 리 이기 때문에 최소 시간 초과 시간 은 사실상 왼쪽 나무의 최소 값 이다.그래서 ngx 를 볼 수 있 습 니 다.event_find_timer 함수 의 실현 은 왼쪽 하위 트 리 에서 최소 값 을 찾 는 것 입 니 다.붉 은 검 은 나무의 실현 을 잘 모 르 면 주리 대신 의 블 로 그 를 볼 수 있다http://www.cnblogs.com/v-July-v/archive/2010/12/29/1983707.html
// ;
// :>0
// <=0
ngx_msec_t ngx_event_find_timer(void)
{
ngx_msec_int_t timer;
ngx_rbtree_node_t *node, *root, *sentinel;
// , -1
if (ngx_event_timer_rbtree.root == &ngx_event_timer_sentinel)
{
return NGX_TIMER_INFINITE;
}
root = ngx_event_timer_rbtree.root;
sentinel = ngx_event_timer_rbtree.sentinel;
//
node = ngx_rbtree_min(root, sentinel);
//
timer = (ngx_msec_int_t) node->key - (ngx_msec_int_t) ngx_current_msec;
return (ngx_msec_t) (timer > 0 ? timer : 0);
}
그리고 epollwait 호출 후 이벤트 가 시간 을 초과 하면 시간 초과 사건 을 어떻게 처리 합 니까?ngx_event_expire_timers 내부 에 빨 간 검 은 나 무 를 옮 겨 다 니 며 시간 이 초 과 된 모든 사건 을 찾 고 시간 이 초 과 된 사건 의 처리 반전 을 호출 합 니 다.주의해 야 할 것 은 함수 도 빨 간 검 은 나무 에서 이 시간 초과 사건 을 삭제 하기 때문에 이 시간 초과 사건 을 관리 해 야 한다 면 이 사건 을 빨 간 검 은 나무 가 실현 하 는 타이머 에 다시 추가 해 야 합 니 다.
// ,
void ngx_event_expire_timers(void)
{
ngx_event_t *ev;
ngx_rbtree_node_t *node, *root, *sentinel;
sentinel = ngx_event_timer_rbtree.sentinel;
// ,
for ( ;; )
{
root = ngx_event_timer_rbtree.root;
//
if (root == sentinel)
{
return;
}
//
node = ngx_rbtree_min(root, sentinel);
/* node->key <= ngx_current_time */
//
if ((ngx_msec_int_t) node->key - (ngx_msec_int_t) ngx_current_msec <= 0)
{
ev = (ngx_event_t *) ((char *) node - offsetof(ngx_event_t, timer));
//
ngx_rbtree_delete(&ngx_event_timer_rbtree, &ev->timer);
//
ev->timer_set = 0;
//
ev->timedout = 1;
//
ev->handler(ev);
// ,
continue;
}
// , ,
break;
}
}
이로써 시간 초과 사건 의 관리 도 분석 이 끝났다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
nginx 소스 코드 분석 - reuseport 의 사용reuseport 의 감청 소켓 을 설정 하면 모든 worker 프로 세 스 는 하나의 독립 된 fd 를 가지 고 있 으 며, worker 프로 세 스 간 에 서로 간섭 하지 않 고 커 널 차원 에서 부하 균형 을 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.