nginx 수신 패키지 처리
11422 단어 nginx 소스 코드 분석
http 프레임 워 크 수신 패키지 의 입 구 는: ngx_http_read_client_request_body, 가방 을 버 리 는 입 구 는:ngxhttp_discard_request_body。http 프레임 워 크 가 요청 패 키 지 를 어떻게 처리 하 는 지 분석 하고 패 키 지 를 버 리 면 다음 글 에서 분석 합 니 다.
1.첫 수신 패키지 초기 화 작업
ngx_http_read_client_request_body 는 http 패키지 함 수 를 처음 받 습 니 다.한 번 에 패키지 함 수 를 모두 받 지 않 으 면 ngx 를 호출 합 니 다.http_read_client_request_body_handler 계속 받 아.패키지 가 미리 읽 히 지 않 았 다 면 이 함 수 는 수신 버퍼 만 열 고 패키지 가 완성 되 지 않 았 을 때 읽 기 이벤트 리 셋 을 설정 하여 다음 에 패키지 만 계속 읽 을 수 있 도록 하 는 것 과 같은 초기 화 프로 세 스 입 니 다.실제 읽 기 데 이 터 는 뒤에서 분석 된다.이 함 수 는 귀납 하여 다음 과 같은 몇 가지 일 을 했다.
1.함 수 는 수신 패키지 버퍼 를 열 어 http 요청 구조 에 저 장 된 requestbody。클 라 이언 트 로부터 받 은 패 키 지 는 모두 이 공간 에 저 장 됩 니 다.
2.일부 패 킷 을 미리 읽 었 는 지 판단 하고 http 요청 머리 를 받 았 을 때 도 패 킷 데이터 도 읽 었 으 면 미리 읽 은 패 킷 을 처리 합 니 다.
3.요청 에 대응 하 는 읽 기 이벤트 의 리 셋 을 설정 하여 전체 패키지 가 한꺼번에 읽 히 지 않 았 을 때 다시 예약 할 때 나머지 패키지 데 이 터 를 계속 읽 을 수 있 습 니 다.
수신 패키지 버퍼 를 개척 하 는 과정 을 보십시오.매개 변수 posthandler 는 http 패 키 지 를 받 은 후 http 모듈 에서 호출 된 리 셋 을 표시 합 니 다.예 를 들 어 역방향 프 록 시 모듈 은 패키지 수신 후 posthandler 설정:ngxhttp_upstream_init,받 은 패 키 지 를 상위 서버 에 맡 깁 니 다.
ngx_int_t ngx_http_read_client_request_body(ngx_http_request_t *r, ngx_http_client_body_handler_pt post_handler)
{
// http
rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
// http
r->request_body = rb;
}
가방 의 길이 가 0 이면 가방 이 없다 는 뜻 이다.그러나 nginx.conf 설정 파일 에 패키지 만 파일 에 저장 할 수 있 도록 지정 하면 nginx 서버 는 클 라 이언 트 의 패키지 데이터 가 없 더 라 도 빈 파일 을 만 듭 니 다.이 빈 파일 은 요청 이 끝 난 후에 삭 제 됩 니 다.왜 패키지 데이터 가 없 는 지 빈 파일 을 만들어 야 하 는 지 이 논 리 는 아직 잘 모 르 겠 습 니 다.처리 할 데이터 가 없 기 때문에 마지막 으로 http 모듈 에서 제공 하 는 posthandler 함 수 는 http 모듈 에서 직접 처리 합 니 다.ngx_int_t ngx_http_read_client_request_body(ngx_http_request_t *r, ngx_http_client_body_handler_pt post_handler)
{
if (r->headers_in.content_length_n == 0)
{
//
if (r->request_body_in_file_only)
{
ngx_create_temp_file(&tf->file, tf->path, tf->pool, tf->persistent, tf->clean, tf->access)
}
post_handler(r);
}
}
http 요청 머리 를 받 을 때 도 패키지 데이터 도 읽 으 면 미리 읽 은 패키지 처리 합 니 다.대략적인 논 리 는 버퍼 를 열 어 패키지 데 이 터 를 읽 는 것 이다.미리 읽 은 데이터 가 완전한 패키지 라면 패키지 가 모두 읽 었 음 을 설명 하고 http 모듈 에서 제공 하 는 post 를 직접 되 돌려 줍 니 다.handler 함 수 는 http 모듈 에서 직접 처리 합 니 다.미리 읽 은 데이터 가 완전한 패키지 가 아니라면 패 키 지 를 계속 받 을 수 있 도록 다시 예약 해 야 한 다 는 뜻 입 니 다.이 때 읽 기 이 벤트 를 epoll 에 등록 해 야 합 니 다.물론 하나의 버퍼 에 모든 패 키 지 를 저장 할 수 없 을 때 하나의 버퍼 를 만 들 고 두 노드 만 있 는 버퍼 링크 를 구성 합 니 다.ngx_int_t ngx_http_read_client_request_body(ngx_http_request_t *r, ngx_http_client_body_handler_pt post_handler)
{
// http
if (preread)
{
// ngx_chain_t
rb->bufs = ngx_alloc_chain_link(r->pool);
rb->bufs->buf = b;
rb->bufs->next = NULL;
rb->buf = b;
// ,
if ((off_t) preread >= r->headers_in.content_length_n)
{
//
if (r->request_body_in_file_only)
{
//
ngx_http_write_request_body(r, rb->bufs));
}
post_handler(r);
return NGX_OK;
}
// http
r->header_in->pos = r->header_in->last;
r->request_length += preread;
rb->rest = r->headers_in.content_length_n - preread;
//
if (rb->rest <= (off_t) (b->end - b->last))
{
rb->to_write = rb->bufs;
//
r->read_event_handler = ngx_http_read_client_request_body_handler;
return ngx_http_do_read_client_request_body(r);
}
// , ,
next = &rb->bufs->next;
}
}
다음은 http 에서 요청 한 읽 기 이벤트 read 를 등록 합 니 다.event_handler 반전: ngx_http_read_client_request_body_handler
ngx_int_t ngx_http_read_client_request_body(ngx_http_request_t *r, ngx_http_client_body_handler_pt post_handler)
{
//
r->read_event_handler = ngx_http_read_client_request_body_handler;
}
앞의 논 리 는 이미 분석 되 었 습 니 다.ngxconnection_s 읽 기 이벤트 의 반전 설정 은 ngxhttp_request_handler。 따라서 읽 기 이벤트 가 발생 할 때 구조 적 읽 기 리 셋 을 요청 합 니 다.//http , ngx_http_process_request
// ngx_http_request_handler
static void ngx_http_request_handler(ngx_event_t *ev)
{
// , 。
if (ev->write)
{
r->write_event_handler(r); // ngx_http_handler ngx_http_core_run_phases
}
else
{
r->read_event_handler(r); // ngx_http_process_request ngx_http_block_reading
}
//
ngx_http_run_posted_requests(c);
}
2.http 요청 패키지 수신
초기 화 과정 은 수신 패키지 버퍼 만 열 었 을 뿐 입 니 다.이 버퍼 는 미리 분 배 된 방법 으로 만 들 어 졌 으 며 하나 또는 두 개의 노드 로 구성 되 어 있 습 니 다(최대 두 개의 노드 만 있 을 수 있 습 니 다).실제 수신 패 키 지 는 ngxhttp_do_read_client_request_body 함수 완성.함수 코드 를 분석 하기 전에 다음 과 같은 몇 가지 장면 을 먼저 고려 합 니 다.
1.nginx.conf 설정 에서 http 가 요청 한 패키지 데 이 터 는 메모리 에 만 저장 할 수 있 고 한 데이터 노드 가 모든 패키지 데 이 터 를 저장 할 수 있 으 면 메모리 레이아웃 은 다음 과 같 습 니 다.
2.하나의 데이터 노드 만 있 는 상황 에서 만약 에 하나의 데이터 노드 가 모든 패키지 데 이 터 를 저장 하지 못 하면 이 노드 의 모든 데 이 터 를 임시 파일 에 기록 합 니 다.파일 에 기록 하면 데이터 노드 는 클 라 이언 트 로부터 패 키 지 를 다시 받 을 수 있 습 니 다.버퍼 가 가득 차 면 다시 파일 에 기록 합 니 다.완전한 패키지 데 이 터 를 받 을 때 까지 순서대로 이 동작 을 수행 합 니 다.이 경우 데 이 터 를 메모리 에 만 저장 할 수 있 도록 지정 하 더 라 도 메모리 버퍼 에 한계 가 있어 모든 패 키 지 를 받 을 수 없습니다.이 때 는 모든 데 이 터 를 임시 파일 에 기록 합 니 다.메모리 레이아웃 은 다음 과 같 습 니 다:
3.버퍼 가 두 개의 데이터 노드 로 구성 된다 고 가정 하면 가능 합 니 다.(예 를 들 어 http 요청 머리 를 받 을 때 일부 패키지 데 이 터 를 미리 읽 었 으 나 현재 데이터 노드 가 남 은 패키지 데 이 터 를 저장 할 수 없 음 을 발견 하면 데이터 노드 를 다시 엽 니 다).이러한 상황 에서 ngix.conf 가 데 이 터 를 메모리 에 만 저장 할 수 있 고 두 노드 의 버퍼 가 모든 패키지 데 이 터 를 저장 할 수 있다 면 메모리 레이아웃 은 다음 과 같 습 니 다.
4.버퍼 가 두 개의 데이터 노드 로 구성 된다 고 가정 합 니 다.이 경우 ngix.conf 에서 데 이 터 를 파일 에 만 저장 할 수 있 도록 지정 하면 링크 의 모든 데 이 터 를 파일 에 기록 합 니 다.링크 노드 의 버퍼 는 파일 에 해당 하 는 위 치 를 가리킨다.메모리 레이아웃 은 다음 그림 과 같 습 니 다.
5.버퍼 가 두 개의 데이터 노드 로 구성 된다 고 가정 합 니 다.이러한 상황 에서 ngix.conf 가 지정 한 패키지 데 이 터 를 파일 에 만 저장 하거나 지정 한 패키지 데 이 터 를 메모리 에 만 저장 할 수 있 습 니 다.이 경우 일부 데 이 터 를 메모리 에 저장 하고 다른 일 부 는 파일 에 저장 할 수 있 습 니 다.두 번 째 노드 버퍼 가 가득 차 면 두 번 째 노드 의 데 이 터 를 파일 에 만 기록 하고 첫 번 째 노드 의 데 이 터 는 변 하지 않 으 며 메모리 에 저 장 됩 니 다.이 때 두 번 째 노드 는 클 라 이언 트 로부터 http 패키지 데 이 터 를 계속 받 을 수 있 습 니 다.버퍼 가 가득 차 면 두 번 째 노드 의 데 이 터 를 파일 에 기록 합 니 다.모든 패 키 지 를 읽 을 때 까지 이러한 절 차 를 순서대로 실행 합 니 다.메모리 레이아웃 은 다음 과 같 습 니 다.링크 에 있 는 데 이 터 는 메모리 에 저장 되 고 다른 데 이 터 는 파일 에 저 장 됩 니 다.
이제 ngx 분석 해 보 겠 습 니 다.http_do_read_client_request_body 함 수 는 어떻게 패 키 지 를 받 습 니까?사실 이 함 수 는 위의 5 개의 장면 을 처리 하고 가방 체 를 미리 열 린 노드 에 저장 하 는 것 이다.
static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r)
{
for ( ;; )
{
// ,
if (rb->buf->last == rb->buf->end)
{
ngx_http_write_request_body(r, rb->to_write)) ;
// 2 , , 2
rb->to_write = rb->bufs->next ? rb->bufs->next : rb->bufs;
// ,
rb->buf->last = rb->buf->start;
}
//
n = c->recv(c, rb->buf->last, size); //ngx_unix_recv
//
rb->buf->last += n;
}
// , 。
// , , 。
if (rb->temp_file || r->request_body_in_file_only)
{
ngx_http_write_request_body(r, rb->to_write));
b = ngx_calloc_buf(r->pool);
b->in_file = 1;
b->file_pos = 0;
b->file_last = rb->temp_file->file.offset;
b->file = &rb->temp_file->file;
}
}
데이터 가 모두 수신 되면 읽 기 요청 의 반전 을 ngx 로 설정 합 니 다.http_block_reading。이 함 수 는 아무것도 하지 않 습 니 다.패키지 가 읽 기 완료 되 었 고 읽 기 이벤트 가 있 을 때 처리 하지 않 습 니 다.이 동시에 http 모듈 의 post 를 되 돌려 줍 니 다.handler 방법 은 패키지 가 모두 수신 되 었 음 을 설명 하고 후속 작업 은 모듈 에 맡 깁 니 다.예 를 들 어 역방향 프 록 시 모듈 은 http 프레임 워 크 를 호출 하여 전체 패 킷 을 받 은 후 이 모듈 을 역방향 으로 프 록 시 하 는 방법 으로 패 킷 데 이 터 를 백 엔 드 서버 에 보 냅 니 다.static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r)
{
// , , ,
r->read_event_handler = ngx_http_block_reading;
// , , , ,
rb->post_handler(r);
}
3.다시 스케줄 링 할 때 남 은 가방 을 받 습 니 다.
한 번 에 완전한 패키지 데 이 터 를 받 지 않 으 면 요청 한 읽 기 방법 을 ngx 로 설정 합 니 다.http_read_client_request_body_handler。이렇게 다시 배 치 될 때 이 함수 가 나머지 패키지 데 이 터 를 받 는 것 을 책임 집 니 다.이 함수 의 실현 과정 을 살 펴 보 겠 습 니 다:
// , ngx_event_t ngx_http_request_handler
static void ngx_http_read_client_request_body_handler(ngx_http_request_t *r)
{
// ,
rc = ngx_http_do_read_client_request_body(r);
}
함수 실현 이 매우 간편 하 다.바로 수신 패키지 처리 함 수 를 스케줄 링 하여 나머지 패키지 데 이 터 를 수신 하 는 것 이다.이 함 수 는 http 패키지 가 모두 접 수 될 때 까지 남 은 패키지 데 이 터 를 받 아들 여 함수 의 사명 을 수행 합 니 다.지금까지 프레임 워 크 는 http 요청 패 키 지 를 어떻게 받 아들 이 고 패 키 지 를 받 은 후에 구체 적 인 http 모듈 을 어떻게 바 꾸 는 지 모듈 에 맡 기 고 패 키 지 를 받 은 후의 작업 을 계속 처리 하 는 지 분석 이 완료 되 었 습 니 다.패키지 체 를 미리 분 배 된 링크 에 저장 합 니 다.이 링크 버퍼 는 메모리 일 수도 있 고 파일 일 수도 있 습 니 다.저 는 이 처리 논 리 는 배 울 만 한 가치 가 있다 고 생각 합 니 다.사전 배분 방법 을 사용 하 는 동시에 데 이 터 를 메모리 에 저장 할 수도 있 고 파일 에 저장 할 수도 있 는 장면 을 해결 하 였 습 니 다.다음 글 은 http 프레임 워 크 가 패키지 작업 을 어떻게 버 렸 는 지 분석 할 것 입 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
nginx 소스 코드 분석 - reuseport 의 사용reuseport 의 감청 소켓 을 설정 하면 모든 worker 프로 세 스 는 하나의 독립 된 fd 를 가지 고 있 으 며, worker 프로 세 스 간 에 서로 간섭 하지 않 고 커 널 차원 에서 부하 균형 을 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.