nginx 수신 패키지 처리

http 에서 하나의 요청 은 보통 선택 한 요청 줄,요청 머리,그리고 선택 할 수 있 는 패키지 로 구 성 됩 니 다.따라서 http 머리 를 받 은 후 상태 기 를 사용 하여 각 http 모듈 의 협동 처리 요청 을 조정 한 후 각 http 모듈 에서 패 키 지 를 어떻게 처리 할 지 결정 합 니 다.http 프레임 워 크 는 http 모듈 호출(수신 패키지 와 버 림 패키지)을 위 한 2 가지 처리 패 키 지 를 제공 합 니 다.이 두 가지 처리 패 키 지 는 http 각 모듈 에 투명 합 니 다.즉,http 모듈 은 프레임 워 크 가 패 키 지 를 어떻게 처리 하 는 지 에 관심 을 가 질 필요 가 없습니다. http 모듈 은 http 프레임 워 크 가 제공 하 는 방법 으로 패 키 지 를 처리 하면 됩 니 다.수신 패키지 인 데 요?아니면 가방 을 버 릴 까요?이러한 행 위 는 http 모듈 자체 의 필요 에 의 해 결정 된다.
        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 가 요청 한 패키지 데 이 터 는 메모리 에 만 저장 할 수 있 고 한 데이터 노드 가 모든 패키지 데 이 터 를 저장 할 수 있 으 면 메모리 레이아웃 은 다음 과 같 습 니 다.
nginx接收包体处理_第1张图片
        2.하나의 데이터 노드 만 있 는 상황 에서 만약 에 하나의 데이터 노드 가 모든 패키지 데 이 터 를 저장 하지 못 하면 이 노드 의 모든 데 이 터 를 임시 파일 에 기록 합 니 다.파일 에 기록 하면 데이터 노드 는 클 라 이언 트 로부터 패 키 지 를 다시 받 을 수 있 습 니 다.버퍼 가 가득 차 면 다시 파일 에 기록 합 니 다.완전한 패키지 데 이 터 를 받 을 때 까지 순서대로 이 동작 을 수행 합 니 다.이 경우 데 이 터 를 메모리 에 만 저장 할 수 있 도록 지정 하 더 라 도 메모리 버퍼 에 한계 가 있어 모든 패 키 지 를 받 을 수 없습니다.이 때 는 모든 데 이 터 를 임시 파일 에 기록 합 니 다.메모리 레이아웃 은 다음 과 같 습 니 다:
nginx接收包体处理_第2张图片
        3.버퍼 가 두 개의 데이터 노드 로 구성 된다 고 가정 하면 가능 합 니 다.(예 를 들 어 http 요청 머리 를 받 을 때 일부 패키지 데 이 터 를 미리 읽 었 으 나 현재 데이터 노드 가 남 은 패키지 데 이 터 를 저장 할 수 없 음 을 발견 하면 데이터 노드 를 다시 엽 니 다).이러한 상황 에서 ngix.conf 가 데 이 터 를 메모리 에 만 저장 할 수 있 고 두 노드 의 버퍼 가 모든 패키지 데 이 터 를 저장 할 수 있다 면 메모리 레이아웃 은 다음 과 같 습 니 다.
nginx接收包体处理_第3张图片
         4.버퍼 가 두 개의 데이터 노드 로 구성 된다 고 가정 합 니 다.이 경우 ngix.conf 에서 데 이 터 를 파일 에 만 저장 할 수 있 도록 지정 하면 링크 의 모든 데 이 터 를 파일 에 기록 합 니 다.링크 노드 의 버퍼 는 파일 에 해당 하 는 위 치 를 가리킨다.메모리 레이아웃 은 다음 그림 과 같 습 니 다.
nginx接收包体处理_第4张图片
        5.버퍼 가 두 개의 데이터 노드 로 구성 된다 고 가정 합 니 다.이러한 상황 에서 ngix.conf 가 지정 한 패키지 데 이 터 를 파일 에 만 저장 하거나 지정 한 패키지 데 이 터 를 메모리 에 만 저장 할 수 있 습 니 다.이 경우 일부 데 이 터 를 메모리 에 저장 하고 다른 일 부 는 파일 에 저장 할 수 있 습 니 다.두 번 째 노드 버퍼 가 가득 차 면 두 번 째 노드 의 데 이 터 를 파일 에 만 기록 하고 첫 번 째 노드 의 데 이 터 는 변 하지 않 으 며 메모리 에 저 장 됩 니 다.이 때 두 번 째 노드 는 클 라 이언 트 로부터 http 패키지 데 이 터 를 계속 받 을 수 있 습 니 다.버퍼 가 가득 차 면 두 번 째 노드 의 데 이 터 를 파일 에 기록 합 니 다.모든 패 키 지 를 읽 을 때 까지 이러한 절 차 를 순서대로 실행 합 니 다.메모리 레이아웃 은 다음 과 같 습 니 다.링크 에 있 는 데 이 터 는 메모리 에 저장 되 고 다른 데 이 터 는 파일 에 저 장 됩 니 다.
nginx接收包体处理_第5张图片
        이제 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 프레임 워 크 가 패키지 작업 을 어떻게 버 렸 는 지 분석 할 것 입 니 다.

좋은 웹페이지 즐겨찾기