12.6.3 接收包体的流程

本节介绍的实际就是ngx_http_upstream_process_body_in_memory方法的执行流程,它会负责接收上游服务器的包体,同时调用HTTP模块实现的input_filter方法处理包体,如图12-6所示。

12.6.3 接收包体的流程 - 图1

图 12-6 ngx_http_upstream_process_body_in_memory方法的流程图

下面分析图12-6,了解一下在内存中处理包体的流程。

1)首先要检查Nginx接收上游服务器的响应是否超时,也就是检查读事件的timedout标志位。如果timedout为1,则表示读取响应超时,这时跳到第2步调用ngx_http_upstream_finalize_request方法结束请求,传递的参数是NGX_ETIMEDOUT(详见12.9.3节);如果timedout为0,则继续执行第3步。

2)调用ngx_http_upstream_finalize_request方法结束请求,该方法类似于ngx_http_finalize_request方法,它们都需要一个rc参数,来决定该方法的行为。

3)在保存着响应包体的buffer缓冲区中,last成员指向空闲内存块的地址(下次还会由last处开始接收响应包体),而end成员指向缓冲区的结尾,用end-last即可计算出剩余空闲内存。如果缓冲区全部用尽,则跳到第2步调用ngx_http_upstream_finalize_request方法结束请求;如果还有空闲缓冲区,则跳到第4步接收包体。

4)调用recv方法接收上游服务器的响应,接收到的内容存放在buffer缓冲区的last成员指向的内存中。检查recv的返回值,不同的返回值会导致3种结果:如果返回NGX_AGAIN,则表示期待下一次的读事件,这时跳到第6步执行;如果返回NGX_ERROR或者上游服务器主动关闭连接,则跳到第2步结束请求;如果返回正数,则表示接收到的响应长度,这时跳到第5步处理包体。

5)调用HTTP模块实现的input_filter方法处理本次接收到的包体。检测input_filter方法的返回值,返回NGX_ERROR时跳到第2步结束请求。否则,再检测读事件的ready标志位,如果ready为1,则表示仍有TCP流可以读取,这时跳到第3步执行;如果ready为0,则跳到第6步执行。

6)调用ngx_handle_read_event方法将读事件添加到epoll中。

7)调用ngx_add_timer方法将读事件添加到定时器中,超时时间为ngx_http_upstream_conf_t配置结构体中的read_timeout成员。

在内存中处理包体的关键在于如何实现input_filter方法,特别是在该方法中对buffer缓冲区的管理。如果上游服务器的响应包体非常小,可以考虑本节说明的这种方式,它的效率很高。