1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
r->keepalive = 0;
ngx_http_free_request(r, 0);
c->data = hc;
//设置定时器
ngx_add_timer(rev, clcf->keepalive_timeout);
//然后设置可读事件
if (ngx_handle_read_event(rev, 0) != NGX_OK) {
ngx_http_close_connection(c);
return ;
}
wev = c->write;
wev->handler = ngx_http_empty_handler;
|
12 34
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
if (b->pos < b->last) {
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c-> log ,
0, "pipelined request" );
#if (NGX_STAT_STUB)
( void ) ngx_atomic_fetch_add(ngx_stat_reading,
1);
#endif
//设置标记。
hc->pipeline = 1;
c-> log ->action =
"reading client pipelined request line" ;
//然后扔进post queue,继续进行处理.
rev->handler = ngx_http_init_request;
ngx_post_event(rev, &ngx_posted_events);
return ;
}
|
56789 10 1112131415 r->keepalive = 0; ngx_http_free_request(r, 0); c->data = hc; //타이머 설정 ngx_add_timer(rev, clcf ->keepalive_timeout); //읽을 수 있는 이벤트를 설정합니다 if (ngx_handle_read_event(rev, 0) != NGX_OK) { ngx_http_close_connection(c); 반환 ; wev = c->write; wev->handler = ngx_http_empty_handler; 그런 다음 다음 부분은 파이프라인 처리입니다.
12 3456789101112131415 |
if (b->pos < b->last) { ngx_log_debug0( NGX_LOG_DEBUG_HTTP, c-> 로그 ,
0, "파이프라인 요청" ); #if (NGX_STAT_STUB) ( void ) ngx_atomic_fetch_add(ngx_stat_reading,
1); #endif //태그를 설정합니다. hc->파이프라인 = 1; c-> 로그 ->액션 =
"클라이언트 파이프라인 요청 라인 읽기" ; //그런 다음 게시 대기열에 넣고 처리를 계속합니다. code >rev->handler = ngx_http_init_request; ngx_post_event(rev, &ngx_posted_events); 반환 ; 이 맨 아래에 도달하면 파이프라인 요청이 아니라는 뜻이므로 요청과 http_connection 정리를 시작합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
if (ngx_pfree(c->pool, r) == NGX_OK) {
hc->request = NULL;
}
b = c->buffer;
if (ngx_pfree(c->pool, b->start) == NGX_OK) {
/*
* the special note for ngx_http_keepalive_handler() that
* c->buffer's memory was freed
*/
b->pos = NULL;
}
else {
b->pos = b->start;
b->last = b->start;
}
.....................................................................
if (hc->busy) {
for (i = 0; i < hc->nbusy; i++) {
ngx_pfree(c->pool, hc->busy[i]->start);
hc->busy[i] = NULL;
}
hc->nbusy = 0;
}
|
12 34
1
2
3
4
5
6
7
8
9
|
//后面会详细分析这个函数
rev->handler = ngx_http_keepalive_handler;
if (wev->active && (ngx_event_flags & NGX_USE_LEVEL_EVENT)) {
if (ngx_del_event(wev, NGX_WRITE_EVENT, 0) != NGX_OK) {
ngx_http_close_connection(c);
return ;
}
}
|
567891011121314151617181920212223 24252627282930
|
if (ngx_pfree(c->pool, r) == NGX_OK) { hc->request = NULL; } b = c->buffer; if (ngx_pfree (c->풀, b->시작) == NGX_OK) { /* * ngx_http_keepalive_handler()에 대한 특별 참고 사항 * c->버퍼의 메모리가 해제되었습니다 코드> 코드> */ b->pos = NULL; 코드> }
else { b->pos = b->start; code>else code><code> b->last = b->start; } .......................... ......... ................................ if (hc->busy) { for code>(i = 0; i < hc->nbusy; i++) { ngx_pfree(c->pool, hc->busy[i] ->start); hc->busy[i] = NULL; } hc->nbusy = 0; <code>}
|
Keepalive 처리기를 설정합니다.
12 3456789 |
//이 함수는 나중에 자세히 분석할 예정입니다. rev->handler = ngx_http_keepalive_handler ; if (wev->active && (ngx_event_flags & NGX_USE_LEVEL_EVENT)) { if (ngx_del_event(wev, NGX_WRITE_EVENT, 0) != NGX_OK) { code><code>ngx_http_close_connection(c); return ; } }
|
마지막 단계는 tcp push 처리입니다. 지금은 여기서 소개하지 않겠습니다. 다음으로 nginx의 tcp push 동작을 소개하는 특별한 블로그를 준비하겠습니다. 그런 다음 ngx_http_keepalive_handler 함수를 살펴보겠습니다. 이 함수는 연결에 다시 읽을 수 있는 이벤트가 있을 때 호출됩니다. 이 핸들러는 비교적 간단합니다. 새 buf를 생성한 다음 http 요청 실행을 다시 시작합니다(ngx_http_init_request 호출).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
b = c->buffer;
size = b->end - b->start;
if (b->pos == NULL) {
/*
* The c->buffer's memory was freed by ngx_http_set_keepalive().
* However, the c->buffer->start and c->buffer->end were not changed
* to keep the buffer size.
*/
//重新分配buf
b->pos = ngx_palloc(c->pool, size);
if (b->pos == NULL) {
ngx_http_close_connection(c);
return ;
}
b->start = b->pos;
b->last = b->pos;
b->end = b->pos + size;
}
|
12 34
1
2
3
4
5
6
7
8
9
|
n = c->recv(c, b->last, size);
c->log_error = NGX_ERROR_INFO;
if (n == NGX_AGAIN) {
if (ngx_handle_read_event(rev, 0) != NGX_OK) {
ngx_http_close_connection(c);
}
return ;
}
|
567
1 |
ngx_http_init_request(rev);
|
89101112131415161718192021
|
b = c->버퍼; 크기 = b->end - b->start; 코드> 코드> if (b->pos == NULL) { /* * c->버퍼의 메모리는 ngx_http_set_keepalive()에 의해 해제되었습니다. * 단, c->buffer->start와 c->buffer->end는 변경되지 않았습니다. code>//buf 재할당 b->pos = ngx_palloc(c->pool, size) ; code><code> if (b->pos == NULL) { ngx_http_close_connection(c); } b->start = b->pos; >위치 + 크기 }
|
그런 다음 데이터가 있으면 읽어 보십시오. 읽을 수 있는 데이터가 없으면 읽기 가능한 이벤트에 핸들이 다시 추가됩니다
1234 56789 |
n = c->recv(c, b->마지막, 크기); code>c->log_error = NGX_ERROR_INFO; if (n == NGX_AGAIN) { if (ngx_handle_read_event(rev, 0 ) != NGX_OK) { ngx_http_close_connection(c); } 반환 ; } |
table>드디어 데이터를 읽어오면 요청 처리에 들어갑니다.
1 |
ngx_http_init_request(rev);
|
마지막으로 ngx_http_init_request 함수를 살펴보겠습니다. 이번에는 파이프라인이 요청될 때 nginx가 요청을 재사용하는 방법을 주로 살펴보겠습니다. 여기에서 hc->busy[0]에 주의하세요. 파이프라인 요청인 경우 이전에 구문 분석되지 않은 요청 header_in을 저장한다는 것을 이미 알고 있습니다. 이는 두 번째 헤더를 읽었을 수 있기 때문입니다. 파이프라인 요청의 일부 헤더입니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
//取得request,这里我们知道,在pipeline请求中,我们会保存前一个request.
r = hc->request;
if (r) {
//如果存在,则我们重用前一个request.
ngx_memzero(r,
sizeof (ngx_http_request_t));
r->pipeline = hc->pipeline;
//如果nbusy存在
if (hc->nbusy) {
//则保存这个header_in,然后下面直接解析。
r->header_in = hc->busy[0];
}
}
else {
r = ngx_pcalloc(c->pool,
sizeof (ngx_http_request_t));
if (r == NULL) {
ngx_http_close_connection(c);
return ;
}
hc->request = r;
}
//保存请求
c->data = r;
|
12 34567891011121314151617181920212223 2425
|
//요청 가져오기, 여기서 우리는 파이프라인 요청에서 이전 요청을 저장할 것이라는 것을 알고 있습니다.<code> r = hc->request; if code >(r) { //존재하는 경우 이전 요청을 재사용합니다. ngx_memzero(r,
sizeof (ngx_http_request_t)); r->pipeline = hc-> 파이프라인; //nbusy가 존재하는 경우 if (hc ->nbusy) { //이 header_in을 저장한 후 바로 아래에서 구문 분석합니다. r->header_in = hc->busy[0]; 코드> 코드>} }
else { r = ngx_pcalloc(c->pool,
크기 (ngx_http_request_t)); if (r == NULL) { ngx_http_close_connection(c); 반환 ; } hc->request = r; } //요청 저장 c->data = r;
|
위 코드와 이전 블로그를 통해 큰 헤더가 주로 파이프라인용이라는 것을 알 수 있습니다. 왜냐하면 파이프라인에서는 이전 요청이 다음 요청보다 더 많이 읽는 경우 헤더가 몇 개 있는 경우이기 때문입니다. , 다음 번에 구문 분석할 때 원래 할당된 client_header_buffer_size를 초과할 수 있습니다. 이때 큰 헤더인 헤더를 재할당해야 하므로 여기서 httpconnection은 주로 파이프라인 상황을 위한 것이며 Keepalive 연결이 다음과 같은 경우입니다. 파이프라인 요청이 아닙니다. 메모리를 절약하기 위해 이전 요청이 해제됩니다.
위 내용은 관련 측면을 포함하여 keepalive 및 파이프라인 요청 처리에 대한 nginx의 분석을 소개합니다. PHP 튜토리얼에 관심이 있는 친구들에게 도움이 되기를 바랍니다.
|
|
|