nginx는 http 패키지 본문 처리 예제를 삭제합니다. 자세한 설명
http 프레임워크는 http 요청 패키지 본문을 삭제하고 이전 기사 http 프레임워크는 패키지 본문을 수신합니다. 이는 http 프레임워크에서 제공하는 두 가지 방법으로, 각 http 모듈에서 호출하여 무엇을 할지 결정합니다. 패키지로 하세요. 폐기할지 아니면 수신할지 여부는 모듈에 의해 결정됩니다. 예를 들어, 정적 리소스 모듈이 브라우저로부터 get 요청을 받고 특정 파일을 요청하면 해당 파일의 내용을 브라우저에 직접 반환할 수 있습니다. 패키지 본문 데이터를 수신할 필요가 없으며 가져오기 요청에는 실제로 패키지 본문이 없습니다. 따라서 정적 리소스 모듈은 http 프레임워크에서 제공하는 패킷 폐기 처리 기능을 호출하여 패킷 폐기 처리를 수행합니다.
패키지 본문을 수신하는 과정에 비해 패키지 본문을 삭제하는 작업이 훨씬 간단합니다. 적어도 http 구조의 request_body 버퍼에 패키지 본문을 저장할 필요는 없습니다. 패키지 바디가 메모리에만 저장되는지, 아니면 메모리에만 저장되는지 고려하세요. 파일 등에 문제가 있는 경우 프레임워크는 패키지 바디를 받은 후 바로 폐기합니다. 폐기된 패킷 본문은 다음 세 부분으로 구성됩니다.
(1) http 모듈은 처음으로 프레임워크에서 제공하는 ngx_http_discard_request_body 함수를 호출하여 일부 초기 작업을 수행합니다. 화 작업. 예를 들어, 한 번의 작업으로 모든 패킷 바디를 버릴 수 없는 경우 읽기 이벤트를 다시 epoll에 등록해야 다시 실행이 예약될 때 패킷 버리는 작업을 계속할 수 있습니다. 또한 실제 패킷 폐기 함수 ngx_http_read_discarded_request_body를 호출하여 패킷 본문을 폐기합니다.
(2) 한 번의 작업으로 모든 패킷 본문을 삭제할 수 없는 경우 이벤트가 다시 예약될 때 나머지 패킷 데이터는 계속 수신된 후 삭제됩니다.
(3) 실제 패킷 손실 처리, 즉 패킷을 수신한 후 본문을 직접 폐기하는 것입니다.
그림을 보면 이 세 가지 프로세스 중 패킷 손실 프로세스가 공통 기능임을 알 수 있습니다. 즉, http 모듈이 ngx_http_discard_request_body 함수를 호출하여 패킷 손실 처리를 시작하는지, 아니면 전체 패킷 본문이 하나의 일정으로 수신되지 않는지, ngx_http_discarded_request_body_handler가 나머지 패킷 본문 작업을 폐기하는 역할을 담당하고, 공용 패킷 손실 함수 ngx_http_read_discarded_request_body 패킷 본문을 직접 수신하기 위해 호출됩니다.
1. 패킷 폐기 초기화 프로세스
ngx_http_discard_request_body는 패킷 본문을 폐기하기 위해 http 모듈에서 호출되는 함수입니다. 이는 모듈에 대한 투명한 작업입니다. 즉, 모듈은 http 프레임워크가 이 인터페이스를 구현하는 방법을 알지 못한 채 http 요청 패킷 본문을 삭제하기 위해 이 인터페이스만 호출하면 됩니다. 프레임워크가 한 번의 스케줄링에서 모든 패킷 바디를 폐기하지 않더라도 다음 스케줄링이 실행될 때 패킷 폐기 작업이 다시 수행되지만 모듈은 이를 알지 못합니다. ㅠㅠ 그런데 http 패키지 본문 데이터도 수신한 경우에는 이때 패키지 본문이 성공적으로 삭제되면 나머지 작업을 계속 수행할 필요가 없습니다. 모든 패킷 본문이 하나의 일정에서 삭제되지 않으면 http 요청 구조 ngx_http_request_s의 읽기 이벤트 read_event_handler가 ngx_http_discarded_request_body_handler로 설정됩니다. 이 함수는 다음에 예약될 때 나머지 패킷 본문을 삭제하는 역할을 합니다. 따라서 ngx_http_discard_request_body는 http 모듈에 의해 처음으로만 호출됩니다.
이 함수는 실제 패킷 손실 함수 ngx_http_read_discarded_request_body를 호출하여 패킷 본문 수신을 시작하고 직접 폐기합니다.
2. 패킷 손실 처리
ngx_http_read_discarded_request_body 함수는 클라이언트로부터 패킷 본문 데이터를 수신한 후 폐기하는 기능을 담당합니다. 따라서 모듈의 경우 패키지 바디를 폐기하는 동작이지만 프레임워크의 경우 패키지 바디를 폐기하는 동작은 실제로 패키지 바디를 수신하는 동작이지만 수신된 패키지 바디 데이터를 모듈에 제공하지 않습니다. 사용하기위한. 프레임워크가 패키지 본문을 수신한 다음 직접 폐기해야 하는 이유는 무엇입니까? 그렇지 않은데 이렇게 된 데에는 이유가 있습니다. 견고하지 않은 클라이언트 브라우저가 차단 방법을 사용하여 http 패킷 본문 데이터를 nginx 서버로 전송한다고 가정합니다. nginx 프레임워크가 이를 수신하지 못하면 클라이언트 브라우저가 시간 초과되어 응답하지 않게 되어 클라이언트 브라우저가 닫힙니다. 연결. . 따라서 nginx의 http 프레임워크는 먼저 커널로부터 클라이언트로부터 패키지 본문 데이터를 받아야 하지만 이 데이터는 모듈에 쓸모가 없으므로 수신된 데이터는 직접 폐기됩니다.
//功能: 从内核中读取数据到nginx中,nginx不对收到的数据进行处理。相当于丢弃包体 static ngx_int_t ngx_http_read_discarded_request_body(ngx_http_request_t *r) { //用于接收包体的临时缓冲区 u_char buffer[ngx_http_discard_buffer_size]; for ( ;; ) { //已经全部丢弃成功 if (r->headers_in.content_length_n == 0) { //设置丢弃后的读事件回调,再有读事件时,不做任何处理 r->read_event_handler = ngx_http_block_reading; return ngx_ok; } //从内核中接收包体到临时缓冲区 n = r->connection->recv(r->connection, buffer, size); //更新剩余需要接收的包体大小 r->headers_in.content_length_n -= n; } }
函数内部只是使用一个临时的缓冲区变量存放每次接收来自内核的包体数据。并没有把这部分数据保存到http请求结构中的request_body缓冲区。因此包体数据没有交给http模块,相当于被丢弃了。在所有包体从内核中接收完成时,设置http请求结构ngx_http_request_s的读事件read_event_handler回调设置为: ngx_http_block_reading, 表示再收到来自客户端的数据,则不进行任何处理了。因为已经接收完所有的包体数据,也就不需要理会来自客户端浏览器的其它数据。
三、丢弃剩余的包体
ngx_http_discarded_request_body_handler用于在一次调度中没有丢弃完所有包体,则该函数会表调用,用于丢弃剩余的包体。函数内部也会调用实际的丢弃包体函数,进行接收包体然后丢弃操作。nginx服务器做了一个优化处理,会设置一个总超时时间,如果超过这个时间都还没有丢弃完全部的包体,则会关闭这个连接。这是一种对服务器保护的措施,避免长时间的丢包操作占用服务器资源。
//功能: 第1次未能全部丢弃包体时,该函数被调用。之后有读事件时,该函数被调用 void ngx_http_discarded_request_body_handler(ngx_http_request_t *r) { //检测延迟关闭时间,如果总时长超过了lingering_time,则不再接收任何包体,这是一个总时间。 //总超时后,将直接光比连接 if (r->lingering_time) { timer = (ngx_msec_t) (r->lingering_time - ngx_time()); //已经到达了延迟关闭时间 if (timer <= 0) { //清空丢弃包体标识,表示包体已经丢弃 r->discard_body = 0; //延迟关闭开关清0 r->lingering_close = 0; ngx_http_finalize_request(r, ngx_error); return; } } //接收包体后丢弃 rc = ngx_http_read_discarded_request_body(r); //表示包体已经全部丢弃 if (rc == ngx_ok) { r->discard_body = 0; //包体已经全部接收完 r->lingering_close = 0; //清空延迟关闭标志 ngx_http_finalize_request(r, ngx_done); return; } }
ngx_http_discarded_request_body_handler这个函数是怎么被事件对象调用的呢? 在前面的文章已经分析了,ngx_connection_s读事件的回调设置为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 } }
위 내용은 http 패킷 본문을 폐기하는 Nginx를 처리하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!