diff --git a/nginx-1.9.2/src/http/ngx_http_write_filter_module.c b/nginx-1.9.2/src/http/ngx_http_write_filter_module.c index 887dce17..5a903f7c 100755 --- a/nginx-1.9.2/src/http/ngx_http_write_filter_module.c +++ b/nginx-1.9.2/src/http/ngx_http_write_filter_module.c @@ -28,62 +28,62 @@ static ngx_http_module_t ngx_http_write_filter_module_ctx = { }; /* -表6-1 默认即编译进Nginx的HTTP过滤模块 -┏━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ -┃默认即编译进Nginx的HTTP过滤模块 ┃ 功能 ┃ -┣━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫ -┃ ┃ 仅对HTTP头部做处理。在返回200成功时,根据请求中If- ┃ -┃ ┃Modified-Since或者If-Unmodified-Since头部取得浏览器缓存文件的时 ┃ -┃ngx_http_not_modified_filter_module ┃ ┃ -┃ ┃间,再分析返回用户文件的最后修改时间,以此决定是否直接发送304 ┃ -┃ ┃ Not Modified响应给用户 ┃ -┣━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫ -┃ ┃ 处理请求中的Range信息,根据Range中的要求返回文件的一部分给 ┃ -┃ngx_http_range_body_filter_module ┃ ┃ -┃ ┃用户 ┃ -┣━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫ -┃ ┃ 仅对HTTP包体做处理。将用户发送的ngx_chain_t结构的HTTP包 ┃ -┃ ┃体复制到新的ngx_chain_t结构中(都是各种指针的复制,不包括实际 ┃ -┃ngx_http_copy_filter_module ┃ ┃ -┃ ┃HTTP响应内容),后续的HTTP过滤模块处埋的ngx_chain_t类型的成 ┃ -┃ ┃员都是ngx_http_copy_filter_module模块处理后的变量 ┃ -┣━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫ -┃ ┃ 仅对HTTP头部做处理。允许通过修改nginx.conf配置文件,在返回 ┃ -┃ngx_http_headers_filter_module ┃ ┃ -┃ ┃给用户的响应中添加任意的HTTP头部 ┃ -┣━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫ -┃ ┃ 仅对HTTP头部做处理。这就是执行configure命令时提到的http_ ┃ -┃ngx_http_userid_filter_module ┃ ┃ -┃ ┃userid module模块,它基于cookie提供了简单的认证管理功能 ┃ -┣━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫ -┃ ┃ 可以将文本类型返回给用户的响应包,按照nginx.conf中的配置重新 ┃ -┃ngx_http_charset_filter_module ┃ ┃ -┃ ┃进行编码,再返回给用户 ┃ -┣━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫ -┃ ┃ 支持SSI(Server Side Include,服务器端嵌入)功能,将文件内容包 ┃ -┃ngx_http_ssi_filter_module ┃ ┃ -┃ ┃含到网页中并返回给用户 ┃ -┣━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫ -┃ ┃ 仅对HTTP包体做处理。 它仅应用于 ┃ -┃ngx_http_postpone_filter_module ┃subrequest产生的子请求。它使得多个子请求同时向客户端发送响应时 ┃ -┃ ┃能够有序,所谓的“有序”是揩按照构造子请求的顺序发送响应 ┃ -┣━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫ -┃ ┃ 对特定的HTTP响应包体(如网页或者文本文件)进行gzip压缩,再 ┃ -┃ngx_http_gzip_filter_module ┃ ┃ -┃ ┃把压缩后的内容返回给用户 ┃ -┣━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫ -┃ngx_http_range_header_filter_module ┃ 支持range协议 ┃ -┣━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫ -┃ngx_http_chunked_filter_module ┃ 支持chunk编码 ┃ -┣━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫ -┃ ┃ 仅对HTTP头部做处理。该过滤模块将会把r->headers out结构体 ┃ -┃ ┃中的成员序列化为返回给用户的HTTP响应字符流,包括响应行(如 ┃ -┃ngx_http_header_filter_module ┃ ┃ -┃ ┃HTTP/I.1 200 0K)和响应头部,并通过调用ngx_http_write filter ┃ -┃ ┃ module过滤模块中的过滤方法直接将HTTP包头发送到客户端 ┃ -┣━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫ -┃ngx_http_write_filter_module ┃ 仅对HTTP包体做处理。该模块负责向客户端发送HTTP响应 ┃ -┗━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ +琛6-1 榛樿鍗崇紪璇戣繘Nginx鐨凥TTP杩囨护妯″潡 +鈹忊攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲敵鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲敁 +鈹冮粯璁ゅ嵆缂栬瘧杩汵ginx鐨凥TTP杩囨护妯″潡 鈹 鍔熻兘 鈹 +鈹b攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲晪鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲敨 +鈹 鈹 浠呭HTTP澶撮儴鍋氬鐞嗐傚湪杩斿洖200鎴愬姛鏃讹紝鏍规嵁璇锋眰涓璉f- 鈹 +鈹 鈹僊odified-Since鎴栬匢f-Unmodified-Since澶撮儴鍙栧緱娴忚鍣ㄧ紦瀛樻枃浠剁殑鏃 鈹 +鈹僴gx_http_not_modified_filter_module 鈹 鈹 +鈹 鈹冮棿锛屽啀鍒嗘瀽杩斿洖鐢ㄦ埛鏂囦欢鐨勬渶鍚庝慨鏀规椂闂达紝浠ユ鍐冲畾鏄惁鐩存帴鍙戦304 鈹 +鈹 鈹 Not Modified鍝嶅簲缁欑敤鎴 鈹 +鈹b攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲晪鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲敨 +鈹 鈹 澶勭悊璇锋眰涓殑Range淇℃伅锛屾牴鎹甊ange涓殑瑕佹眰杩斿洖鏂囦欢鐨勪竴閮ㄥ垎缁 鈹 +鈹僴gx_http_range_body_filter_module 鈹 鈹 +鈹 鈹冪敤鎴 鈹 +鈹b攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲晪鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲敨 +鈹 鈹 浠呭HTTP鍖呬綋鍋氬鐞嗐傚皢鐢ㄦ埛鍙戦佺殑ngx_chain_t缁撴瀯鐨凥TTP鍖 鈹 +鈹 鈹冧綋澶嶅埗鍒版柊鐨刵gx_chain_t缁撴瀯涓紙閮芥槸鍚勭鎸囬拡鐨勫鍒讹紝涓嶅寘鎷疄闄 鈹 +鈹僴gx_http_copy_filter_module 鈹 鈹 +鈹 鈹僅TTP鍝嶅簲鍐呭锛夛紝鍚庣画鐨凥TTP杩囨护妯″潡澶勫煁鐨刵gx_chain_t绫诲瀷鐨勬垚 鈹 +鈹 鈹冨憳閮芥槸ngx_http_copy_filter_module妯″潡澶勭悊鍚庣殑鍙橀噺 鈹 +鈹b攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲晪鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲敨 +鈹 鈹 浠呭HTTP澶撮儴鍋氬鐞嗐傚厑璁搁氳繃淇敼nginx.conf閰嶇疆鏂囦欢锛屽湪杩斿洖 鈹 +鈹僴gx_http_headers_filter_module 鈹 鈹 +鈹 鈹冪粰鐢ㄦ埛鐨勫搷搴斾腑娣诲姞浠绘剰鐨凥TTP澶撮儴 鈹 +鈹b攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲晪鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲敨 +鈹 鈹 浠呭HTTP澶撮儴鍋氬鐞嗐傝繖灏辨槸鎵цconfigure鍛戒护鏃舵彁鍒扮殑http_ 鈹 +鈹僴gx_http_userid_filter_module 鈹 鈹 +鈹 鈹僽serid module妯″潡锛屽畠鍩轰簬cookie鎻愪緵浜嗙畝鍗曠殑璁よ瘉绠$悊鍔熻兘 鈹 +鈹b攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲晪鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲敨 +鈹 鈹 鍙互灏嗘枃鏈被鍨嬭繑鍥炵粰鐢ㄦ埛鐨勫搷搴斿寘锛屾寜鐓ginx锛巆onf涓殑閰嶇疆閲嶆柊 鈹 +鈹僴gx_http_charset_filter_module 鈹 鈹 +鈹 鈹冭繘琛岀紪鐮侊紝鍐嶈繑鍥炵粰鐢ㄦ埛 鈹 +鈹b攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲晪鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲敨 +鈹 鈹 鏀寔SSI锛圫erver Side Include锛屾湇鍔″櫒绔祵鍏ワ級鍔熻兘锛屽皢鏂囦欢鍐呭鍖 鈹 +鈹僴gx_http_ssi_filter_module 鈹 鈹 +鈹 鈹冨惈鍒扮綉椤典腑骞惰繑鍥炵粰鐢ㄦ埛 鈹 +鈹b攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲晪鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲敨 +鈹 鈹 浠呭HTTP鍖呬綋鍋氬鐞嗐 瀹冧粎搴旂敤浜 鈹 +鈹僴gx_http_postpone_filter_module 鈹僺ubrequest浜х敓鐨勫瓙璇锋眰銆傚畠浣垮緱澶氫釜瀛愯姹傚悓鏃跺悜瀹㈡埛绔彂閫佸搷搴旀椂 鈹 +鈹 鈹冭兘澶熸湁搴忥紝鎵璋撶殑鈥滄湁搴忊濇槸鎻╂寜鐓ф瀯閫犲瓙璇锋眰鐨勯『搴忓彂閫佸搷搴 鈹 +鈹b攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲晪鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲敨 +鈹 鈹 瀵圭壒瀹氱殑HTTP鍝嶅簲鍖呬綋锛堝缃戦〉鎴栬呮枃鏈枃浠讹級杩涜gzip鍘嬬缉锛屽啀 鈹 +鈹僴gx_http_gzip_filter_module 鈹 鈹 +鈹 鈹冩妸鍘嬬缉鍚庣殑鍐呭杩斿洖缁欑敤鎴 鈹 +鈹b攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲晪鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲敨 +鈹僴gx_http_range_header_filter_module 鈹 鏀寔range鍗忚 鈹 +鈹b攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲晪鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲敨 +鈹僴gx_http_chunked_filter_module 鈹 鏀寔chunk缂栫爜 鈹 +鈹b攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲晪鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲敨 +鈹 鈹 浠呭HTTP澶撮儴鍋氬鐞嗐傝杩囨护妯″潡灏嗕細鎶妑->headers out缁撴瀯浣 鈹 +鈹 鈹冧腑鐨勬垚鍛樺簭鍒楀寲涓鸿繑鍥炵粰鐢ㄦ埛鐨凥TTP鍝嶅簲瀛楃娴侊紝鍖呮嫭鍝嶅簲琛(濡 鈹 +鈹僴gx_http_header_filter_module 鈹 鈹 +鈹 鈹僅TTP/I.1 200 0K)鍜屽搷搴斿ご閮紝骞堕氳繃璋冪敤ngx_http_write filter 鈹 +鈹 鈹 module杩囨护妯″潡涓殑杩囨护鏂规硶鐩存帴灏咹TTP鍖呭ご鍙戦佸埌瀹㈡埛绔 鈹 +鈹b攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲晪鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲敨 +鈹僴gx_http_write_filter_module 鈹 浠呭HTTP鍖呬綋鍋氬鐞嗐傝妯″潡璐熻矗鍚戝鎴风鍙戦丠TTP鍝嶅簲 鈹 +鈹椻攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲敾鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲攣鈹佲敍 */ngx_module_t ngx_http_write_filter_module = { NGX_MODULE_V1, @@ -101,19 +101,19 @@ static ngx_http_module_t ngx_http_write_filter_module_ctx = { }; /* -ngx_http_header_filter发送头部内容是通过调用ngx_http_write_filter方法来发送响应头部的。事实上,这个方法是包体过滤模块链表中的 -最后一个模块ngx_http_write_filter_module的处理方法,当HTTP模块调用ngx_http_output_filter方法发送包体时,最终也是通过该方法发送响应的 -。当一次无法发送全部的缓冲区内容时,ngx_http_write_filter方法是会返回NGX_AGAIN的(同时将未发送完成的缓冲区放到请求的out成员 -中),也就是说,发送响应头部的ngx_http_header_filter方法会返回NGX_AGAIN。如果不需要再发送包体,那么这时就需要调用 -ngx_http_finalize_request方法来结束请求,其中第2个参数务必要传递NGX_AGAIN,这样HTTP框架才会继续将可写事件注册到epoll,并持 -续地把请求的out成员中缓冲区里的HTTP响应发送完毕才会结束请求。 -*/ //发送数据的时候调用ngx_http_write_filter写数据,如果返回NGX_AGAIN,则以后的写数据触发通过在ngx_http_writer添加epoll write事件来触发 +ngx_http_header_filter鍙戦佸ご閮ㄥ唴瀹规槸閫氳繃璋冪敤ngx_http_write_filter鏂规硶鏉ュ彂閫佸搷搴斿ご閮ㄧ殑銆備簨瀹炰笂锛岃繖涓柟娉曟槸鍖呬綋杩囨护妯″潡閾捐〃涓殑 +鏈鍚庝竴涓ā鍧梟gx_http_write_filter_module鐨勫鐞嗘柟娉曪紝褰揌TTP妯″潡璋冪敤ngx_http_output_filter鏂规硶鍙戦佸寘浣撴椂锛屾渶缁堜篃鏄氳繃璇ユ柟娉曞彂閫佸搷搴旂殑 +銆傚綋涓娆℃棤娉曞彂閫佸叏閮ㄧ殑缂撳啿鍖哄唴瀹规椂锛宯gx_http_write_filter鏂规硶鏄細杩斿洖NGX_AGAIN鐨勶紙鍚屾椂灏嗘湭鍙戦佸畬鎴愮殑缂撳啿鍖烘斁鍒拌姹傜殑out鎴愬憳 +涓級锛屼篃灏辨槸璇达紝鍙戦佸搷搴斿ご閮ㄧ殑ngx_http_header_filter鏂规硶浼氳繑鍥濶GX_AGAIN銆傚鏋滀笉闇瑕佸啀鍙戦佸寘浣擄紝閭d箞杩欐椂灏遍渶瑕佽皟鐢 +ngx_http_finalize_request鏂规硶鏉ョ粨鏉熻姹傦紝鍏朵腑绗2涓弬鏁板姟蹇呰浼犻扤GX_AGAIN锛岃繖鏍稨TTP妗嗘灦鎵嶄細缁х画灏嗗彲鍐欎簨浠舵敞鍐屽埌epoll锛屽苟鎸 +缁湴鎶婅姹傜殑out鎴愬憳涓紦鍐插尯閲岀殑HTTP鍝嶅簲鍙戦佸畬姣曟墠浼氱粨鏉熻姹傘 +*/ //鍙戦佹暟鎹殑鏃跺欒皟鐢╪gx_http_write_filter鍐欐暟鎹紝濡傛灉杩斿洖NGX_AGAIN,鍒欎互鍚庣殑鍐欐暟鎹Е鍙戦氳繃鍦╪gx_http_writer娣诲姞epoll write浜嬩欢鏉ヨЕ鍙 ngx_int_t ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in) -//ngx_http_write_filter把in中的数据拼接到out后面,然后调用writev发送,没有发送完的数据最后留在out中 -{//将r->out里面的数据,和参数里面的数据一并以writev的机制发送给客户端,如果没有发送完所有的,则将剩下的放在r->out +//ngx_http_write_filter鎶奿n涓殑鏁版嵁鎷兼帴鍒皁ut鍚庨潰锛岀劧鍚庤皟鐢╳ritev鍙戦侊紝娌℃湁鍙戦佸畬鐨勬暟鎹渶鍚庣暀鍦╫ut涓 +{//灏唕->out閲岄潰鐨勬暟鎹紝鍜屽弬鏁伴噷闈㈢殑鏁版嵁涓骞朵互writev鐨勬満鍒跺彂閫佺粰瀹㈡埛绔紝濡傛灉娌℃湁鍙戦佸畬鎵鏈夌殑锛屽垯灏嗗墿涓嬬殑鏀惧湪r->out -//调用ngx_http_write_filter写数据,如果返回NGX_AGAIN,则以后的写数据触发通过在ngx_http_set_write_handler->ngx_http_writer添加epoll write事件来触发 +//璋冪敤ngx_http_write_filter鍐欐暟鎹紝濡傛灉杩斿洖NGX_AGAIN,鍒欎互鍚庣殑鍐欐暟鎹Е鍙戦氳繃鍦╪gx_http_set_write_handler->ngx_http_writer娣诲姞epoll write浜嬩欢鏉ヨЕ鍙 off_t size, sent, nsent, limit; ngx_uint_t last, flush, sync; @@ -123,7 +123,7 @@ ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in) ngx_http_core_loc_conf_t *clcf; c = r->connection; - //如果error为1表示请求出错,那么直接返回NGX_ERROR + //濡傛灉error涓1琛ㄧず璇锋眰鍑洪敊锛岄偅涔堢洿鎺ヨ繑鍥濶GX_ERROR if (c->error) { return NGX_ERROR; } @@ -135,10 +135,10 @@ ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in) ll = &r->out; /* find the size, the flush point and the last link of the saved chain */ -//找到请求的ngx_http_request_t结构体中存放的等待发送的缓冲区链表out,遍历这个ngx_chain_t类型的缓冲区链表, -//计算出out缓冲区共占用了多大的字节数,这个out链表通常都保存着待发送的响应。例如,在调用ngx_http_send header方法时, -//如果HTTP响应头部过大导致无法一次性发送完,那么剩余的响应头部就会在out链表中。 - for (cl = r->out; cl; cl = cl->next) { //out里面是上次发送没有发送完的内容 +//鎵惧埌璇锋眰鐨刵gx_http_request_t缁撴瀯浣撲腑瀛樻斁鐨勭瓑寰呭彂閫佺殑缂撳啿鍖洪摼琛╫ut锛岄亶鍘嗚繖涓猲gx_chain_t绫诲瀷鐨勭紦鍐插尯閾捐〃锛 +//璁$畻鍑簅ut缂撳啿鍖哄叡鍗犵敤浜嗗澶х殑瀛楄妭鏁帮紝杩欎釜out閾捐〃閫氬父閮戒繚瀛樼潃寰呭彂閫佺殑鍝嶅簲銆備緥濡傦紝鍦ㄨ皟鐢╪gx_http_send header鏂规硶鏃讹紝 +//濡傛灉HTTP鍝嶅簲澶撮儴杩囧ぇ瀵艰嚧鏃犳硶涓娆℃у彂閫佸畬锛岄偅涔堝墿浣欑殑鍝嶅簲澶撮儴灏变細鍦╫ut閾捐〃涓 + for (cl = r->out; cl; cl = cl->next) { //out閲岄潰鏄笂娆″彂閫佹病鏈夊彂閫佸畬鐨勫唴瀹 ll = &cl->next; ngx_log_debug7(NGX_LOG_DEBUG_EVENT, c->log, 0, @@ -186,8 +186,8 @@ ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in) } /* add the new chain to the existent one */ - //遍历这个ngx_chain_t类型的缓存链表in,将in中的缓冲区加入到out链表的末尾,并计算out缓冲区共占用多大的字节数 - for (ln = in; ln; ln = ln->next) { //in表示这次新加进来需要发送的内容 + //閬嶅巻杩欎釜ngx_chain_t绫诲瀷鐨勭紦瀛橀摼琛╥n锛屽皢in涓殑缂撳啿鍖哄姞鍏ュ埌out閾捐〃鐨勬湯灏撅紝骞惰绠梠ut缂撳啿鍖哄叡鍗犵敤澶氬ぇ鐨勫瓧鑺傛暟 + for (ln = in; ln; ln = ln->next) { //in琛ㄧず杩欐鏂板姞杩涙潵闇瑕佸彂閫佺殑鍐呭 cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return NGX_ERROR; @@ -197,7 +197,7 @@ ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in) *ll = cl; ll = &cl->next; -//注意从后端接收的数据到缓存文件中后,在filter模块中,有可能是新的buf数据指针了,因为ngx_http_copy_filter->ngx_output_chain中会重新分配内存读取缓存文件内容 +//娉ㄦ剰浠庡悗绔帴鏀剁殑鏁版嵁鍒扮紦瀛樻枃浠朵腑鍚庯紝鍦╢ilter妯″潡涓紝鏈夊彲鑳芥槸鏂扮殑buf鏁版嵁鎸囬拡浜嗭紝鍥犱负ngx_http_copy_filter->ngx_output_chain涓細閲嶆柊鍒嗛厤鍐呭瓨璇诲彇缂撳瓨鏂囦欢鍐呭 ngx_log_debug7(NGX_LOG_DEBUG_EVENT, c->log, 0, "write new buf temporary:%d buf-in-file:%d, buf->start:%p, buf->pos:%p, buf_size: %z " "file_pos: %O, in_file_size: %O", @@ -264,8 +264,8 @@ Connection: keep-alive 2025/02/08 00:56:18 [debug] 13330#0: *1 write new buf t:1 f:0 080E68BC, pos 080E68BC, size: 147 file: 0, size: 0 2025/02/08 00:56:18 [debug] 13330#0: *1 http write filter: l:0 f:0 s:147 -2025/02/08 00:56:18 [debug] 13330#0: *1 http output filter "/mytest?" //这前面的都是头部打印,注意到实际上并没有writev,而是和下面的包体一起writev的 -2025/02/08 00:56:18 [debug] 13330#0: *1 http copy filter: "/mytest?" //ngx_http_copy_filter函数开始 +2025/02/08 00:56:18 [debug] 13330#0: *1 http output filter "/mytest?" //杩欏墠闈㈢殑閮芥槸澶撮儴鎵撳嵃锛屾敞鎰忓埌瀹為檯涓婂苟娌℃湁writev锛岃屾槸鍜屼笅闈㈢殑鍖呬綋涓璧穡ritev鐨 +2025/02/08 00:56:18 [debug] 13330#0: *1 http copy filter: "/mytest?" //ngx_http_copy_filter鍑芥暟寮濮 2025/02/08 00:56:18 [debug] 13330#0: *1 http postpone filter "/mytest?" 080E6A40 2025/02/08 00:56:18 [debug] 13330#0: *1 write old buf t:1 f:0 080E68BC, pos 080E68BC, size: 147 file: 0, size: 0 2025/02/08 00:56:18 [debug] 13330#0: *1 write new buf t:1 f:0 080C82EC, pos 080C82EC, size: 18 file: 0, size: 0 @@ -274,7 +274,7 @@ Connection: keep-alive 2025/02/08 00:56:18 [debug] 13330#0: *1 http write filter limit 0 2025/02/08 00:56:18 [debug] 13330#0: *1 writev: 190 of 190 2025/02/08 00:56:18 [debug] 13330#0: *1 http write filter 00000000 - 2025/02/08 00:56:18 [debug] 13330#0: *1 http copy filter: 0 "/mytest?" //ngx_http_copy_filter函数结尾,也就是中间的filter都是在ngx_http_copy_filter调用执行的 + 2025/02/08 00:56:18 [debug] 13330#0: *1 http copy filter: 0 "/mytest?" //ngx_http_copy_filter鍑芥暟缁撳熬锛屼篃灏辨槸涓棿鐨刦ilter閮芥槸鍦╪gx_http_copy_filter璋冪敤鎵ц鐨 2025/02/08 00:56:18 [debug] 13330#0: *1 http finalize request: 0, "/mytest?" a:1, c:1 2025/02/08 00:56:18 [debug] 13330#0: *1 set http keepalive handler 2025/02/08 00:56:18 [debug] 13330#0: *1 http close request @@ -282,26 +282,26 @@ Connection: keep-alive */ /* - 3个标志位同时为0(即待发送的out链表中没有一个缓冲区表示响应已经结束或需要立刻发送出去),而且本次要发送的缓冲区in虽然不为空, - 但以上两步骤中计算出的待发送响应的大小又小于配置文件中的postpone_output参数,那么说明当前的缓冲区是不完整的且没有必要立刻发送 - */ //例如如果有头部,又有包体,则一般最尾部的头部filter函数ngx_http_header_filter->ngx_http_write_filter到这里的时候一般头部字段 - //过少,这里直接返回NGX_OK,这样就可以让头部和包体在最尾部的包体filter函数ngx_http_write_filter->ngx_http_write_filter和包体在一个报文中发送出去 + 3涓爣蹇椾綅鍚屾椂涓0锛堝嵆寰呭彂閫佺殑out閾捐〃涓病鏈変竴涓紦鍐插尯琛ㄧず鍝嶅簲宸茬粡缁撴潫鎴栭渶瑕佺珛鍒诲彂閫佸嚭鍘伙級锛岃屼笖鏈瑕佸彂閫佺殑缂撳啿鍖篿n铏界劧涓嶄负绌猴紝 + 浣嗕互涓婁袱姝ラ涓绠楀嚭鐨勫緟鍙戦佸搷搴旂殑澶у皬鍙堝皬浜庨厤缃枃浠朵腑鐨刾ostpone_output鍙傛暟锛岄偅涔堣鏄庡綋鍓嶇殑缂撳啿鍖烘槸涓嶅畬鏁寸殑涓旀病鏈夊繀瑕佺珛鍒诲彂閫 + */ //渚嬪濡傛灉鏈夊ご閮紝鍙堟湁鍖呬綋锛屽垯涓鑸渶灏鹃儴鐨勫ご閮╢ilter鍑芥暟ngx_http_header_filter->ngx_http_write_filter鍒拌繖閲岀殑鏃跺欎竴鑸ご閮ㄥ瓧娈 + //杩囧皯锛岃繖閲岀洿鎺ヨ繑鍥濶GX_OK锛岃繖鏍峰氨鍙互璁╁ご閮ㄥ拰鍖呬綋鍦ㄦ渶灏鹃儴鐨勫寘浣揻ilter鍑芥暟ngx_http_write_filter->ngx_http_write_filter鍜屽寘浣撳湪涓涓姤鏂囦腑鍙戦佸嚭鍘 if (!last && !flush && in && size < (off_t) clcf->postpone_output) { ngx_log_debugall(c->log, 0, "send size:%O < min postpone_output:%O, do not send", size, (off_t) clcf->postpone_output); - //如果last flush都等于0,并且in不为NULL,并且输出链中的数据小于postpone_output,则直接返回,表示等数据跟多(达到postpone_output),或者指定last flush则输出 + //濡傛灉last flush閮界瓑浜0锛屽苟涓攊n涓嶄负NULL锛屽苟涓旇緭鍑洪摼涓殑鏁版嵁灏忎簬postpone_output锛屽垯鐩存帴杩斿洖锛岃〃绀虹瓑鏁版嵁璺熷(杈惧埌postpone_output)锛屾垨鑰呮寚瀹歭ast flush鍒欒緭鍑 return NGX_OK; } /* - 首先检查连接上写事件的标志位delayed,如果delayed为1,则表示这一次的epoll调度中请求仍需要减速,是不可以发送响应的,delayed为1 - 指明了响应需要延迟发送;如果delayed为0,表示本次不需要减速,那么再检查ngx_http_request_t结构体中的limit_rate - 发送响应的速率,如果limit_rate为0,表示这个请求不需要限制发送速度;如果limit rate大干0,则说明发送响应的速度不能超过limit_rate指定的速度。 + 棣栧厛妫鏌ヨ繛鎺ヤ笂鍐欎簨浠剁殑鏍囧織浣峝elayed锛屽鏋渄elayed涓1锛屽垯琛ㄧず杩欎竴娆$殑epoll璋冨害涓姹備粛闇瑕佸噺閫燂紝鏄笉鍙互鍙戦佸搷搴旂殑锛宒elayed涓1 + 鎸囨槑浜嗗搷搴旈渶瑕佸欢杩熷彂閫侊紱濡傛灉delayed涓0锛岃〃绀烘湰娆′笉闇瑕佸噺閫燂紝閭d箞鍐嶆鏌gx_http_request_t缁撴瀯浣撲腑鐨刲imit_rate + 鍙戦佸搷搴旂殑閫熺巼锛屽鏋渓imit_rate涓0锛岃〃绀鸿繖涓姹備笉闇瑕侀檺鍒跺彂閫侀熷害锛涘鏋渓imit rate澶у共0锛屽垯璇存槑鍙戦佸搷搴旂殑閫熷害涓嶈兘瓒呰繃limit_rate鎸囧畾鐨勯熷害銆 */ - if (c->write->delayed) { //在后面的限速中置1 -//将客户端对应的buffered标志位放上NGX_HTTP_WRITE_BUFFERED宏,同时返回NGX AGAIN,这是在告诉HTTP框架out缓冲区中还有响应等待发送。 + if (c->write->delayed) { //鍦ㄥ悗闈㈢殑闄愰熶腑缃1 +//灏嗗鎴风瀵瑰簲鐨刡uffered鏍囧織浣嶆斁涓奛GX_HTTP_WRITE_BUFFERED瀹忥紝鍚屾椂杩斿洖NGX AGAIN锛岃繖鏄湪鍛婅瘔HTTP妗嗘灦out缂撳啿鍖轰腑杩樻湁鍝嶅簲绛夊緟鍙戦併 c->buffered |= NGX_HTTP_WRITE_BUFFERED; return NGX_AGAIN; - //调用ngx_http_write_filter写数据,如果返回NGX_AGAIN,则以后的写数据触发通过在ngx_http_set_write_handler->ngx_http_writer添加epoll write事件来触发 + //璋冪敤ngx_http_write_filter鍐欐暟鎹紝濡傛灉杩斿洖NGX_AGAIN,鍒欎互鍚庣殑鍐欐暟鎹Е鍙戦氳繃鍦╪gx_http_set_write_handler->ngx_http_writer娣诲姞epoll write浜嬩欢鏉ヨЕ鍙 } if (size == 0 @@ -335,34 +335,34 @@ Connection: keep-alive } /* - ngx_time()方法,它取出了当前时间,而start sec表示开始接收到客户端请求内容的时间,c->sent表示这条连接上已经发送了的HTTP响 - 应长度,这样计算出的变量limit就表示本次可以发送的字节数了。如果limit小于或等于0,它表示这个连接上的发送响应速度已经超出 - 了limit_rate配置项的限制,所以本次不可以继续发送,跳到第7步执行;如果limit大于0,表示本次可以发送limit字节的响应,开始发送响应。 + ngx_time()鏂规硶锛屽畠鍙栧嚭浜嗗綋鍓嶆椂闂达紝鑰宻tart sec琛ㄧず寮濮嬫帴鏀跺埌瀹㈡埛绔姹傚唴瀹圭殑鏃堕棿锛宑->sent琛ㄧず杩欐潯杩炴帴涓婂凡缁忓彂閫佷簡鐨凥TTP鍝 + 搴旈暱搴︼紝杩欐牱璁$畻鍑虹殑鍙橀噺limit灏辫〃绀烘湰娆″彲浠ュ彂閫佺殑瀛楄妭鏁颁簡銆傚鏋渓imit灏忎簬鎴栫瓑浜0锛屽畠琛ㄧず杩欎釜杩炴帴涓婄殑鍙戦佸搷搴旈熷害宸茬粡瓒呭嚭 + 浜唋imit_rate閰嶇疆椤圭殑闄愬埗锛屾墍浠ユ湰娆′笉鍙互缁х画鍙戦侊紝璺冲埌绗7姝ユ墽琛岋紱濡傛灉limit澶т簬0锛岃〃绀烘湰娆″彲浠ュ彂閫乴imit瀛楄妭鐨勫搷搴旓紝寮濮嬪彂閫佸搷搴斻 */ limit = (off_t) r->limit_rate * (ngx_time() - r->start_sec + 1) - (c->sent - r->limit_rate_after); - //实际上这发送过程中就比实际的limit_rate多发送limit_rate_after,也就是先发送limit_rate_after后才开始计算是否超速了 + //瀹為檯涓婅繖鍙戦佽繃绋嬩腑灏辨瘮瀹為檯鐨刲imit_rate澶氬彂閫乴imit_rate_after锛屼篃灏辨槸鍏堝彂閫乴imit_rate_after鍚庢墠寮濮嬭绠楁槸鍚﹁秴閫熶簡 if (limit <= 0) { - c->write->delayed = 1; //由于达到发送响应的速度上限,这时将连接上写事件的delayed标志位置为1。 + c->write->delayed = 1; //鐢变簬杈惧埌鍙戦佸搷搴旂殑閫熷害涓婇檺锛岃繖鏃跺皢杩炴帴涓婂啓浜嬩欢鐨刣elayed鏍囧織浣嶇疆涓1銆 - /* limit是已经超发的字节数,它是0或者负数。这个定时器的超时时间是超发字节数按照limit_rate速率算出需要等待的时间 - 再加上l毫秒,它可以使Nginx定时器准确地在允许发送响应时激活请求。 */ + /* limit鏄凡缁忚秴鍙戠殑瀛楄妭鏁帮紝瀹冩槸0鎴栬呰礋鏁般傝繖涓畾鏃跺櫒鐨勮秴鏃舵椂闂存槸瓒呭彂瀛楄妭鏁版寜鐓imit_rate閫熺巼绠楀嚭闇瑕佺瓑寰呯殑鏃堕棿 + 鍐嶅姞涓妉姣锛屽畠鍙互浣縉ginx瀹氭椂鍣ㄥ噯纭湴鍦ㄥ厑璁稿彂閫佸搷搴旀椂婵娲昏姹傘 */ delay = (ngx_msec_t) (- limit * 1000 / r->limit_rate + 1); - //添加定时器的时候为什么没有ngx_handle_write_event? 因为一旦添加wrie epoll事件,那么只要内核数据发送出去就会触发write事件, - //从而执行ngx_http_writer,这个过程是很快的,这样就起不到限速的作用了 - ngx_add_timer(c->write, delay, NGX_FUNC_LINE); //handle应该是ngx_http_request_handler + //娣诲姞瀹氭椂鍣ㄧ殑鏃跺欎负浠涔堟病鏈塶gx_handle_write_event? 鍥犱负涓鏃︽坊鍔爓rie epoll浜嬩欢锛岄偅涔堝彧瑕佸唴鏍告暟鎹彂閫佸嚭鍘诲氨浼氳Е鍙憌rite浜嬩欢锛 + //浠庤屾墽琛宯gx_http_writer锛岃繖涓繃绋嬫槸寰堝揩鐨勶紝杩欐牱灏辫捣涓嶅埌闄愰熺殑浣滅敤浜 + ngx_add_timer(c->write, delay, NGX_FUNC_LINE); //handle搴旇鏄痭gx_http_request_handler c->buffered |= NGX_HTTP_WRITE_BUFFERED; return NGX_AGAIN; - //调用ngx_http_write_filter写数据,如果返回NGX_AGAIN,则以后的写数据触发通过在ngx_http_set_write_handler->ngx_http_writer添加epoll write事件来触发 + //璋冪敤ngx_http_write_filter鍐欐暟鎹紝濡傛灉杩斿洖NGX_AGAIN,鍒欎互鍚庣殑鍐欐暟鎹Е鍙戦氳繃鍦╪gx_http_set_write_handler->ngx_http_writer娣诲姞epoll write浜嬩欢鏉ヨЕ鍙 } /* - 本步将把响应发送给客户端。然而,缓冲区中的响应可能非常大,那么这一次应该发送多少字节呢?这要根据前面计算出的limit变量, - 前面取得的配置项sendfile_max_chunk来计算,同时要根据遍历缓冲区计算出的待发送字节数来决定,这3个值中的最小值即作为本 - 次发送的响应长度。 实际最后通过ngx_writev_chain发送数据的时候,还会限制一次 + 鏈灏嗘妸鍝嶅簲鍙戦佺粰瀹㈡埛绔傜劧鑰岋紝缂撳啿鍖轰腑鐨勫搷搴斿彲鑳介潪甯稿ぇ锛岄偅涔堣繖涓娆″簲璇ュ彂閫佸灏戝瓧鑺傚憿锛熻繖瑕佹牴鎹墠闈㈣绠楀嚭鐨刲imit鍙橀噺锛 + 鍓嶉潰鍙栧緱鐨勯厤缃」sendfile_max_chunk鏉ヨ绠楋紝鍚屾椂瑕佹牴鎹亶鍘嗙紦鍐插尯璁$畻鍑虹殑寰呭彂閫佸瓧鑺傛暟鏉ュ喅瀹氾紝杩3涓间腑鐨勬渶灏忓煎嵆浣滀负鏈 + 娆″彂閫佺殑鍝嶅簲闀垮害銆 瀹為檯鏈鍚庨氳繃ngx_writev_chain鍙戦佹暟鎹殑鏃跺欙紝杩樹細闄愬埗涓娆 */ if (clcf->sendfile_max_chunk && (off_t) clcf->sendfile_max_chunk < limit) @@ -378,9 +378,9 @@ Connection: keep-alive ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http write filter limit %O", limit); - //注意这里发送的时候可能会出现超速,所以在发送成功后会重新计算是否超速,从而决定是否需要启动定时器延迟发送 - //返回值应该是out中还没有发送出去的数据存放在chain中 - chain = c->send_chain(c, r->out, limit); //这里面会重新计算实际已经发送出去了多少字节 + + //杩斿洖鍊煎簲璇ユ槸out涓繕娌℃湁鍙戦佸嚭鍘荤殑鏁版嵁瀛樻斁鍦╟hain涓 + chain = c->send_chain(c, r->out, limit); //杩欓噷闈細閲嶆柊璁$畻瀹為檯宸茬粡鍙戦佸嚭鍘讳簡澶氬皯瀛楄妭 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http write filter %p", chain); @@ -390,10 +390,10 @@ Connection: keep-alive return NGX_ERROR; } - //发送响应后再次检查请求的limit_rate标志位,如果limit_rate为0,则表示不需要限速,如果limit_rate大干0,则表示需要限速。 + //鍙戦佸搷搴斿悗鍐嶆妫鏌ヨ姹傜殑limit_rate鏍囧織浣嶏紝濡傛灉limit_rate涓0锛屽垯琛ㄧず涓嶉渶瑕侀檺閫燂紝濡傛灉limit_rate澶у共0锛屽垯琛ㄧず闇瑕侀檺閫熴 if (r->limit_rate) { - nsent = c->sent;//在上面执行c->send_chain后实际发送的字节数会加到c->send上面 + nsent = c->sent;//鍦ㄤ笂闈㈡墽琛宑->send_chain鍚庡疄闄呭彂閫佺殑瀛楄妭鏁颁細鍔犲埌c->send涓婇潰 if (r->limit_rate_after) { @@ -407,60 +407,60 @@ Connection: keep-alive nsent = 0; } } - - //从新计算是否超速了,如果超速了则启动延迟定时器延迟发送 + + // nsent-sent琛ㄧず鍒氬垰鍙戦佷簡澶氬皯涓瓧鑺傦紝 + // 璁$畻鍦ㄦ寚瀹氱殑limit_rate涓嬶紝鍒氭墠鍙戦佺殑瀛楄妭鏁伴渶瑕佺殑鏃堕棿鏄灏(delay)锛屽苟璁剧疆涓涓畾鏃跺櫒琛ュ伩杩欎竴閮ㄥ垎鏃堕棿銆 delay = (ngx_msec_t) ((nsent - sent) * 1000 / r->limit_rate); /* - 前面调用c->send_chain发送的响应速度还是过快了,已经超发了一些响应,从新计算出至少要经过多少毫秒后才可以继续发送, - 调用ngx_add_timer方法将写事件按照上面计算出的毫秒作为超时时间添加到定时器中。同时,把写事件的delayed标志位置为1。 + 璋冪敤ngx_add_timer鏂规硶灏嗗啓浜嬩欢鎸夌収涓婇潰璁$畻鍑虹殑姣浣滀负瓒呮椂鏃堕棿娣诲姞鍒板畾鏃跺櫒涓傚悓鏃讹紝鎶婂啓浜嬩欢鐨刣elayed鏍囧織浣嶇疆涓1銆 */ if (delay > 0) { limit = 0; c->write->delayed = 1; - //添加定时器的时候为什么没有ngx_handle_write_event? 因为一旦添加wrie epoll事件,那么只要内核数据发送出去就会触发write事件, - //从而执行ngx_http_writer,这个过程是很快的,这样就起不到限速的作用了 + //娣诲姞瀹氭椂鍣ㄧ殑鏃跺欎负浠涔堟病鏈塶gx_handle_write_event? 鍥犱负涓鏃︽坊鍔爓rie epoll浜嬩欢锛岄偅涔堝彧瑕佸唴鏍告暟鎹彂閫佸嚭鍘诲氨浼氳Е鍙憌rite浜嬩欢锛 + //浠庤屾墽琛宯gx_http_writer锛岃繖涓繃绋嬫槸寰堝揩鐨勶紝杩欐牱灏辫捣涓嶅埌闄愰熺殑浣滅敤浜 ngx_add_timer(c->write, delay, NGX_FUNC_LINE); } } if (limit && c->write->ready - && c->sent - sent >= limit - (off_t) (2 * ngx_pagesize)) //如果超速的字节数超过了 + && c->sent - sent >= limit - (off_t) (2 * ngx_pagesize)) //濡傛灉瓒呴熺殑瀛楄妭鏁拌秴杩囦簡 { c->write->delayed = 1; - //添加定时器的时候为什么没有ngx_handle_write_event? 因为一旦添加wrie epoll事件,那么只要内核数据发送出去就会触发write事件, - //从而执行ngx_http_writer,这个过程是很快的,这样就起不到限速的作用了 + //娣诲姞瀹氭椂鍣ㄧ殑鏃跺欎负浠涔堟病鏈塶gx_handle_write_event? 鍥犱负涓鏃︽坊鍔爓rie epoll浜嬩欢锛岄偅涔堝彧瑕佸唴鏍告暟鎹彂閫佸嚭鍘诲氨浼氳Е鍙憌rite浜嬩欢锛 + //浠庤屾墽琛宯gx_http_writer锛岃繖涓繃绋嬫槸寰堝揩鐨勶紝杩欐牱灏辫捣涓嶅埌闄愰熺殑浣滅敤浜 ngx_add_timer(c->write, 1, NGX_FUNC_LINE); } /* - 重置ngx_http_request_t结构体的out缓冲区,把已经发送成功的缓冲区归还给内存池。如果out链表中还有剩余的没有发送出去的缓冲区, - 则添加到out链表头部;如果已经将out链表中的所有缓冲区都发送给客户端了,则r->out链上为空 + 閲嶇疆ngx_http_request_t缁撴瀯浣撶殑out缂撳啿鍖猴紝鎶婂凡缁忓彂閫佹垚鍔熺殑缂撳啿鍖哄綊杩樼粰鍐呭瓨姹犮傚鏋渙ut閾捐〃涓繕鏈夊墿浣欑殑娌℃湁鍙戦佸嚭鍘荤殑缂撳啿鍖猴紝 + 鍒欐坊鍔犲埌out閾捐〃澶撮儴锛涘鏋滃凡缁忓皢out閾捐〃涓殑鎵鏈夌紦鍐插尯閮藉彂閫佺粰瀹㈡埛绔簡,鍒檙->out閾句笂涓虹┖ */ - for (cl = r->out; cl && cl != chain; /* void */) { //chain为r->out中还未发送的数据不符 + for (cl = r->out; cl && cl != chain; /* void */) { //chain涓簉->out涓繕鏈彂閫佺殑鏁版嵁涓嶇 ln = cl; cl = cl->next; ngx_free_chain(r->pool, ln); } -/*实际上p->busy最终指向的是ngx_http_write_filter中未发送完的r->out中保存的数据,这部分数据始终在r->out的最前面,后面在读到数据后在 -ngx_http_write_filter中会把新来的数据加到r->out后面,也就是未发送的数据在r->out前面新数据在链后面,所以实际write是之前未发送的先发送出去*/ +/*瀹為檯涓妏->busy鏈缁堟寚鍚戠殑鏄痭gx_http_write_filter涓湭鍙戦佸畬鐨剅->out涓繚瀛樼殑鏁版嵁锛岃繖閮ㄥ垎鏁版嵁濮嬬粓鍦╮->out鐨勬渶鍓嶉潰锛屽悗闈㈠湪璇诲埌鏁版嵁鍚庡湪 +ngx_http_write_filter涓細鎶婃柊鏉ョ殑鏁版嵁鍔犲埌r->out鍚庨潰锛屼篃灏辨槸鏈彂閫佺殑鏁版嵁鍦╮->out鍓嶉潰鏂版暟鎹湪閾惧悗闈紝鎵浠ュ疄闄厀rite鏄箣鍓嶆湭鍙戦佺殑鍏堝彂閫佸嚭鍘*/ - r->out = chain; //把还没有发送完的数据从新添加到out中,实际上in中的相关chain和buf与r->out中的相关chain和buf指向了相同的还为发送出去的数据内存 + r->out = chain; //鎶婅繕娌℃湁鍙戦佸畬鐨勬暟鎹粠鏂版坊鍔犲埌out涓紝瀹為檯涓奿n涓殑鐩稿叧chain鍜宐uf涓巖->out涓殑鐩稿叧chain鍜宐uf鎸囧悜浜嗙浉鍚岀殑杩樹负鍙戦佸嚭鍘荤殑鏁版嵁鍐呭瓨 - if (chain) { //还没有发送完成,需要继续发送 + if (chain) { //杩樻病鏈夊彂閫佸畬鎴愶紝闇瑕佺户缁彂閫 c->buffered |= NGX_HTTP_WRITE_BUFFERED; return NGX_AGAIN; - //调用ngx_http_write_filter写数据,如果返回NGX_AGAIN,则以后的写数据触发通过在ngx_http_set_write_handler->ngx_http_writer添加epoll write事件来触发 + //璋冪敤ngx_http_write_filter鍐欐暟鎹紝濡傛灉杩斿洖NGX_AGAIN,鍒欎互鍚庣殑鍐欐暟鎹Е鍙戦氳繃鍦╪gx_http_set_write_handler->ngx_http_writer娣诲姞epoll write浜嬩欢鏉ヨЕ鍙 } c->buffered &= ~NGX_HTTP_WRITE_BUFFERED; - /* 如果其他filter模块buffer了chain并且postponed为NULL,那么返回NGX_AGAIN,需要继续处理buf */ + /* 濡傛灉鍏朵粬filter妯″潡buffer浜哻hain骞朵笖postponed涓篘ULL锛岄偅涔堣繑鍥濶GX_AGAIN锛岄渶瑕佺户缁鐞哹uf */ if ((c->buffered & NGX_LOWLEVEL_BUFFERED) && r->postponed == NULL) { return NGX_AGAIN; - //调用ngx_http_write_filter写数据,如果返回NGX_AGAIN,则以后的写数据触发通过在ngx_http_set_write_handler->ngx_http_writer添加epoll write事件来触发 + //璋冪敤ngx_http_write_filter鍐欐暟鎹紝濡傛灉杩斿洖NGX_AGAIN,鍒欎互鍚庣殑鍐欐暟鎹Е鍙戦氳繃鍦╪gx_http_set_write_handler->ngx_http_writer娣诲姞epoll write浜嬩欢鏉ヨЕ鍙 } return NGX_OK;