久久精品国产精品国产精品污,男人扒开添女人下部免费视频,一级国产69式性姿势免费视频,夜鲁夜鲁很鲁在线视频 视频,欧美丰满少妇一区二区三区,国产偷国产偷亚洲高清人乐享,中文 在线 日韩 亚洲 欧美,熟妇人妻无乱码中文字幕真矢织江,一区二区三区人妻制服国产

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

《深入理解NGINX 模块开发与架构解析》之摘抄学习

發布時間:2024/1/23 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 《深入理解NGINX 模块开发与架构解析》之摘抄学习 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1.基于Nginx框架開發程序有5個優勢:

? ? (1).Nginx將網絡、磁盤及定時器等異步事件的驅動都做了非常好的封裝,基于它開發將可以忽略這些事件處理的細節;

? ? (2).Nginx封裝了許多平臺無關的接口、容器,適用于跨平臺開發。

? ? (3) 優秀的模塊化設計,使得開發者可以輕易地復用各種已有的模塊,其中既包括基本的讀取配置、記錄日志等模塊,也包括處理請求的諸如HTTP.mail等高級功能模塊;

? ? (4)?Nginx是作為服務器來設計其框架的,因此,它在服務器進程的管理上相當出色,基于它開發服務器程序可以輕松地實現程序的動態升級,子進程的監控、管理,配置項的動態修改生效等;

? ? (5).Nginx充分考慮到各操作系統所擅長的“絕活”,能夠使用特殊的系統調用更高效地完成任務時,絕不會去使用低效的通用接口。尤其對于Linux操作系統,Nginx不遺余力地做了大量優化。

2.由于默認的Linux內核參數考慮的是最通用的場景,這明顯不符合用于支持高并發訪問的Web服務器的定義,所以需要修改Linux內核參數,使得Nginx可以擁有更高的性能。

? ?最常用的配置:

fs.file-max = 999999 //這個參數表示進程(比如一個worker進程)可以同時打開的最大句柄數 net.ipv4.tcp_tw_reuse = 1 //這個參數設置為1,表示允許將TIME-WAIT狀態的socket重新用于新的TCP連接,這對于服務器來說很有意義,因為服務器上總會有大量TIME-WAIT狀態的連接。 net.ipv4.tcp_keepalive_time = 600 //這個參數表示當前keepalive啟用時,TCP發送keepalive消息的頻度。默認是2小時,若將其設置得小一些,可以更快地清理無效的連接 net.ipv4.tcp_fin_timeout = 30 //這個參數表示當前當服務器主動關閉連接時,socket保持在FIN-WAIT-2狀態的最大時間 net.ipv4.tcp_max_tw_buckets = 5000 //這個參數表示操作系統允許TIME_WAIT套接字數量的最大值,如果超過這個數字,TIME_WAIT套接字將立刻被清除并打印警告信息。 net.ipv4.ip_local_port_range = 1024 61000 //這個參數定義了在UDP和TCP連接中本地(不包括連接的遠端)端口的取值范圍。 net.ipv4.tcp_rmem = 4096 32768 262142 //這個參數定義了TCP接收緩存(用于TCP接受滑動窗口)的最小值、默認值、最大值。 net.ipv4.tcp_wmem = 4096 32768 262142 //這個參數定義了TCP發送緩存(用于TCP發送滑動窗口)的最小值、默認值、最大值。 net.core.netdev_max_backlog = 8096 //當網卡接收數據包的速度大于內核處理的速度時,會有一個隊列保存這些數據包。這個參數表示該隊列的最大值。 net.core.rmem_default = 262144 //這個參數表示內核套接字接收緩存區默認的大小。 net.core.wmem_default = 262144 //這個參數表示內核套接字發送緩存區默認的大小。 net.core.rmem_max = 2097152 //這個參數表示內核套接字接收緩存區的最大大小。 net.core.wmem_max = 2097152 //這個參數表示內核套接字發送緩存區的最大大小。 net.ipv4.tcp_syncookies = 1 //該參數與性能無關,用于解決TCP的SYN攻擊。 net.ipv4.tcp_max_syn_backlog = 1024 //這個參數表示TCP三次握手建立階段SYN請求隊列的最大長度,默認為1024,將其設置得大一些可以使出現Nginx繁忙來不及accept新連接的情況時,Linux不至于丟失客戶端發起的連接請求。

3.configure腳本的內容如下:

#!bin/sh# Copyright (C) Igor Sysoev # Copyright (C) Nginx, Inc.#auto/options腳本處理configure命令的參數。例如,如果參數是--help,那么顯示支持的所有參數格式。options腳本會定義后續工作將要用到的變量,然后根據本次參數以及默認值設置這些變量 . auto/options#auto/init腳本初始化后續將產生的文件路徑。例如,Makefile、ngx_modules.c等文件默認情況下會在<nginx-source>/objs/ . auto/init#auto/sources腳本將分析Nginx的源碼結構,這樣才能構造后續的Makefile文件 . auto/sources# 編譯過程中所有目錄文件生成的路徑由--builddir=DIR參數指定,默認情況下為<nginx-source>/objs,此時這個目錄將會被創建 test -d $NGX_OBJS || mkdir $NGX_OBJS# 開始準備建立ngx_auto_headers.h、autoconf.err等必要的編譯文件 echo > $NGX_AUTO_HEADERS_H echo > $NGX_AUTOCONF_ERR# 向objs/ngx_auto_config.h寫入命令行帶的參數 echo "#define NGX_CONFIGURE \"$NGX_CONFIGURE\"" > $NGX_AUTO_CONFIG_H# 判斷DEBUG標志,如果有,那么在objs/ngx_auto_config.h文件中寫入DEBUG宏 if [ $NGX_DEBUG = YES ]; thenhave=NGX_DEBUG . auto/have fi# 現在開始檢查操作系統參數是否支持后續編譯 if test -z "$NGX_PLATFORM"; thenecho "checking for OS"NGX_SYSTEM=`uname -s 2>/dev/null`NGX_RELEASE=`uname -r 2>/dev/null`NGX_MACHINE=`uname -m 2>/dev/null`#屏幕上輸出OS名稱、內核版本、32位/64位內核echo " + $NGX_SYSTEM $NGX_RELEASE $NGX_MACHINE"NGX_PLATFORM="$NGX_SYSTEM:$NGX_RELEASE:$NGX_MACHINE";case "$NGX_SYSTEM" inMINGW32_*)NGX_PLATFORM=win32;;esacelseecho "building for $NGX_PLATFORM"NGX_SYSTEM=$NGX_PLATFORMfi#檢查并設置編譯器,如GCC是否安裝、GCC版本是否支持后續編譯nginx. auto/cc/conf# 對非Windows操作系統定義一些必要的頭文件,并檢查其是否存在,一次決定configure后續步驟是否可以成功if [ "$NGX_PLATFORM" != win32 ]; then. auto/headersfi# 對于當前操作系統,定義一些特定的操作系統相關的方法并檢查當前環境是否支持。例如,對于Linux,在這里使用sched_sestaffinity設置進程優先級,使用Linux特有的sendfile系統調用來加速向網絡中發送文件塊. auto/os/conf# 定義類UNIX操作系統中通用的頭文件和系統調用等,并檢查當前環境是否支持if [ "$NGX_PLATFORM" != win32 ]; then. auto/unixfi#最核心的構造運行期modules的腳本。它將會生成ngx_modules.c文件,這個文件會被編譯進Nginx中,其中它所做的唯一的事情就是定義了ngx_modules數組。ngx_modules指明Nginx運行期間有哪些模塊會參與到請求的處理中,包括HTTP請求可能會使用哪些模塊處理,因此,它對數組元素的順序非常敏感,也就是說,絕大部分模塊在ngx_modules數組中的順序其實是固定的。例如,一個請求必須先執行ngx_http_gzip_filter_module模塊重新修改HTTP響應中的頭部后,才能使用ngx_http_header_filter模塊按照headers_in結構體里的成員構造出以TCP流形式發送給客戶端的HTTP響應頭部。注意,我們在--add-module=參數里加入的第三方模塊也在此步驟寫入到ngx_modules.c文件中了. auto/modules# conf腳本用來檢查Nginx在鏈接期間需要鏈接的第三方靜態庫、動態庫或者目標文件是否存在. auto/lib/conf# 處理Nginx安裝后的路徑case ".$NGX_PREFIX" in.)NGX_PREFIX=${NGX_PREFIX:-/usr/local/nginx}have=NGX_PREFIX value="\"$NGX_PREFIX/\"" . auto/define;;.!)NGX_PREFIX=;;*)have=NGX_PREFIX value="\"$NGX_PREFIX/\"" . auto/define;;esac# 處理Nginx安裝后conf文件的路徑if [ ".$NGX_CONF_PREFIX" != "." ]; thenhave=NGX_CONF_PREFIX value="\"$NGX_CONF_PREFIX/\"" . auto/definefi# 處理Nginx安裝后,二進制文件、pid、lock等其他文件的路徑可參見configure參數中路徑類選項的說明have=NGX_SBIN_PATH value="\"$NGX_SBIN_PATH\"" . auto/definehave=NGX_CONF_PATH value="\"$NGX_CONF_PATH\"" . auto/definehave=NGX_PID_PATH value="\"$NGX_PID_PATH\"" . auto/definehave=NGX_LOCK_PATH value="\"$NGX_LOCK_PATH\"" . auto/definehave=NGX_ERROR_LOG_PATH value="\"$NGX_ERROR_LOG_PATH\"" . auto/definehave=NGX_HTTP_LOG_PATH value="\"$NGX_HTTP_LOG_PATH\"" . auto/definehave=NGX_HTTP_CLIENT_TEMP_PATH value="\"$NGX_HTTP_CLIENT_TEMP_PATH\"" . auto/definehave=NGX_HTTP_PROXY_TEMP_PATH value="\"$NGX_HTTP_PROXY_TEMP_PATH\"" . auto/definehave=NGX_HTTP_FASTCGI_TEMP_PATH value="\"$NGX_HTTP_FASTCGI_TEMP_PATH\"" . auto/definehave=NGX_HTTP_UWSGI_TEMP_PATH value="\"$NGX_HTTP_UWSGI_TEMP_PATH\"" . auto/definehave=NGX_HTTP_SCGI_TEMP_PATH value="\"$NGX_HTTP_SCGI_TEMP_PATH\"" . auto/define# 創建編譯時使用的objs/Makefile文件. auto/make# 為objs/Makefile加入需要連接的第三方靜態庫、動態庫或者目標文件. auto/lib/make# 為objs/Makefile加入install功能,當執行make install時將編譯生成的必要文件復制到安裝路徑,建立必要的目錄. auto/install# 在ngx_auto_config.h文件中加入NGX_SUPPERSS_WARN宏、NGX_SMP宏. auto/stubs# 在ngx_auto_config.h文件中指定NGX_USER和NGX_GROUP宏,如果執行configure時沒有參數指定,默認兩者皆為nobody(也就是默認以nobody用戶運行進程)have=NGX_USER value="\"$NGX_USER\"" . auto/definehave=NGX_GROUP value="\"$NGX_GROUP\"" . auto/define# 顯示configure執行的結果,如果失敗,則給出原因. auto/summary

4.ngx_moduels.c文件就是用來定義ngx_moduels數組的。它指明了每個模塊在Nginx中的優先級,當一個請求同時符合多個模塊的處理規則時,將按照它們在ngx_moduels數組中的順序選擇最靠前的模塊優先處理。對于HTTP過濾模塊而言,在ngx_modules數組中越是靠后的模塊反而會首先處理HTTP響應。

5.日志文件回滾

? ?使用-s reopen參數可以重新打開日志文件,這樣可以先把當前日志文件改名或轉移到其他目錄中進行備份,再重新打開時就會生成新的日志文件。這個功能使得日志文件不至于過大。

6.平滑升級Nginx??

? ?當Nginx服務升級到新的版本時,必須要將舊的二進制文件Nginx替換掉,通常情況下這是需要重啟服務的,但Nginx支持不重啟服務來完成新版本的平滑升級。

? ?升級時包括以下步驟:

? ? 1) 通知正在運行的舊版本Nginx準備升級。通過向master進程發送USR2信號可達到目的。例如:

kill -s SIGUSR2 <nginx master pid>

? ? ? 這時,運行中的Nginx會將pid文件重命名,如將/usr/local/nginx/los/nginx.pid重命名為/usr/local/nginx/logs/nginx.pid.oldbin,這樣新的Nginx才有可能啟動成功。

? ? ?2) 啟動新版本的Nginx,可以使用以上介紹過的任意一種啟動方法,這時通過ps命令可以發現新舊版本的Nginx在同時運行。

? ? ?3) 通過kill命令向舊版本的master進程發送SIGQUIT信號,以“優雅”的方式關閉舊版本的Nginx。隨后將只有新版本的Nginx服務運行,此時平滑升級完畢。

7.部署后Nginx進程間的關系

? ?

8.系統調用gettimeofday的執行頻率

? ?默認情況下,每次內核的事件調用(如epoll、select、poll、kqueue等)返回時,都會執行一次gettimeofdata,實現用內核的時鐘來更新Nginx中的緩存時鐘。

9.server_name后可以跟多個主機名稱,如server_name www.testweb.com、download.testweb.com;。

? 在開始處理一個HTTP請求時,Nginx會取出header頭中的Host,與每個server中的server_name進行匹配,以此決定到底由哪一個server塊來處理這個請求。有可能一個Host與多個server塊中的server_name都匹配,這是就會根據匹配優先級來選擇實際處理的server塊。server_name與Host的匹配優先級如下:

? ? 1) 首先選擇所有字符串完全匹配的server_name,如www.testweb.com.

? ? 2)其次選擇通配符在前面的server_name,如 *.testweb.com。

? ? 3)再次選擇通配符在后面的server_name,如www.testweb.*。

? ? 4)最后選擇使用正則表達式才匹配的server_name,如~^\.testweb\.com$。

10.作為靜態Web服務器與反向代理服務器的Nginx

? ??

11.Nginx作為反向代理服務器時轉發請求的流程

? ??

? ?當客戶端發來HTTP請求時,Nginx并不會立刻轉發到上游服務器,而是先把用戶的請求(包括HTTP包體)完整地接收到Nginx所在服務器的硬盤或者內存中,然后再向上游服務器發起連接,把緩存的客戶端請求轉發到上游服務器。而Squid等代理服務器則采用一邊接收客戶端請求,一邊轉發到上游服務器的方式。

? ?Nginx的這種工作方式有什么優缺點呢?很明顯,缺點是延長了一個請求的處理時間,并增加了用于緩存請求內容的內存內核磁盤空間。而優點則是降低了上游服務器的負載,盡量把壓力放在Nginx服務器上。

12.Nginx HTTP模塊調用的簡化流程

? ??

13.在Linux平臺下,Nginx對ngx_int_t和ngx_uint_t的定義如下:

typedef intptr_t ngx_int_t; typedef uintptr_t ngx_uint_t;

14.ngx_str_t的定義如下:

typedef struct {size_t len;u_char *data; } ngx_str_t;

? ?任何視圖將ngx_str_t的data成員當做字符串來使用的情況,都可能導致內存越界!

? ?Nginx使用ngx_str_t可以有效地降低內存使用量。例如,用戶請求“GET /test?a=1 http/1.1\r\n”存儲到內存地址0x1d0b0110上,這時只需要把r->method_name設置為{len = 3,data = 0x1d0b0110}就可以表示方法名"GET",而不需要單獨為method_name再分配內存冗余的存儲字符串。

15.ngx_list_t是Nginx封裝的鏈表容器,它在Nginx中使用得很頻繁,例如HTTP的頭部就是用ngx_list_t來存儲的。先看一下ngx_list_t相關成員的定義:

typedef struct ngx_list_part_s ngx_list_part_t;struct ngx_list_part_s {void *elts; //指向數組的起始地址。ngx_uint_t nelts; //表示數組中已經使用了多少個元素,當然,nelts必須小于ngx_list_t結構體中的nalloc.ngx_list_part_t *next; //下一個鏈表元素ngx_list_part_t的地址。 };typedef struct {ngx_list_part_t *last; //指向鏈表的最后一個數組元素ngx_list_part_t part; //鏈表的首個數組元素size_t size; //鏈表中的每個ngx_list_part_t元素都是一個數組。因為數組存儲的是某種類型的數據結構,且ngx_list_t是非常靈活的數據結構,所以它不會限制存儲什么樣的數據,只是通過size限制每一個數組元素的占用的空間大小,也就是用戶要存儲的一個數據所占用的字節數必須小于或等于size。ngx_uint_t nalloc; //鏈表的數組元素一旦分配后是不可更改的。nalloc表示每個ngx_list_part_t數組的容量,即最多可存儲多少個數據。ngx_pool_t *pool; //鏈表中管理內存分配的內存池對象。用戶要存放的數據占用的內存都是由pool分配的。 } ngx_list_t;

? ngx_list_t的內存分布情況如下:

? ?

? ?上圖中是由3個ngx_list_part_t數組元素組成的ngx_list_t鏈表中可能擁有的一種內存分布結構。這里,pool內存池為其分配了連續的內存,最前端內存存儲的是ngx_list_t結構中的成員,緊接著是第一個ngx_list_part_t結構占用的內存,然后是ngx_list_part_t結構指向的數組,它們一共占用size*nalloc字節,表示數組中擁有nalloc個大小為size的元素。其后面是第2個ngx_list_part_t結構以及它所指向的數組,依次類推。

16.ngx_table_elt_t數據結構如下所示:

typedef struct {ngx_uint_t hash; //表明ngx_table_elt_t也可以是某個散列表數據結構(ngx_hash_t類型)中的成員ngx_str_t key;ngx_str_t value;u_char *lowcase_key; } ngx_table_elt_t;

? 顯而易見,ngx_table_elt_t是為HTTP頭部"量身定制"的。

17.緩沖區ngx_buf_t是Nginx處理大數據的關鍵數據結構,它既應用于內存數據也應用于磁盤數據。下面主要介紹ngx_buf_t結構體本身:

typedef struct ngx_buf_s ngx_buf_t; typedef void * ngx_buf_tag_t; struct ngx_buf_s {/* pos通常是用來告訴使用者本次應該從pos這個位置開始處理內存中的數據,這樣設置是因為同一個ngx_buf_t可能被多次反復處理,當然,pos的含義是由使用它的模塊定義的*/u_char *pos;/* last通常表示有效的內容到此為止,注意,pos與last之間的內存是希望nginx處理的內容*/u_char *last;/*處理文件時,file_pos與file_last的含義與處理內存時的pos與last相同,file_pos表示將要處理的文件位置,file_last表示截止的文件位置*/off_t file_pos;off_t file_last;//如果ngx_buf_t緩沖區用于內存,那么start指向這段內存的起始地址u_char *start;//與start成員對應,指向緩沖區內存的末尾u_char *end;/* 表示當前緩沖區的類型,例如由哪個模塊使用就指向這個模塊ngx_module_t變量的地址*/ngx_buf_tag_t tag;//引用的文件ngx_file_t *file;/* 當前緩沖區的影子緩沖區,該成員很少用到,僅僅在12.8節描述的使用緩沖區轉發上游服務器的響應時才使用了shadow成員,這是因為Nginx太節約內存了,分配一塊內存并使用ngx_buf_t表示接收到的上游服務器響應后,在向下游客戶端轉發時可能會把這塊內存存儲到文件中,也可能直接向下游發送,此時Nginx絕不會重新復制一份內存用于新的目的,而是再次建立一個ngx_buf_t結構體指向原內存,這樣多個ngx_buf_t結構體指向了同一塊內存,它們之間的關系就通過shadow成員來引用。這種設計過于復雜,通常不建議使用*/ngx_buf_t *shadow;//臨時內存標志位,為1時表示數據在內存中且這段內存可以修改unsigned temporary:1;//標志位,為1時表示數據在內存中且這段內存不可以被修改unsigned memory:1;//標志位,為1時表示這段內存使用mmap系統調用映射過來的,不可以被修改unsigned mmap:1;//標志位,為1時表示可回收unsigned recycled:1;//標志位,為1時表示這段緩沖區處理的是文件而不是內存unsigned in_file:1;//標志位,為1時表示需要執行flush操作unsigned flush:1;/*標志位,對于操作這塊緩沖區時是否使用同步方式,需謹慎考慮,這可能會阻塞Nginx進程,Nginx中所有操作幾乎都是異步的,這是它支持高并發的關鍵。有些框架代碼在sync為1時可能會有阻塞的方式進行I/O操作,它的意義視使用它的Nginx模塊而定*/unsigned sync:1;/*標志位,表示是否是最后一塊緩沖區,因為ngx_buf_t可以由ngx_chain_t鏈表串聯起來,因為,當last_buf為1時,表示當前是最后一塊待處理的緩沖區*/unsigned last_buf:1;//標志位,表示是否是ngx_chain-t中的最后一塊緩沖區unsigned last_in_chain:1;/* 標志位,表示是否是最后一個影子緩沖區,與shadow域配合使用。通常不建議使用它*/unsigned last_shadow:1;//標志位,表示當前緩沖區是否屬于臨時文件unsigned temp_file:1; };

18.ngx_chain_t是與ngx_buf_t配合使用的鏈表數據結構,來看一下定義:

typedef struct ngx_chain_s ngx_chain_t; struct ngx_chain_s {ngx_buf_t *buf; //指向當前的ngx_buf_t緩沖區ngx_chain-t *next; //用來指向下一個ngx_chain_t,如果這是最后一個ngx_chain_t,則需要把next置為NULL。 };

? 在向用戶發送HTTP包體時,就要傳入ngx_chain_t鏈表對象,注意,如果是最后一個ngx_chain_t,那么必須將next置為NULL,否則永遠不會發送成功,而且這個請求將一直不會結束(Nginx框架的要求).

19.ngx_module_t是一個Nginx模塊的數據結構,如下所示:

typedef struct ngx_module_s ngx_module_t; struct ngx_module_s {/* 下面的ctx_index、index、spare0、spare1、spare2、spare3、version變量不需要在定義時賦值,可以用Nginx準備好的宏NGX_MODULE_V1來定義,它已經定義好了這7個值 #define NGX_MODULE_V1 0,0,0,0,0,0,1對于一類模塊(由下面的type成員決定類別)而言,ctx_index表示當前模塊在這類模塊中的序號。這個成員常常是由管理這類模塊的一個Nginx核心模塊設置的,對于所有的HTTP模塊而言,ctx_index是由核心模塊ngx_http_module設置的。ctx_index非常重要,Nginx的模塊化設計非常依賴于各個模塊的順序,它們既用于表達優先級,也用于表明每個模塊的位置,借以幫助Nginx框架快速獲得某個模塊的數據*/ngx_uint_t ctx_index;/*index表示當前模塊在ngx_modules數組中的序號,注意,ctx_index表示的是當前模塊在一類模塊中的序號,而index表示當前模塊在所有模塊中的序號,它同樣關鍵。Nginx啟動時會根據ngx_modules數組設置各模塊的index值,例如:ngx_max_module = 0;for (i=0; ngx_modules[i]; i++) {ngx_modules[i]->index = ngx_max_module++;}*/ngx_uint_t index;//spare系列的保留變量,暫未使用ngx_uint_t spare0;ngx_uint_t spare1;ngx_uint_t spare2;ngx_uint_t spare3;//模塊的版本,便于將來的擴展。目前只有一種,默認為1ngx_uint_t version;/*ctx用于指向一類模塊的上下文結構體,為什么需要ctx呢?因為前面說過,Nginx模塊有許多種類,不同類模塊之間的功能差別很大。例如,事件類型的模塊主要處理I/O事件相關的功能,HTTP類型的模塊主要處理HTTP應用層的功能。這樣,每個模塊都有了自己的特性,而ctx將會指向特定類型模塊的公共接口。例如,在HTTP模塊中,ctx需要指向ngx_http_module_t結構體*/void *ctx;//commands將處理nginx.conf中的配置項ngx_command_t *commands;/*type表示該模型的類型,它與ctx指針是緊密相關的。在官方Nginx中,它的取值范圍是以下5種:NGX_HTTP_MODULE、NGX_CORE_MODULE、NGX_CONF_MODULE、NGX_EVENT_MODULE、NGX_MAIL_MODULE。*/ngx_uint_t type;/*在Nginx的啟動、停止過程中,以下7個函數指針表示有7個執行點會分別調用者7種方法。對于任一個方法而言,如果不需要Nginx在某個時刻執行它,那么簡單地把它設為NULL空指針即可*//*雖然從字面上理解應當在master進程啟動時回調init_master,但到目前為止,框架代碼從來不會調用它,因此,可將init_master設為NULL */ngx_int_t (*init_master)(ngx_lot_t *log);/* init_module回調方法在初始化所有模塊時被調用。在master/worker模式下,這個階段將在啟動worker子進程前完成*/ngx_int_t (*init_module)(ngx_cycle_t *cycle);/*init_process回調方法在正常服務前被調用。在master/worker模式下,多個worker子進程已經產生,在每個worker進程的初始化過程會調用所有模塊的init_process函數 */ngx_int_t (*init_process)(ngx_cycle_t *cycle);/*由于Nginx暫不支持多線程模式,所以init_thread在框架代碼中沒有被調用過,設為NULL*/ngx_int_t (*init_thread)(ngx_cycle_t *cycle);//同上,exit_thread也不支持,設為NULL.void (*exit_process)(ngx_cycle_t *cycle);//exit_master回調方法將在master進程退出前被調用void (*exit_master)(ngx_cycle_t *cycle);/*保留字段,目前沒有使用*/uintptr_t spare_hook0;uintptr_t spare_hook1;uintptr_t spare_hook2;uintptr_t spare_hook3;uintptr_t spare_hook4;uintptr_t spare_hook5;uintptr_t spare_hook6;uintptr_t spare_hook7; };

20.HTTP框架在讀取、重載配置文件時定義了由ngx_http_module_t接口描述的8個階段,HTTP框架在啟動過程中會在每一個階段中調用ngx_http_module_t中相應的方法。

typedef struct {//解析配置文件前調用ngx_int_t (*preconfiguration)(ngx_conf_t *cf);//完成配置文件的解析后調用ngx_int_t (*postconfiguration)(ngx_conf_t *cf);/*當需要創建數據結構用于存儲main級別(直屬于http{...}塊的配置項)的全局配置項時,可以通過create_main_conf回調方法創建存儲全局配置項的結構體 */void *(*create_main_conf)(ngx_conf_t *cf);//常用于初始化main級別配置項char *(*init_main_conf)(ngx_conf_t *cf, void *conf);/* 當需要創建數據結構用于存儲srv級別(直屬于虛擬主機server{...}塊的配置項)的配置項時,可以通過實現create_srv_conf回調方法創建存儲srv級別配置項的結構體 */void *(*create_srv_conf)(ngx_conf_t *cf);//merge_srv_conf回調方法主要用于合并main級別和srv級別下的同名配置項char *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, void *conf);/*當需要創建數據結構用于存儲loc級別(直屬于location{...}塊的配置項)的配置項時,可以實現create_loc_conf回調方法*/void *(*create_loc_conf)(ngx_conf_t *cf);//merge_loc_conf回調方法主要用于合并srv級別和loc級別下的同名配置項char *(*merge_loc_conf)(ngx_conf_t *cf, void *prev, void *conf); } ngx_http_module_t;

21.每一個ngx_command_t結構體定義了自己感興趣的一個配置項:

typedef struct ngx_command_s ngx_command_t; struct ngx_command_s {//配置項名稱,如"gzip"ngx_str_t name;/*配置項類型,type將指定配置項可以出現的位置。例如,出現在server{}或location{}中,以及它可以攜帶的參數個數 */ngx_uint_t type;//出現了name中指定的配置項后,將會調用set方法處理配置項的參數char *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);//在配置文件中的偏移量ngx_uint_t conf;/*通常用于使用預設的解析方法解析配置項,這是配置模塊的一個優秀設計。*/ngx_uint_t offset;//配置項讀取后的處理方法,必須是ngx_conf_post_t結構的指針void *post; };

? ?ngx_null_command只是一個空的ngx_command_t,如下所示:

?#define ngx_null_command { ngx_null_string, 0, NULL, 0, 0, NULL }

22.? ?

typedef enum {//在接收到完整的HTTP頭部后處理的HTTP階段NGX_HTTP_POST_READ_PHASE = 0,/*在還沒有查詢到URI匹配的location前,這時rewrite重寫URL也作為一個獨立的HTTP階段*/NGX_HTTP_SERVER_REWRITE_PHASE,/*根據URI尋找匹配的location,這個階段通常由ngx_http_core_module模塊實現,不建議其他HTTP模塊重新定義這一階段的行為*/NGX_HTTP_FIND_CONFIG_PHASE,/*在NGX_HTTP_FIND_CONFIG_PHASE階段之后重寫URL的意義與NGX_HTTP_SERVER_REWRITE_PHASE階段顯然是不同的,因為這兩者會導致查找到不同的location塊(location是與URI進行匹配的) */NGX_HTTP_REWRITE_PHASE,/* 這一階段是用于在rewrite重寫URL后重新跳到NGX_HTTP_FIND_CONFIG_PHASE階段,找到與心得URI匹配的location。所以,這一階段是無法由第三方HTTP模塊處理的,而僅由ngx_http_core_module模塊使用*/NGX_HTTP_POST_REWRITE_PHASE,//處理NGX_HTTP_ACCESS_PHASE階段前,HTTP模塊可以介入的處理階段NGX_HTTP_PREACCESS_PHASE,/*這個階段用于讓HTTP模塊判斷是否允許這個請求訪問Nginx服務器*/NGX_HTTP_ACCESS_PHASE,/*當NGX_HTTP_ACCESS_PHASE階段中HTTP模塊的handler處理方法返回不允許訪問的錯誤碼時(實際是NGX_HTTP_FORBIDDEN或者NGX_HTTP_UNAUTHORIZED),這個階段將負責構造拒絕服務的用戶響應。所以,這個階段實際上用于給NGX_HTTP_ACCESS_PHASE階段收尾*/NGX_HTTP_POST_ACCESS_PHASE,/*這個階段完全是為了try_files配置項而設計的。當HTTP請求訪問靜態文件資源時,try_files配置項可以使這個請求順序地訪問多個靜態文件資源,如果某一次訪問失敗,則繼續訪問try_files中指定的下一個靜態資源。另外,這個功能完全是在NGX_HTTP_TRY_FILES_PHASE階段中實現的 */NGX_HTTP_TRY_FILES_PHASE,//用于處理HTTP請求內容的階段,這是大部分HTTP模塊最喜歡介入的階段NGX_HTTP_CONTENT_PHASE,/* 處理完請求后記錄日志的階段,例如,ngx_http_log_module模塊就在這個階段中加入了一個handler處理方法,使得每個HTTP請求處理完畢后會記錄access_log日志 */NGX_HTTP_LOG_PHASE } ngx_http_phases;

23.處理方法的返回值,其中包括了HTTP框架已經在/src/http/ngx_http_request.h文件中定義好的宏,如下所示:

#define NGX_HTTP_OK 200 #define NGX_HTTP_CREATED 201 #define NGX_HTTP_ACCEPTED 202 #define NGX_HTTP_NO_CONTENT 204 #define NGX_HTTP_PARTIAL_CONTENT 206#define NGX_HTTP_SPECIAL_RESPONSE 300 #define NGX_HTTP_MOVED_PERMANENTLY 301 #define NGX_HTTP_MOVED_TEMPORARILY 302 #define NGX_HTTP_SEE_OTHER 303 #define NGX_HTTP_NOT_MODIFIED 304 #define NGX_HTTP_TEMPORARY_REDIRECT 307#define NGX_HTTP_BAD_REQUEST 400 #define NGX_HTTP_UNAUTHORIZED 401 #define NGX_HTTP_FORBIDDEN 403 #define NGX_HTTP_NOT_FOUND 404 #define NGX_HTTP_NOT_ALLOWED 405 #define NGX_HTTP_REQUEST_TIME_OUT 408 #define NGX_HTTP_CONFLICT 409 #define NGX_HTTP_LENGTH_REQUIRED 411 #define NGX_HTTP_PRECONDITION_FAILED 412 #define NGX_HTTP_REQUEST_ENTITY_TOO_LARGE 414 #define NGX_HTTP_REQUEST_URI_TOO_LARGE 414 #define NGX_HTTP_UNSUPPORTED_MEDIA_TYPE 415 #define NGX_HTTP_RANGE_NOT_SATISFIABLE 416/* The special code to close connection without any response */ #define NGX_HTTP_CLOSE 444 #define NGX_HTTP_NGINX_CODES 494 #define NGX_HTTP_REQUEST_HEADER_TOO_LARGE 494 #define NGX_HTTPS_CERT_ERROR 495 #define NGX_HTTPS_NO_CERT 496#define NGX_HTTP_TO_HTTPS 497 #define NGX_HTTP_CLIENT_CLOSED_REQUEST 499#define NGX_HTTP_INTERNAL_SERVER_ERROR 500 #define NGX_HTTP_NOT_IMPLEMENTED 501 #define NGX_HTTP_BAD_GATEWAY 502 #define NGX_HTTP_SERVICE_UNAVAILABLE 503 #define NGX_HTTP_GATEWAY_TIME_OUT 504 #define NGX_HTTP_INSUFFICIENT_STORAGE 507

24.請求的所有信息(如方法、URI、協議版本號和頭部等)都可以在傳入的ngx_http_request_t類型參數r中取得。

typedef struct ngx_http_request_s ngx_http_request_t; struct ngx_http_request_s {...ngx_uint_t method;ngx_uint_t http_version;ngx_str_t request_line;ngx_str_t uri;ngx_str_t args;ngx_str_t exten;ngx_str_t unparsed_uri; //表示沒有進行URL解碼的原始請求。ngx_str_t method_name;ngx_str_t http_protocol;u_char *uri_start;u_char *uri_end;u_char *uri_ext;u_char *args_start;u_char *request_start;u_char *request_end;u_char *method_end;u_char *schema_start;u_char *schema_end;... };

25.ngx_http_headers_in_t類型的headers_in則存儲已經解析過的HTTP頭部。

typedef struct {/* 所有解析過的HTTP頭部都在headers鏈表中,可以使用遍歷鏈表的方法來獲取所有的HTTP頭部。注意:這里headers鏈表的每一個元素都是ngx_table_elt_t成員*/ngx_list_t headers;/*以下每個ngx_table_elt_t成員都是RFC1616規范中定義的HTTP頭部,它們實際都指向headers鏈表中的響應成員。注意,當它們為NULL空指針時,表示沒有解析到響應的HTTP頭部*/ngx_table_elt_t *host;ngx_table_elt_t *connection;ngx_table_elt_t *if_modified_since;ngx_table_elt_t *if_unmodified_since;ngx_table_elt_t *user_agent;ngx_table_elt_t *referer;ngx_table_elt_t *content_length;ngx_table_elt_t *content_type;ngx_table_elt_t *range;ngx_table_elt_t *if_range;ngx_table_elt_t *transfer_encoding;ngx_table_elt_t *expect;#if (NGX_HTTP_GZIP)ngx_table_elt_t *accept_encoding;ngx_table_elt_t *via; #endifngx_table_elt_t *authorization;ngx_table_elt_t *keep_alive; #if (NGX_HTTP_PROXY || NGX_HTTP_REALIP || NGX_HTTP_GEO)ngx_table_elt_t *x_forwarded_for; #endif#if (NGX_HTTP_REALIP)ngx_table_elt_t *x_real_ip; #endif#if (NGX-HTTP_HEADERS)ngx_table_elt_t *accept;ngx_table_elt_t *accept_language; #endif#if (NGX_HTTP_DAV)ngx_table_elt_t *depth;ngx_table_elt_t *destination;ngx_table_elt_t *overwrite;ngx_table_elt_t *date; #endif/* user和passwd是只有ngx_http_auth_basic_module才會用到的成員,這里可以忽略*/ngx_str_t user;ngx_str_t passwd;/* cookies是以ngx_array_t數組存儲的。*/ngx_array_t cookies;//server名稱ngx_str_t server;//根據ngx_table_elt_t *content_length計算出的HTTP包體代銷off_t content_length_n;time_t keep_alive_n;/* HTTP連接類型,它的取值范圍是0、NGX_http_CONNECTION_CLOSE或者NGX_HTTP_CONNECTION_KEEP_ALIVE */unsigned connection_type:2;/*以下7個標志位是HTTP框架根據瀏覽器傳來的"useragent"頭部,它們可用來判斷瀏覽器的類型,值為1時表示是相應的瀏覽器發來的請求,值為0時則相反 */unsigned msie:1;unsigned msie6:1;unsigned opera:1;unsigned gecko:1;unsigned chrome:1;unsigned safari:1;unsigned konqueror:1; } ngx_http_headers_in_t;

26.HTTP包體的長度有可能非常大,如果視圖一次性調用并讀取完所有的包體,那么多半會阻塞Nginx進程,HTTP框架提供了一種方法來異步地接受包體:

ngx_int_t ngx_http_read_client_request_body(ngx_http_request_t *r, ngx_http_client_body_handler_pt post_handler);

? ngx_http_read_client_request_body是一個異步方法,調用它只是說明要求Nginx開始接收請求的包體,并不表示是否已經接收完,當接收完所有的包體內容后,post_handler指向的回調方法會被調用。因此,即使在調用了ngx_http-read_client_request_body方法后它已經返回,也無法確定這時是否已經調用過post_handler指向的方法。換句話說,ngx_http_read_client_request_body返回時既有可能已經接收完請求中所有的包體(假設包體的長度很小),也有可能還沒開始接受包體。

27.HTTP框架提供的發送HTTP頭部的方法如下所示:

ngx_int_t ngx_http_send_header(ngx_http_request_t *r);

28.headers_out的結構類型ngx_http_headers_out_t:

typedef struct {//待發送的HTTP頭部鏈表,與headers_in中的headers成員類似ngx_list_t headers;/*響應中的狀態值,如200表示成功。*/ngx_str_t status;//響應的狀態行,如"HTTP/1.1 201 CREATED"ngx_str_t status_line;/*以下成員(包括ngx_table_elt_t)都是RFC1616規范中定義的HTTP頭部,設置后,ngx_http_header_filter_module過濾模塊可以把它們加到待發送的網絡包中*/ngx_table_elt_t *server;ngx_table_elt_t *date;ngx_table_elt_t *content_length;ngx_table_elt_t *content_encoding;ngx_table_elt_t *location;ngx_table_elt_t *refresh;ngx_table_elt_t *last_modified;ngx_table_elt_t *content_range;ngx_table_elt_t *accept_ranges;ngx_table_elt_t *www_authenticate;ngx_table_elt_t *expires;ngx_table_elt_t *etag;ngx_str_t *override_charset;/* 可以調用ngx_http_set_content_type(r)方法幫助我們設置Content-Type頭部,這個方法會根據URI中的文件擴展名餅對應著mime.type來設置Content-Type值*/size_t content_type_len; ngx_str_t content_type;ngx_str_t charset;u_char *content_type_lowcase;ngx_uint_t content_type_hash;ngx_array_t cache_control;/*在這里指定過content_length_n后,不用再次到ngx_table_elt_t *content_length中設置響應長度*/off_t content_length_n;time_t date_time;time_t last_modified_time; } ngx_http_headers_out_t;

? ?ngx_http_send_header方法會首先調用所有的HTTP過濾模塊共同處理headers_out中定義的HTTP響應頭部,全部處理完畢后才會序列化為TCP字符流發送到客戶端。

28.注意:在向用戶發送響應包體時,必須牢記Nginx是全異步的服務器,也就是說,不可以在進程的棧里分配內存并將其作為包體發送。當ngx_http_output_filter方法返回時,可能由于TCP連接上的緩沖區還不可寫,所以導致ngx_buf_t緩沖區指向的內存還沒有發送,可這時方法返回已把控制權交給Nginx了,又會導致棧里的內存被釋放,最后就會造成內存越界錯誤。因此,在發送響應包體時,盡量將ngx_buf_t中的pos指針指向從內存池里分配的內存。

29.經典的"Hello World"示例

static ngx_int_t ngx_http_mytest_handler(ngx_http_request_t *r) {//必須是GET或者HEAD方法,否則返回405 Not Allowedif (!(r->method & (NGX_HTTP_GET | NGX_HTTP_HEAD))) {return NGX_HTTP_NOT_ALLOWED;}//丟棄請求中的包體ngx_int_t rc = ngx_http_discard_request_body(r);if (rc != NGX_OK) {return rc;}/* 設置返回的Content-Type.注意,ngx_str_t有一個很方便的初始化宏ngx_string,它可以把ngx_str_t的data和len成員都設置好 */ngx_str_t type = ngx_string("text/plain");//返回的包體內容ngx_str_t type = ngx_string("Hello World!");//設置返回狀態碼r->headers_out.status = NGX_HTTP_OK;//響應包是有包體內容的,需要設置Content-Lenght的長度r->headers_out.content_length_n = response.len;//設置Content-Typer->headers_out.content_type = type;//發送HTTP頭部rc = ngx_http_send_header(r);if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {return rc;}//構造ngx_buf_t結構體準備發送包體ngx_buf_t *b;b = ngx_create_temp_buf(r->pool, response.len);if (b == NULL) {return NGX_HTTP_INTERNAL_SERVER_ERROR;}//將Hello World復制到ngx_buf_t指向的內存中ngx_memcpy(b->pos, response.data, response.len);//注意,一定要設置好last指針b->last = b->pos + response.len;//聲明這是最后一塊緩沖區b->last_buf = 1;//構造發送時的ngx_chain_t結構體ngx_chain_t out;//賦值ngx_buf_tout.buf = b;//設置next為NULLout.next = NULL;/*最后一步為發送包體,發送結束后HTTP框架會調用ngx_http_finalize_request方法結束請求 */return ngx_http_output_filter(r, &out); }

30.ngx_file_t的結構如下:

typedef struct ngx_file_s ngx_file_t; struct ngx_file_s {//文件句柄描述符ngx_fd_t fd;//文件名稱ngx_str_t name;//文件大小等資源信息,實際就是Linux系統定義的stat結構ngx_file_info_t info;/*該偏移量告訴Nginx現在處理到文件何處了,一般不用設置它,Nginx框架會根據當前發送狀態設置它*/off_t offset;//當前文件系統偏移量,一般不用設置它off_t sys_offset;//日志對象,相關的日志會輸出到log指定的日志文件中ngx_log_t *log;//目前未使用unsigned valid_info:1;//與配置文件中的directio配置項相對應,在發送大文件時可以設為1unsigned directio:1; };

? Nginx不只對stat數據結構做了封裝,對于由操作系統中獲取文件信息的stat方法,Nginx也使用一個宏進行了簡單的封裝,如下:

#define ngx_file_info(file, sb) stat((const char *) file, sb)

? ?之后必須要設置Content-Length頭部:

r->headers_out.content_length_n = b->file->info.st_size;

? ?還需要設置ngx_buf_t緩沖區的file_pod和file_last:

b->file_pos = 0; b->file_last = b->file->info.st_size;

? ?這里告訴Nginx從文件的file_pos偏移量開始發送文件,一直到達file_last偏移量處截止。

31. HTTP框架定義了3個級別的配置main、srv、loc,分別表示直接出現在http{}、server{}、location{}塊內的配置項。當nginx.conf中出現http{}時,HTTP框架會接管配置文件中http{}塊內的配置項解析。當遇到http{...}配置塊時,HTTP框架會調用所有HTTP模塊可能實現的create_main_conf、create_srv_conf、create_loc_conf方法生成存儲main級別配置參數的結構體;在遇到server{...}塊時會再次調用所有HTTP模塊的create_srv_conf、create_loc_conf回調方法生成存儲srv級別配置參數的結構體;在遇到location{...}時則會再次調用create_loc_conf回調方法生成存儲loc級別配置參數的結構體。因此,實現這3個回調方法的意義是不同的。

32.設定配置項的解析方式

? ? ngx_command_t結構詳解

struct ngx_command_s {ngx_str_t name;ngx_uint_t type;char *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);ngx_uint_t conf;ngx_uint_t offset;void *post; };

? ? (1) ngx_str_t name

? ? ? ? 其中,name是配置項名稱。

? ? (2) ngx_uint_t type

? ? ? ? 其中,type決定這個配置項可以在哪些塊(如http、server、location、if、upstream塊等)中出現,以及可以攜帶的參數類型和個數等。

? ? ? ? ? ngx_command_t結構體中type成員的取值及其意義

type類型type取值意義
處理配置項時獲取當前配置塊的方式NGX_DIRECT_CONF一般由NGX_CORE_MODULE類型的核心模塊使用,僅與下面的NGX_MAIN_CONF同時設置,表示模塊需要解析不屬于任何{}內的全局配置項。它實際上會指定set方法里的第3個參數conf的值,使之指向每個模塊解析全局配置項的配置結構體(表下面解釋)
NGX_ANY_CONF目前未使用,設置與否均無意義
配置項可以在哪些{}配置塊中出現NGX_MAIN_CONF配置項可以出現在全局配置中,即不屬于任何{}配置塊
NGX_EVENT_CONF配置項可以出現在events{}塊內
NGX_MAIL_MAIN_CONF配置項可以出現在mail{}塊或者imap{}塊內
NGX_MAIL_SRV_CONF配置項可以出現在server{}塊內,然而該server{}塊必須屬于mail{}塊或者imap{}塊
NGX_HTTP_MAIN_CONF配置項可以出現在http{}塊內
NGX_HTTP_SRV_CONF配置項可以出現在server{}塊內,然而該server塊必須屬于http{}內
NGX_HTTP_LOC_CONF

配置項可以出現在location{}塊內,然而該location塊必須屬于http{}內

NGX_HTTP_UPS_CONF配置項可以出現在upstream{}塊內,然而該upstream塊必須屬于http{}塊
NGX_HTTP_SIF_CONF配置項可以出現在server塊內的if{}塊中。目前僅有rewrite模塊會使用,該if塊必須屬于http{}塊
NGX_HTTP_LIF_CONF配置項可以出現在location塊內的if{}塊中。目前僅有rewrite模塊會使用,該if塊必須屬于http{}塊
NGX_HTTP_LMT_CONF配置項可以出現在limit_except{}塊內,然而該limit_except塊必須屬于http{}塊
限制配置項的參數個數NGX_CONF_NOARGS配置項不攜帶任何參數
NGX_CONF_TAKE1配置項必須攜帶1個參數
NGX_CONF_TAKE2配置項必須攜帶2個參數
NGX_CONF_TAKE3配置項必須攜帶3個參數
NGX_CONF_TAKE4配置項必須攜帶4個參數
NGX_CONF_TAKE5配置項必須攜帶5個參數
NGX_CONF_TAKE6配置項必須攜帶6個參數
NGX_CONF_TAKE7配置項必須攜帶7個參數
NGX_CONF_TAKE12配置項可以攜帶1個參數或2個參數
NGX_CONF_TAKE13配置項可以攜帶1個參數或3個參數
NGX_CONF_TAKE23配置項可以攜帶2個參數或3個參數
NGX_CONF_TAKE123配置項可以攜帶1~3個參數
NGX_CONF_TAKE1234配置項可以攜帶1~4個參數
限制配置項后的參數出現的形式NGX_CONF_ARGS_NUMBERS目前未使用,無意義
NGX_CONF_BLOCK配置項定義了一種新的{}塊。例如,http、server、location等配置,它們的ttype都必須定義為NGX_CONF_BLOCK
NGX_CONF_ANY不驗證配置項攜帶的參數個數
NGX_CONF_FLAG配置項攜帶的參數只能是1個,并且參數的值只能是on或者off
NGX_CONF_1MORE配置項攜帶的參數個數必須超過1個
NGX_CONF_2MORE配置項攜帶的參數個數必須超過2個
NGX_CONF_MULTI表示當前配置項可以出現在任意塊中(包括不屬于任何塊的全局配置),它僅用于配合其他配置項使用。type中未加入NGX_CONF_MULTI時,如果一個配置項出現在type成員未標明的配置塊中,那么Nginx會認為該配置項非法,最后將導致Nginx啟動失敗。但如果type中加入了NGX_CONF_MULTI,則認為該配置項一定是合法的,然而又會有兩種不同的結果: a.如果配置項出現在type指示的塊中,則會調用set方法解析配置項;b.如果配置項沒有出現在type指示的塊中,則不對該配置項做任何處理。因此,NGX_CONF_MULTI會使得配置項出現在未知塊中時不會出錯。目前,還沒有官方模塊使用過NGX_CONF_MULTI.

解釋:每個進程總都有一個唯一的ngx_cycle_t核心結構體,它有一個成員conf_ctx維護著所有模塊的配置結構體,其類型是void ****。conf_ctx意義為首先指向一個成員皆為指針的數組,其中每個成員指針又指向另外一個成員皆為指針的數組,第2個子數組中的成員指針才會指向各模塊生成的配置結構體。這正是為了事件模塊、http模塊、mail模塊而設計的,這有利于不同于NGX_CORE_MODULE類型的特定模塊解析配置項。然而,NGX_CORE_MODULE類型的核心模塊解析配置項時,配置項一定是全局的,不會從屬于任何{}配置塊的,它不需要上述這種雙數組設計。解析標識為NGX_DIRECT_CONF類型的配置項時,會把void ****類型的conf_ctx強制轉換為void **,也就是說,此時,在conf_ctx指向的指針數組中,每個成員指針不再指向其他數組,直接指向核心模塊生成的配置結構體。因此,NGX_DIRECT_CONF僅由NGX_CORE_MODULE類型的核心模塊使用,而且配置項只應該出現在全局配置中。

? ?c. char*(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)

? ? 預設的14個配置項解析方法

預設方法名行為
ngx_conf_set_flag_slot如果ngxin.conf文件中某個配置項的參數是on或者off(即希望配置項表達打開或者關閉某個功能的意思),而且在Nginx模塊的代碼中使用ngx_flag_t變量來保存這個配置項的參數,就可以將set回調方法設為ngx_conf_set_flag_slot。當nginx.conf文件中參數是on時,代碼中的ngx_flag_t類型變量將設為1,參數為off時則設為0
ngx_conf_set_str_slot如果配置項后只有1個參數,同時在代碼中我們希望用ngx_str_t類型的變量來保存這個配置項的參數,則可以使用ngx_conf_set_str_slot方法
ngx_conf_set_str_array_slot如果這個配置項會出現多次,每個配置項后面都跟著1個參數,而在程序中我們希望僅用一個ngx_array_t動態數組來存儲所有的參數,且數組中的每個參數都以ngx_str_t來存儲,那么預設的ngx_conf_set_str_array_slot方法可以幫我們做到
ngx_conf_set_keyval_slot與ngx_conf_set_str_array_slot類似,也使用用一個ngx_array_t數組來存儲所有同名配置項的參數。只是每個配置項的參數不再只有1個,而必須是兩個,且以“配置項名 關鍵字 值;”的形式出現在nginx.conf文件中,同時,ngx_conf_set_keyval_slot將把這些配置項轉化為數組,其中每個元素都存儲著key/value鍵值對。
ngx_conf_set_num_slot

配置項后必須攜帶1個參數,且只能是數字。存儲這個參數的變量必須是整形

ngx_conf_set_size_slot

配置項后必須攜帶1個參數,表示空間大小,可以是一個數字,這時表示字節數(Byte)。如果數字后跟著k或者K,就表示Kilobyt,1KB=1024B;如果數字后跟著m或者M,就表示Megabyte,1MB=1024KB。ngx_conf_set_size_slot解析后將把配置項后的參數轉化成以字節數為單位的數字

ngx_conf_set_off_slot配置項后必須攜帶1個參數,表示空間上的偏移量。它與設置的參數非常類似,其參數是一個數字時表示Byte,也可以在后面加單位,但與ngx_conf_set_size_slot不同的是,數字后面的單位不僅可以是k或者K、m或者M,還可以是g或者G,這時表示Gigabyte,1GB=1024MB,ngx_conf_set_off_slot解析后將把配置項后的參數轉化成以字節數為單位的數字
ngx_conf_set_msec_slot配置項后必須攜帶1個參數,表示時間。這個參數可以在數字后面加單位,如果單位為s或者沒有任何單位,那么這個數字表示秒;如果單位為m,則表示分鐘,1m=60s;如果單位為h,則表示小時,1h=60m;如果單位為d,則表示天,1d=24h;如果單位為w,則表示周,1w=7d;如果單位為M,則表示月,1M=30d;如果單位為y,則表示年,1y=265d。ngx_conf_set_msec_slot解析后將把配置項后的參數轉化成以毫秒為單位的數字
ngx_conf_set_sec_slot與ngx_conf_set_msec_slot非常類似,唯一的區別是ngx_conf_set_msec_slot解析后將把配置項后的參數轉化成以毫秒為單位的數字,而ngx_conf_set_sec_slot解析后會把配置項后的參數轉化成以秒為單位的數字
ngx_conf_set_bufs_slot配置項后必須攜帶一兩個參數,第1個參數是數字,第2個參數表示空間大小。例如:"gzip_buffers 4 8k;"(通常用來表示有多少個ngx_buf_t緩沖區),其中第1個參數不可以攜帶任何單位,第2個參數不帶任何單位時表示Byte,如果yik或者K作為單位,則表示Kilobyte,如果以m或者M作為單位,則表示Megabyte。ngx_conf_set_bufs_slot解析后會把配置項后的兩個參數轉化成ngx_bufs_t結構體下的兩個成員,這個配置項對應于Nginx最喜歡用的多緩沖區的解決方案(如接受連接對端發來的TCP流)
ngx_conf_set_enum_slot配置項后必須攜帶1個參數,其取值范圍必須是我們設定好的字符串之一(就像C語言中的枚舉一樣),首先,我們要用ngx_conf_enum_t結構定義配置項的取值范圍,并設定每個值對應的序列號,然后,ngx_conf_set_enum_slot將會把配置項參數轉化為對應的序列號。
ngx_conf_set_bitmask_slot與ngx_conf_set_bitmask_slot類似,配置項后必須攜帶1個參數,其取值范圍必須是設定好的字符串只注意。首先,我們要用ngx_conf_bitmask_t結構定義配置項的取值范圍,并設定每個值對應的比特位。注意,每個值所對應的比特位都要不同,然后ngx_conf_set_bitmask_slot將會把配置項參數轉化為對應的比特位
ngx_conf_set_access_slot這個方法用于設置目錄或者文件的讀寫權限。配置項后可以攜帶1~3個參數,可以是如下形式:user:rw group:rw all:rw。注意,它的意義與Linux上文件或者目錄的權限意義視一致的,但是user/group/all后面的權限只可以設為rw(讀/寫)或者r(只讀),不可以有其他任何形式,如w或者rx等。ngx_conf_set_access_slot將會把這些參數轉化為一個整形。
ngx_conf_set_path_slot這個方法用于設置路徑,配置項后必須攜帶1個參數,表示1個有意義的路徑。ngx_conf_set_path_slot將會把參數轉化為ngx_path_t結構。

? ? d.ngx_uint_t conf

? ? ? ?conf用于指示配置項所處內存的相對偏移位置,僅在type中沒有設置NGX_DIRECT_CONF和NGX_MAIN_CONF時才會生效。對于HTTP模塊,conf是必須要設置的,它的取值范圍如下:

conf在HTTP模塊中的取值意義
NGX_HTTP_MAIN_CONF_OFFSET使用create_main_conf方法產生的結構體來存儲解析出的配置項參數
NGX_HTTP_SRV_CONF_OFFSET使用create_srv_conf方法產生的結構體來存儲解析出的配置項參數
NGX_HTTP_LOC_CONF_OFFSET使用create_loc_conf方法產生的結構體來存儲解析出的配置項參數

? ? e.ngx_uint_t offset

? ? ? offset表示當前配置項在整個存儲配置項啊的結構體中的偏移位置(以字節(Byte)為單位)。

? ? f.void *post

? ? ?一般置為NULL。

33.解析HTTP配置的流程

? ??

? ?(1) 主循環是指Nginx進程的主循環,主循環只有調用配置文件解析器才能解析nginx.conf文件(這里的"主循環"是指解析全部配置文件的循環代碼)。

? ?(2) 當發現配置文件中含有http{}關鍵字時,HTTP框架開始啟動,這一過程見ngx_http_block方法。

? ?(3) HTTP框架會初始化所有HTTP模塊的序列號,并創建3個數組用于存儲所有HTTP模塊的create_main_conf、create_srv_conf、create_loc_conf方法返回的指針地址,并把這3個數組的地址保存到ngx_http_conf_ctx_t結構中。

? ?(4) 調用每個HTTP模塊(當然也包括例子中的mytest模塊)的create_main_conf、create_srv_conf、create_loc_conf(如果實現的話)方法。

? ?(5) 把各HTTP模塊上述3個方法的地址依次保存到ngx_http_conf_ctx_t結構體的3個數組中。

? ?(6) 調用每個HTTP模塊的preconfiguration方法(如果實現的話).

? ?(7) 注意,如果preconfiguration返回失敗,那么Nginx進程將會停止。

? ?(8) HTTP框架開始循環解析nginx.conf文件中http{...}里面的所有配置項,注意,這個過程到第19步才會返回。

? ?(9) 配置文件解析器在檢測到1個配置項后,會遍歷所有的HTTP模塊,檢查它們的ngx_command_t數組中的name項是否與配置項名相同。

? ? (10) 如果找到有1個HTTP模塊對這個配置項感興趣,就調用ngx_command_t結構中的set方法來處理。

? ? (11) set方法返回是否處理成功。如果處理失敗,那么Nginx進程會停止。

? ? (12) 配置文件解析器繼續監測配置項。如果發現server{...}配置項,就會調用ngx_http_core_module模塊來處理。因為ngx_http_core_module模塊明確表示希望處理server{}塊下的配置項。注意,這次調用到第18步才會返回。

? ? (13) ngx_http_core_module模塊在解析server{...}之前,也會如第3步一樣建立ngx_http_conf_ctx_t結構,并建立數組保存所有HTTP模塊返回的指針地址。然后,它會調用每個HTTP模塊的create_srv_conf、create_loc_conf方法(如果實現的話).

? ? (14) 將上一步各HTTP模塊返回的指針地址保存到ngx_http_conf_ctx_t對應的數組中。

? ? (15) 開始調用配置文件解析器來處理server{...}里面的配置項,注意,這個過程在第17步返回。

? ? (16) 繼續重復第9步的過程,遍歷nginx.conf中當前server{...}內的所有配置項。

? ? (17)配置文件解析器繼續解析配置項,發現當前server塊已經遍歷到尾部,說明server塊內的配置項處理完畢,返回ngx_http_core_module模塊。

? ? (18) http core模塊也處理完server配置項了,返回至配置文件解析器繼續解析后面的配置項。

? ? (19) 配置文件解析器繼續解析配置項,這時發現處理到了http{...}的尾部,返回給HTTP框架繼續處理。

? ? (20) 在第3步和第13步,以及我們沒有列出來的某些步驟中(如發現其他server塊或者location塊),都創建了ngx_http_conf_ctx_t結構體,這時將開始調用merge_srv_conf、merge_loc_conf等方法合并這些不同塊(http、server、location)中每個HTTP模塊分配的數據結構。

? ? (21) HTTP框架處理完畢http配置項(也就是ngx_command_t結構中的set回調方法處理完畢),返回給配置文件解析器繼續處理其他http{...}外的配置項。

? ? (22) 配置文件解析器處理完所有配置項后會告訴Nginx主循環配置項解析完畢,這時Nginx才會啟動Web服務器。

34.http塊與server塊下的ngx_http_conf_ctx_t所指向的內存間的關系

? ?

35.合并配置項過程的活動圖,主要包含四大部分內容:

? ?(1) 如果HTTP模塊實現了merge_srv_conf方法,就將http{...}塊下create_srv_conf生成的結構體與遍歷每一個server{...}配置塊下的結構體做merge_srv_conf操作;

? ?(2) 如果HTTP模塊實現了merge_loc_conf方法,就將http{...}塊下create_loc_conf生成的結構體與嵌套的每一個server{...}配置塊下生成的結構體做merge_loc_conf操作;

? ?(3) 如果HTTP模塊實現了merge_loc_conf方法,就將server{...}塊下create_loc_conf生成的結構體與嵌套的每一個location{...}配置塊下create_loc_conf生成的數據結構做merge_loc_conf操作;

? ?(4) 如果HTTP模塊實現了merge_loc_conf方法,就將location{...}塊下create_loc_conf生成的結構體與繼續嵌套的每一個location{...}配置塊下create_loc_conf生成的數據結構做merge_loc_conf操作。

? ?

? 上圖中包括4重循環,第1層(最外層)遍歷所有的HTTP模塊,第2層遍歷所有的server{...}配置塊,第3層是遍歷某個server{}塊中嵌套的所有location{...}塊,第4層遍歷某個location{}塊中繼續嵌套的所有location塊(實際上,它會一直遞歸下去以解析可能被層層嵌套的location塊).

36.請求的上下文

? ? 在Nginx中,上下文有很多種含義。HTTP框架定義的這個上下文是針對于HTTP請求的,而且一個HTTP請求對應于每一個HTTP模塊都可以有一個獨立的上下文結構體(并不是一個請求的上下文由所有HTTP模塊共用)。

37.ngx_http_get_module_ctx和ngx_http_set_ctx這兩個宏可以完成HTTP上下文的設置和使用。

#define ngx_http_get_module_ctx(r, module) (r)->ctx[module.ctx_index] #define ngx_http_set_ctx(r, c, module) r->ctx[module.ctx_index] = c;

? ?當請求第1次進入mytest模塊處理時,創建ngx_http_mytest_ctx_t結構體,并設置到這個請求的上下文中。

static ngx_int_t ngx_http_mytest_handler(ngx_http_request_t *r) {//首先調用ngx_http_get_module_ctx宏來獲取上下文結構體ngx_http_mytest_ctx_t *myctx = ngx_http_get_module_ctx(r, ngx_http_mytest_module);//如果之前沒有設置過上下文,那么應當返回NULL。if (myctx == NULL) {/*必須在當前請求的內存池r->pool中分配上下文結構體,這樣請求結束時結構體占用的內存才會釋放*/myctx = ngx_palloc(r->pool, sizeof(ngx_http_mytest_ctx_t));if (myctx == NULL) {return NGX_ERROR;}//將剛分配的結構體設置到當前請求的上下文中ngx_http_set_ctx(r, myctx, ngx_http_mytest_module);}//之后可以任意使用myctx這個上下文結構體... }

38.模塊在處理任何一個請求時都有ngx_http_request_t結構的對象r,而請求r中又有一個ngx_http_upstream_t類型的成員upstream.

typedef struct ngx_http_request_s ngx_http_request_t; struct ngx_http_request_s {...ngx_http_upstream_t *upstream;... };

39.啟動upstream的流程圖

? ?

40.upstream執行的一般流程

??

41.ngx_http_upstream_t結構體

typedef struct ngx_http_upstream_s ngx_http_upstream_t; struct ngx_http_upstream_s {.../* request_bufs決定發送什么樣的請求給上游服務器,在實現create_request方法是需要設置它 */ngx_chain_t *request_bufs;//upstream訪問時的所有限制性參數ngx_http_upstream_conf_t *conf;//通過resolved可以直接指定上游服務器地址ngx_http_upstream_resolved_t *resolved;/* buffer成員存儲接收自上游服務器發來的響應內容,由于它會被復用,所以具有下例多種意義:* a) 在使用process_header方法解析上游響應的包頭時,buffer中將會保存完整的響應包頭;* b) 當下面的buffering成員為1,而且此時upstream是向下游轉發上游的包體時,buffer沒有意義;* c) 當buffering標志位位0時,buffer緩沖區會被用于反復地接收上游的包體,進而向下游轉發;* d) 當upstream并不用于轉發上游包體時,buffer會被用于反復接收上游的包體,HTTP模塊實現的input_filter方法需要關注它*/ngx_buf_t buffer;//構造發往上游服務器的請求內容ngx_int_t (*create_request)(ngx_http_request_t *r);/* 銷毀upstream請求時調用 */void (*finalize_request)(ngx_http_request_t *r, ngx_int_t rc);//5個可選的回調方法ngx_int_t (*input_filter_init)(void *data);ngx_int_t (*input_filter)(void *data, ssize_t bytes);ngx_int_t (*reinit_request)(ngx_http_request_t *r);void (*abort_request)(ngx_http_request_t *r);ngx_int_t (*rewrite_redirect)(ngx_http_request_t *r, ngx_table_elt_t *h, size_t prefix);//是否基于SSL協議訪問上游服務器unsigned ssl:1;/* 在向客戶端轉發上游服務器的包體時才有用。當buffering為1時,表示使用多個緩沖區以及磁盤文件來轉發上有的響應包體。當Nginx與上游間的網速遠大于Nginx與下游客戶端見的網速時,讓Nginx開辟更多的內存甚至使用磁盤文件來緩存上游的響應包體,這是有意義的,它可以減輕上游服務器的并發壓力。當buffering為0時,表示只使用上面的這一個buffer緩沖區來向下游轉發響應包體*/unsigned buffering:1;... };

42.設置upstream的限制性參數

? ? ngx_http_upstream_t中的conf成員,它用于設置upstream模塊處理請求時的參數,包括連接、發送、接收的超時時間等。

typedef struct {...//連接上游服務器的超時時間,單位為毫秒ngx_msec_t connect_timeout;//發送TCP包到上游服務器的超時時間,單位為毫秒ngx_msec_t send_timeout;//接收TCP包到上游服務器的超時時間,單位為毫秒ngx_msec_t read_timeout;... } ngx_http_upstream_conf_t;

43.ngx_http_upstream_t結構中的resolved成員可以直接設置上游服務器的地址,首先介紹一下resolved的類型:

typedef struct {...//地址個數ngx_uint_t naddrs;//上游服務器的地址struct sockaddr *sockaddr;socklen_t socklen;... } ngx_http_upstream_resolved_t;

44.直接執行ngx_http_upstream_init方法即可啟動upstream機制。

45.create_request回調方法

? ??

? ? 如上圖,步驟分別如下:

? ? 1) 在Nginx主循環(之類的主循環是指ngx_worker_process_cycle方法)中,會定期地調用事件模塊,以檢查是否有網絡事件發生。

? ? 2)事件模塊在接收到HTTP請求后會調用HTTP框架來處理。假設接收、解析完HTTP頭部后發現應該由mytest模塊處理,這時會調用mytest模塊的ngx_http_mytest_handler來處理。

? ? 3)設置回調函數和第三方地址;

? ? 4)調用ngx_http_upstream_init方法啟動upstream;

? ? 5)upstream模塊會去檢查文件緩存,如果緩存中已經有合適的響應包,則會直接返回緩存(當然必須是在使用反向代理文件緩存的前提下)。

? ? 6)回調mytest模塊已經實現的create_request回調方法;

? ? 7)mytest模塊通過設置r->upstream->request_bufs已經決定好發送什么樣的請求到上有服務器。

? ? 8)upstream模塊會檢查已經介紹過的resolved成員,如果有resolved成員的話,就根據它設置好上游服務器的地址r->upstream->peer成員。

? ? 9)用無阻塞的TCP套接字建立連接;

? ? 10)無論連接是否建立成功,負責建立連接的connect方法都會立刻返回。

? ? 11)ngx_http_upstream_init返回;

? ? 12)mytest模塊的ngx_http_mytest_handler方法返回NGX_DONE。

? ? 13)當事件模塊處理完這批網絡事件后,將控制權交還給Nginx主循環.

46.reinit_request可能會被多次回調。它被調用的原因只有一個,就是在第一次試圖向上游服務器建立連接時,如果連接由于各種異常原因失敗,那么會根據upstream中conf參數的策略要求再次重連上游服務器,而這時就會調用reinit_request方法了。

? ??

? ? ? 上圖中的流程的步驟描述如下:

? ? ? 1) Nginx主循環中會定期地調用事件模塊,檢查是否有網絡事件發生。

? ? ? 2) 事件模塊在確定與上游服務器的TCP連接建立成功后,會回調upstream模塊的相關方法處理。

? ? ? 3) upstream模塊這時會把r->upstream->request_sent標志位置為1,表示連接已經建立成功了,現在開始向上游服務器發送請求內容。

? ? ? 4) 發送請求到上游服務器。

? ? ? 5) 發送方法當然是無阻塞的(使用了無阻塞的套接字),會立刻返回。

? ? ? 6) upstream模塊處理第2步中的TCP連接建立成功事件。

? ? ? 7) 事件模塊處理完本輪網絡事件后,將控制權交還給Nginx主循環。

? ? ? 8) Nginx主循環重復第1步,調用事件模塊檢查網絡事件。

? ? ? 9) 這時,如果發現與上游服務器建立的TCP連接已經異常斷開,那么事件模塊會通知upstream模塊處理它。

? ? ? 10) 在符合重試次數的前提下,upstream模塊會毫不猶豫地再次用無阻塞的套接字試圖建立連接。

? ? ? 11) 無論連接是否建立成功都立刻返回。

? ? ? 12) 這時檢查r->upstream->request_sent標志位,會發現它已經被置為1了。

? ? ? 13) 如果mytest模塊沒有實現reinit_request方法,那么是不會調用它的。而如果reinit_request不為NULL空指針,就會回調它。

? ? ? ?14) mytest模塊在reinit_request中處理完自己的事情。

? ? ? ?15) 處理完第9步中的TCP連接斷開事件,將控制權交還給事件模塊。

? ? ? ?16) 事件模塊處理完本輪網絡事件后,交還控制權給Nginx主循環。

47.finalize_request回調方法

? ? 當調用ngx_http_upstream_init啟動upstream機制后,在各種原因(無論成功還是失敗)導致該請求被銷毀前都會調用finalize_request方法。

? ? 在finalize_request方法中可以不做任何事情,但必須實現finalize_request方法,否則Nginx會出現空指針調用的嚴重錯誤。

48.process_header回調方法

? ? process_header是用于解析上游服務器返回的基于TCP的響應頭部的,因此,process_header可能會被多次調用,它的調用次數與process_header的返回值有關。如果process_header返回NGX_AGAIN,這意味著還沒有接收到完整的響應頭部,如果再次接收到上游服務器發來的TCP流,還會把它當做頭部,仍然調用process_header處理。如果process_header返回NGX_OK(或者其他非NGX_AGAIN的值),那么在這次連接的后續處理中將不會再次調用process_header。

? ?

? ? 上圖中的步驟解釋:
? ?1) Nginx主循環中會定期地調用事件模塊,檢查是否有網絡事件發生。

? ?2) 事件模塊接收到上游服務器發來的響應時,會回調upstream模塊處理。

? ?3) upstream模塊這時可以從套接字緩沖區中讀取到來自上游的TCP流。

? ?4) 讀取的響應會存放到r->upstream->buffer指向的內存中。注意:在未解析完響應頭部前,若多次接收到字符流,所有接收自上游的響應頭回完整地存放到r->upstream->buffer緩沖區中。因此,在解析上游響應包頭時,如果buffer緩沖區全滿卻還沒有解析到完整的響應頭部(也就是說,process_header一直在返回NGX_AGAIN),那么請求就會出錯。

? ?5) 調用mytest模塊實現的process_header方法。

? ?6) process_header方法實際上就是在解析r->upstream->buffer緩沖區,試圖從中取到完整的響應頭部(當然,如果上游服務器與Nginx通過HTTP通信,就是接收到完整的HTTP頭部)。

? ?7) 如果process_header返回NGX_AGAIN,那么表示還沒有解析到完整的響應頭部,下次還會調用process_header處理接收到的上游響應。

? ?8) 調用無阻塞的讀取套接字接口。

? ?9) 這時有可能返回套接字緩沖區已經為空。

? ?10) 當第2步中的讀取上游響應時間處理完畢后,控制權交還給事件模塊。

? ?11) 事件模塊處理完本輪網絡事件后,交還控制權給Nginx主循環。

49.舉例說明upstream機制。實現的功能很簡單:"即以訪問mytest模塊的URL參數作為搜索引擎的關鍵字,用upstream方式訪問google,查詢URL里的參數,然后把google的結果返回給用戶。"

? ?每一個HTTP請求都會有獨立的ngx_http_upstream_conf_t結構體,在mytest模塊的例子中,所有的請求都將共享同一個ngx_http_upstream_conf_t結構體,因此,這里把它放到ngx_http_mytest_conf_t配置結構體中,如下所示:

typedef struct {ngx_http_upstream_conf_t upstream; } ngx_http_mytest_conf_t;

? ?(1) 在啟動upstream前,先將ngx_http_mytest_conf_t下的upstream成員賦給r->upstream->conf成員。

static void *ngx_http_mytest_create_loc_conf(ngx_conf_t *cf) {ngx_http_mytest_conf_t *mycf;mycf = (ngx_http_mytest_conf_t *)ngx_pcalloc(cf->pool, sizeof(ngx_http_mytest_conf_t));if (mycf == NULL) {return NULL;}/* 以下簡單的硬編碼ngx_http_upstream_conf_t結構中的各成員,如超時事件,都設為1分鐘,這也是HTTP反向代理模塊的默認值*/mycf->upstream.connect_timeout = 60000;mycf->upstream.send_timeout = 60000;mycf->upstream.read_timeout = 60000;mycf->upstream.store_access = 0600;/* 實際上,buffering已經決定了將以固定大小的內存作為緩沖區來轉發上游的響應包體,這塊固定緩沖區的大小就是buffer_size。如果buffering為1,就會使用更多的內存緩存來不及發往下游的響應。例如,最多使用bufs.num個緩沖區且每個緩沖區大小為bufs.size。另外,還會使用臨時文件,臨時文件的最大長度為max_temp_file_size */mycf->upstream.buffering = 0;mycf->upstream.bufs.num = 8;mycf->upstream.bufs.size = ngx_pagesize;mycf->upstream.buffer_size = ngx_pagesize;mycf->upstream.busy_buffers_size = 2*ngx_pagesize;mycf->upstream.temp_file_write_size = 2 * ngx_pagesize;mycf->upstream.max_temp_file_size = 1024 * 1024 * 1024;/* upstream模塊要求hide_headers成員必須要初始化(upstream在解析完上游服務器返回的包頭時,會調用ngx_http_upstream_process_headers方法按照hide_headers成員將本應轉發給下游的一些HTTP頭部隱藏),這里將它賦為NGX_CONF_UNSET_PTR,這是為了在merge合并配置項方法中使用upstream模塊提供的ngx_http_upstream_hide_headers_hash方法初始化hide_headers成員 */mycf->upstream.hide_headers = NGX_CONF_UNSET_PTR;mycf->upstream.pass_headers = NGX_CONF_UNSET_PTR:retrurn mycf; }static char *ngx_http_mytest_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) {ngx_http_mytest_conf_t *prev = (ngx_http_mytest_conf_t *)parent;ngx_http_mytest_conf_t *conf = (ngx_http_mytest_conf_t *)child;ngx_hash_init_t hash;hash.max_size = 100;hash.bucket_size = 1024;hash.name = "proxy_headers_hash";if (ngx_http_upstream_hide_headers_hash(cf, &conf->upstream, &prev->upstream, ngx_http_proxy_hide_headers, &hash) != NGX_OK) {return NGX_CONF_ERROR;}return NGX_CONF_OK; }

? 本例必須要使用上下文才能正確地解析upstream上游服務器的響應包,因為upstream模塊每次接收到一段TCP流時都會回調mytest模塊實現的process_header方法解析,這樣就需要有一個上下文保存解析狀態。

? ? ? (2) 在create_request方法中構造請求

? ? ? ? ?下面方法用于創建發送給上游服務器的HTTP請求,upstream模塊將會回調它,實現如下:

static ngx_int_t mytest_upstream_create_request(ngx_http_request_t *r) {/* 在發往google上游服務器的請求很簡單,就是模仿正常的搜索請求,以/search?q=...的URL來發起搜索請求。backendQueryLine中的%V等轉化格式的用法*/static ngx_str_t backendQueryLine = ngx_string("GET /search?q=%V HTTP/1.1\r\nHost: www.google.com\r\nConnection: close\r\n\r\n");ngx_int_t queryLineLen = backendQueryLine.len + r->args.len - 2;/* 必須在內存池中申請內存,這有以下兩點好處:一個好處是,在網絡情況不佳的情況下,向上游服務器發送請求時,可能需要epoll多次調度send才能發送完成,這時必須保證這段內存不會被釋放;另一個好處是,在請求結束時,這段內存會被自動釋放,減低內存泄露的可能性*/ngx_buf_t *b = ngx_create_temp_buf(r->pool, queryLineLen);if (b == NULL) {return NGX_ERROR;}//last要指向請求的末尾b->last = b->pos + queryLineLen;//作用相當于snprintfngx_snprintf(b->pos, queryLineLen, (char *)backendQueryLine.data, &r->args);/* r->upstream->request_bufs是一個ngx_chain_t結構,它包含著要發送給上游服務器的請求 */r->upstream->request_bufs = ngx_alloc_chain_link(r->pool);if (r->upstream->request_bufs == NULL) return NGX_ERROR;//request_bufs在這里只包含1個ngx_buf_t緩沖區r->upstream->request_bufs->buf = b;r->upstream->request_bufs->next = NULL;r->upstream->request_sent = 0;r->upstream->header_sent = 0;// header_hash不可以為0r->header_hash = 1;return NGX_OK; }

? ? ? ? ? (3) 在process_header方法中解析包頭

? ? ? ? ? ? ?process_header負責解析上游服務器發來的基于TCP的包頭,在本例中,就是解析HTTP響應行和HTTP頭部,因此,這里使用mytest_process_status_line方法解析HTTP響應行,使用mytest_upstream_process_header方法解析http響應頭部。

static ngx_int_t mytest_process_status_line(ngx_http_request_t *r) {size_t len;ngx_int_t rc;ngx_http_upstream_t *u;//上下文中才會保存多次解析HTTP響應行的狀態,下面首先取出請求的上下文ngx_http_mytest_ctx_t *ctx = ngx_http_get_module_ctx(r, ngx_http_mytest_module);if (ctx == NULL) {return NGX_ERROR;}u = r->upstream;/* HTTP框架提供的ngx_http_parse_status_line方法可以解析HTTP響應行,它的輸入就是收到的字符流和上下文中的ngx_http_status_t結構 */rc = ngx_http_parse_status_line(r, &u->buffer, &ctx->status);//返回NGX_AGAIN時,表示還沒有解析出完整的HTTP響應行,需要接受更多的字符流再進行解析if (rc == NGX_AGAIN) {return rc;}//返回NGX_ERROR時,表示沒有接收到合法的HTTP響應行if (rc == NGX_ERROR) {ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,"upstream sent no valid HTTP/1.0 header");r->http_version = NGX_HTTP_VERSION_9;u->state->status = NGX_HTTP_OK;return NGX_OK;}/* 以下表示在解析到完整的HTTP響應行時,會做一些簡單的賦值操作,將解析出的信息設置到r->upstream->headers_in結構體中。當upstream解析完所有的包頭時,會把headers_in中的成員設置到 將要向下游發送的r->headers_out結構體中,也就是說,現在用戶向headers_in中設置的信息,最終都會發往下游客戶端。為什么不直接設置r->headers_out而要多此一舉呢?因為upstream希望能夠按照ngx_http_upstream_conf_t配置結構體中的hide_headers等成員對發往下游的響應頭部做統一處理 */if (u->state) {u->state->status = ctx->status.code;}u->headers_in.status_n = ctx->status.code;len = ctx->status.end - ctx->status.start;u->headers_in.status_line.len = len;u->headers_in.status_line.data = ngx_pnalloc(r->pool, len);if (u->headers_in.status_line.data == NULL) {return NGX_ERROR;}ngx_memcpy(u->headers_in.status_line.data, ctx->status.start, len);/* 下一步將開始解析HTTP頭部。設置process_header回調方法為mytest_upstream_process_header,之后再收到的新字符流將由mytest_upstream_process_header解析 */u->process_header = mytest_upstream_process_header;/* 如果本次收到的字符流除了HTTP響應行外,還有多余的字符,那么將由mytest_upstream_process_header方式解析 */return mytest_upstream_process_header(r); }

? mytest_upstream_process_header方法可以解析HTTP響應頭部,而這里只是簡單地把上游服務器發送的HTTP頭部添加到了請求r->upstream->headers_in.headers鏈表中。如果有需要特殊處理的HTTP頭部,那么應該在mytest_upstream_process_header方法中進行。

static ngx_int_t mytest_upstream_process_header(ngx_http_request_t *r) {ngx_int_t rc;ngx_table_elt_t *h;ngx_http_upstream_header_t *hh;ngx_http_upstream_main_conf_t *umcf;/* 這里將upstream模塊配置項ngx_http_upstream_main_conf_t取出來,目的只有一個,就是對將要轉發給下游客戶端的HTTP響應頭部進行統一處理。該結構體中存儲了需要進行統一處理的HTTP頭部名稱和回調方法 */umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);//循環地解析所有的HTTP頭部for (;;) {/* HTTP框架提供了基礎性的ngx_http_parse_haeder_line方法,它用于解析HTTP頭部 */rc = ngx_http_parse_header_line(r, &r->upstream->buffer, 1);//返回NGX_OK時,表示解析出一行HTTP頭部if (rc == NGX_OK) {// 向headers_in.headers這個ngx_list_t鏈表中添加HTTP頭部h = ngx_list_push(&r->upstream->headers_in.headers);if (h == NULL) {return NGX_ERROR;}//下面開始構造剛剛添加到headers鏈表中的HTTP頭部h->hash = r->header_hash;h->key.len = r->header_name_end - r->header_name_start;h->value.len = r->header_end - r->header_start;//必須在內存池中分配存放HTTP頭部的內存空間h->key.data = ngx_pnalloc(r->pool, h->key.len + 1 + h->value.len + 1 + h->key.len);if (h->key.data == NULL) {return NGX_ERROR;}h->value.data = h->key.data + h->key.len + 1;h->lowcase_key = h->key.data + h->key.len + 1 + h->value.len + 1;ngx_memcpy(h->key.data, r->header_name_start, h->key.len);h->key.data[h->key.len] = '\0';ngx_memcpy(h->value.data, r->header_start, h->value.len);h->value.data[h->value.len] = '\0';if (h->key.len == r->lowcase_index) {ngx_memcpy(h->lowcase_key, r->lowcase_header, h->key.len);} else {ngx_strlow(h->lowcase_key, h->key.data, h->key.len);}//upstream模塊會對一些HTTP頭部做特殊處理hh = ngx_hash_find(&umcf->headers_in_hash, h->hash, h->lowcase_key, h->key.len);if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {return NGX_ERROR;}continue;}/* 返回NGX_HTTP_PARSE_HEADER_DONE時,表示響應中所有的HTTP頭部解析完畢,接下來在接收到的都將是HTTP包體 */if (rc == NGX_HTTP_PARSE_HEADER_DONE) {/* 如果之前解析HTTP頭部時沒有發現server和date頭部,那么下面會根據HTTP協議規范添加這兩個頭部 */if (r->upstream->headers_in.server == NULL) {h = ngx_list_push(&r->upstream->headers_in.headers);if (h == NULL) {return NGX_ERROR;}h->hash = ngx_hash(ngx_hash(ngx_hash(ngx_hash(ngx_hash('s', 'e'), 'r'), 'v'), 'e'), 'r');ngx_str_set(&h->key, "Date");ngx_str_null(&h->value);h->lowcase_key = (u_char *) "date";}return NGX_OK;}/* 如果返回NGX_AGAIN, 則表示狀態機還沒有解析到完整的HTTP頭部,此時要求upstream模塊繼續接收新的字符流,然后交由process_header回調方法解析 */if (rc == NGX_AGAIN) {return NGX_AGAIN;}//其他返回值都是非法的ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "upstream sent invalid header");return NGX_HTTP_UPSTREAM_INVALID_HEADER;} }

? ?當mytest_upstream_process_header返回NGX_OK后,upstream模塊開始把上游的包體(如果有的話)直接轉發到下游客戶端。

? ? ? ? ? (4) 在finalize_request方法中釋放資源

? ? ? ? ? ? ? ? 當請求結束時,將會回調finalize_request方法,如果我們希望此時釋放資源,如打開的句柄等,那么可以把這樣的代碼添加到finalize_request方法中。本例中定義了mytest_upstream_finalize_request方法,由于我們沒有任何需要釋放的資源,所以該方法沒有完成任何實際工作,只是因為upstream模塊要求必須實現finalize_request回調方法。

? ? ? ?? ?(5) 在ngx_http_mytest_handler方法中啟動upstream

? ? ? ? ? ? ? ? ?在開始介入處理客戶端請求的ngx_http_mytest_handler方法中啟動upstream機制,而何時會結束,則視Nginx與上游的google服務器間的通信而定。

static ngx_int_t ngx_http_mytest_handler(ngx_http_request_r *r) {//首先建立HTTP上下文結構體ngx_http_mytest_ctx_tngx_http_mytest_ctx_t *myctx = ngx_http_get_module_ctx(r, ngx_http_mytest_module);if (myctx == NULL) {myctx = ngx_palloc(r->pool, sizeof(ngx_http_mytest_ctx_t));if (myctx == NULL) {return NGX_ERROR;}//得到配置結構體ngx_http_mytest_conf_tngx_http_mytest_conf_t *mycf = (ngx_http_mytest_conf_t *)ngx_http_get_module_loc_conf(r, ngx_http_mytest_module);ngx_http_upstream_t *u = r->upstream;//這里用配置文件中的結構體來賦給r->upstream->conf成員u->conf = &mycf->upstream;//決定轉發包體時使用的緩沖區u->buffering = mycf->upstream.buffering;//以下代碼開始初始化resolved結構體,用來保存上游服務器的地址u->resolved = (ngx_http_upstream_resolved_resolved_t *)ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t));if (u->resolved == NULL) {ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ngx_pcalloc resolved error. %s.", strerror(errno));return NGX_ERROR;}//這里的上游服務器就是www.google.comstatic struct sockaddr_in backendSockAddr;struct hostent *pHost = gethostbyname((char *) "www.google.com");if (pHost == NULL) {ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "gethostbyname fail. %s", strerror(errno));return NGX_ERROR;}//訪問上游服務器的80端口backendSockAddr.sin_family = AF_INET;backendSockAddr.sin_port = htons((in_port_t) 80);char *pDmsIP = inet_ntoa(*(struct in_addr *) (pHost->h_addr_list[0]));backendSockAddr.sin_addr.s_addr = inet_addr(pDmsIP);myctx->backendServer.data = (u_char *)pDmsIP;myctx->backendServer.len = strlen(pDmsIP);//將地址設置到resolved成員中u->resolved->sockaddr = (struct sockaddr *)&backendSockAddr;u->resolved->socklen = sizeof(struct sockaddr_in);u->resolved->naddrs = 1;// 設置3個必須實現的回調方法u->create_request = mytest_upstream_create_request;u->process_header = mytest_process_status_line;u->finalize_request = mytest_upstream_finalize_request;//這里必須將count成員加1r->main->count++;//啟動upstreamngx_http_upstream_init(r);//必須返回NGX_DONEreturn NGX_DONE;}

? ? ? ? ? ?到此為止,高性能地訪問第三方服務的upstream例子就介紹完了。在本例中,可以完全異步地訪問第三方服務,并發訪問數也只會受制于物理內存的大小,完全可以輕松達到幾十萬的并發TCP連接。

50.使用subrequest的方式只需要完成以下4步操作即可:

? ? 1) 在nginx.conf文件中配置好子請求的處理方式;

? ? 2) 啟動subrequest子請求;

? ? 3) 實現子請求執行結束時的回調方法;

? ? 4) 實現父請求被激活時的回調方法。

51.ngx_http_subrequest的定義:

ngx_int_t ngx_http_subrequest(ngx_http_request_t *r,ngx_str_t *uri, ngx_str_t *args, ngx_http_request_t **psr,ngx_http_post_subrequest_t *ps, ngx_uint_t flags);

? ? ?1) ngx_http_request_t *r

? ? ? ? ? ngx_http_request_t *r 是當前的請求,也就是父請求。

? ? ? 2) ngx_str_t *uri

? ? ? ? ? ngx_str_t *uri是子請求的URI,它對究竟選用nginx.conf配置文件中的哪個模塊來處理子請求起決定性作用。

? ? ? 3) ngx_str_t *args

? ? ? ? ? ngx_str_t *args是子請求的URI參數,如果沒有參數,可以傳送NULL空指針。

? ? ? ?4) ngx_http_request_t **psr

? ? ? ? ? psr是輸出參數而不是輸入參數,它將把ngx_http_subrequest生成的子請求傳出來。

? ? ? ? 5) ngx_http_post_subrequest_t *ps

? ? ? ? ? 這里傳入創建的ngx_http_post_subrequest_t結構體地址,它指出子請求結束時必須回調的處理方法。

? ? ? ? ?6) ngx_uint_t flags

? ? ? ? ? ?flag的取值范圍包括: (1) 0.在沒有特殊需求的情況下都應該填寫它; (2) NGX_HTTP_SUBREQUEST_IN_MEMORY。這個宏會將子請求的subrequest_in_memory標志位置為1,這意味著如果子請求使用upstream訪問上游服務器,那么上游服務器的響應都將會在內存中處理;(3) NGX_HTTP_SUBREQUEST_WAITED。這個宏會將子請求的waited標志位置為1,當子請求提前結束時,有個done標志位置為1,但目前HTTP框架并沒有針對這兩個標志位做任何實質性處理。注意,flag是按比特位操作的,這樣可以同時包含上述3個值。

? ? ? ? ?7) 返回值

? ? ? ? ? ? 返回NGX_OK表示成功建立子請求;返回NGX_ERROR表示建立子請求失敗。

52.如何啟動subrequest

? ? ?處理父請求的過程中會創建子請求,在父請求的處理方法返回NGX_DONE后,HTTP框架會開始執行子請求

? ? ??

? ? ? ?上圖中的步驟如下:

? ? ? ?1) Nginx主循環中會定期地調用事件模塊,檢查是否有網絡事件發生;

? ? ? ?2) 事件模塊發現這個請求的回調方法屬于HTTP框架,交由HTTP框架來處理請求。

? ? ? ?3) 根據解析完的URI來決定使用哪個location下的模塊來處理這個請求。

? ? ? ?4) 調用mytest模塊的ngx_http_mytest_handler方法處理這個請求。

? ? ? ?5) 設置subrequest子請求的URI及回調方法。

? ? ? ?6) 調用ngx_http_subrequest方法創建子請求。

? ? ? ?7) 創建的子請求會添加到原始請求的posted_requests鏈表中,這樣保證第10步時會在父請求返回NGX_DONE的情況下開始執行子請求。

? ? ? ?8) ngx_http_subrequest方法執行完畢,子請求創建成功。

? ? ? ?9) ngx_http_mytest_handler方法執行完畢,返回NGX_DONE,這樣父請求不會被銷毀,將等待以后的再次激活。

? ? ? ?10) HTTP框架執行完當前請求(父請求)后,檢查posted_requests鏈表中是否還有子請求,如果存在子請求,則調用子請求的write_event_handler方法。

? ? ? ? 11) 根據子請求的URI(第5步中建立),檢查nginx.conf文件中所有的location配置,確定應由哪個模塊來執行子請求。在本章的例子中,子請求是交由反向代理模塊執行的。

? ? ? ? 12) 調用反向代理模塊的入口方法ngx_http_proxy_handler來處理子請求。

? ? ? ? ?13) 由于反向代理模塊使用了upstream機制,所以它也要通過許多次的異步調用才能完整地處理完子請求,這時它的入口方法會返回NGX_DONE.

? ? ? ? ?14) 再次檢查是否還有子請求,這時會發現已經沒有子請求需要執行了。當然,子請求可以繼續建立新的子請求,只是這里的反向代理模塊不會這樣做。

? ? ? ? ?15) 當第2步中的網絡讀取事件處理完畢后,交還控制權給事件模塊。

? ? ? ? ?16) 當本輪網絡事件處理完畢后,交還控制權給Nginx主循環。

53.如何轉發多個子請求的響應包體

? ? ?每個請求的ngx_http_request_t結構體中都有一個postponed成員:

struct ngx_http_request_s {...ngx_http_postponed_request_t *postponed;... } 它實際上是一個鏈表: typedef struct ngx_http_postponed_request_s ngx_http_postponed_request_t; struct ngx_http_postponed_request_s {ngx_http_request_t *request;ngx_chain_t *out;ngx_http_postponed_request_t *next; };

? ? ? ? 多個ngx_http_postponed_request_t之間使用next指針連接成一個單向鏈表。ngx_http_postponed_request_t中的out成員是ngx_chain_t結構,它指向的是來自上游的、將要轉發給下游的響應包體。

? ? ? ? 每當使用ngx_http_output_filter方法(反向代理模塊也使用該方法轉發響應)向下游的客戶端發送響應包體時,都會調用到ngx_http_postpone_filter_module過濾模塊處理這段要發送的包體。

//這里的參數in就是將要發送給客戶端的一段包體 static ngx_int_t ngx_http_postpone_filter(ngx_http_request_t *r, ngx_chain_t *in) {ngx_connection_t *c;ngx_http_postponed_request_t *pr;//c是Nginx與下游客戶端間的連接,c->data保存的是原始請求c = r->connection;//如果當前請求r是一個子請求(因為c->data指向原始請求)if (r != c->data) {/* 如果待發送的in包體不為空,則把in加到postponed鏈表中屬于當前請求的ngx_http_postponed_request_t結構體的out鏈表中,同時返回NGX_OK,這意味著本次不會把in包體發送客戶端*/if (in) {ngx_http_postpone_filter_add(r, in);return NGX_OK;}//如果當前請求是子請求,而in包體又為空,那么直接返回即可return NGX_OK;}//如果postponed為空,表示請求r沒有子請求產生的響應需要轉發if (r->postponed == NULL) {/* 直接調用下一個HTTP過濾模塊繼續處理in包體即可。如果沒有錯誤的話,就會向下游客戶端發送響應 */if (in || c->buffered) {return ngx_http_next_filter(r->main, in);}return NGX_OK;}/* 至此,說明postponed鏈表中是有子請求產生的響應需要轉發的,可以先把in包體加到待轉發響應的末尾 */if (in) {ngx_http_postpone_filter_add(r, in);}//循環處理postponed鏈表中所有子請求待轉發的包體do {pr = r->postponed;/* 如果pr->request是子請求,則加入到原始請求的posted_requests隊列中,等待HTTP框架下次調用這個請求時再來處理 */if (pr->request) {r->postponed = pr->next;c->data = pr->request;return ngx_http_post_request(pr->request, NULL);}//調用下一個HTTP過濾模塊轉發out鏈表中保存的待轉發的包體if (pr->out == NULL) {} else {if (ngx_http_next_filter(r->main, pr->out) == NGX_ERROR) {return NGX_ERROR;}}//遍歷完postponed鏈表r->postponed = pr->next;} while (r->postponed);return NGX_OK; }

? ? ? ? ?

54.子請求在結束前會回調在ngx_http_post_subrequest_t中實現的handler方法,在這個handler方法中,又設置了父請求被激活后的執行方法mytest_post_handler,流程如下:

? ? ? ? ? ? ? ??

? ?上圖中的步驟如下:

? ? 1) Nginx主循環中會定期地調用事件模塊,檢查是否有網絡事件發生。

? ? 2) 如果事件模塊檢測到連接關閉事件,而這個請求的處理方法屬于upstream模塊,則交由upstream模塊來處理請求。

? ? 3) upstream模塊開始調用ngx_http_upstream_finalize_request方法來結束upstream機制下的請求。

? ? 4) 調用HTTP框架提供的ngx_http_finalize_request方法來結束子請求。

? ? 5) ngx_http_finalize_request方法會檢查當前的請求是否是子請求,如果是子請求,則會回調post_subrequest成員中的handler方法,也就是會調用mytest_subrequest_post_handler方法。

? ? 6) 在實現的子請求回調方法中,解析子請求返回的響應包。注意,這時需要通過write_event_handler設置父請求被激活后的回調方法(因此此時父請求的回調方法已經被HTTP框架設置為什么事情也不做的ngx_http_request_empty_handler方法).

? ? 7) 子請求的回調方法執行完畢后,交由HTTP框架的ngx_http_finalize_request方法繼續向下執行。

? ? 8) ngx_http_finalize_request方法執行完畢。

? ? 9) HTTP框架如果發現當前請求后還有父請求需要執行,則調用父請求的write_event_handler回調方法。

? ? 10) 這里可以根據第6步中解析子請求響應后的結果來構造響應包。

? ? ?11) 調用無阻塞的ngx_http_send_header、ngx_http_output_filter發送方法,向客戶端發送響應包。

? ? ?12) 無阻塞發送方法會立刻返回,即使目前未發送完,Nginx之后也會異步地發送完所有的響應包,然后再結束請求。

? ? ? 13) 父請求的回調方法執行完畢。

? ? ? 14) 當第2步中的上游服務器連接關閉時間處理完畢后,交還控制權給事件模塊。

? ? ? 15) 當本輪網絡事件處理完畢后,交還控制權給Nginx主循環。

55.subrequest是分解復雜請求的設計方法,派生出的子請求使用某些HTTP模塊基于upstream訪問第三方服務是最常見的用法,通過subrequest可以使Nginx在保持高并發的前提下處理復雜的業務。

56.

57.默認即編譯進Nginx的HTTP過濾模塊

默認即編譯進Nginx的HTTP過濾模塊功能
ngx_http_not_modified_filter_module僅對HTTP頭部進行處理。在返回200成功時,根據請求中If-Modified-Since或者If-Unmodified-Since頭部取得瀏覽器緩存文件的時間,再分析返回用戶文件的最后修改時間,以此決定是否直接發送304 Not Modified響應給用戶
ngx_http_range_body_filter_module處理請求中的Range信息,根據Range中的要求返回文件的一部分給用戶
ngx_http_copy_filter_module僅對HTTP包體做處理。將用戶發送的ngx_chain_t結構的HTTP包體復制到新的ngx_chain-t結構中(都是各種指針的復制,不包括實際HTTP響應內容),后續的HTTP過濾模塊處理的ngx_chain-t類型的成員都是ngx_http_copy_filter_module模塊處理后的變量
ngx_http_headers_filter_module僅對HTTP頭部做處理。允許通過修改nginx.conf配置文件,在返回給用戶的響應中添加任意的HTTP頭部
ngx_http_userid_filter_module僅對HTTP頭部做處理。這就是執行configure命令時提到的http_userid_module模塊,它基于cookie提供了簡單的認證管理功能
ngx_http_charset_filter_module可以將文本類型返回給用戶的響應包,按照nginx.conf中的配置重新進行編碼,再返回給用戶
ngx_http_ssi_filter_module支持SSI(Server Side Include,服務器端嵌入)功能,將文件內容包含到網頁中并返回給用戶
ngx_http_postpone_filter_module僅對HTTP包體做處理。它僅應用于subrequest產生的子請求。它使得多個子請求同時向客戶端發送響應時能夠有序,所謂的“有序”是指按照子請求的順序發送響應
ngx_http_gzip_filter_module對特定的HTTP響應包體(如網頁或者文本文件)進行gzip壓縮,再把壓縮后的內容返回給用戶
ngx_http_range_header_filter_module

支持range協議

ngx_http_chunked_filter_module支持chunk編碼
ngx_http_header_filter_module僅對HTTP頭部做處理。該過濾模塊將會把r->headers_out結構體中的成員序列化為返回給用戶的HTTP響應字符流,包括響應行(如HTTP/1.1 200 OK)和響應頭部,并通過調用ngx_http_write_filter_module過濾模塊中的過濾方法直接將HTTP包頭發送給客戶端
ngx_http_write_filter_module僅對HTTP包體做處理。該模塊負責向客戶端發送HTTP響應

58.過濾模塊例子中,HTTP頭部處理方法的執行活動圖

?

59.過濾模塊例子中,HTTP包體處理方法的執行活動圖

? ?

60.參考另一篇:https://blog.csdn.net/zhangge3663/article/details/83180659

61.ngx_module_t接口及其對核心、事件、HTTP、mail等4類模塊ctx上下文成員的具體化

? ??

62.Nginx常用模塊及其之間的關系

? ??

63.傳統Web服務器和Nginx間的重要差別:前者是每個事件消費者獨占一個進程資源,后者的事件消費者只是被事件分發者進程短期調用而已。

64.在阻塞代碼段上按照下面4種方式來劃分階段:

? ?(1) 將阻塞進程的方法按照相關的觸發事件分解為兩個階段

? ?(2) 將阻塞方法調用按照時間分解為多個階段的方法調用

? ?(3) 在“無所事事”且必須等待系統的響應,從而導致進程空轉時,使用定時器劃分階段

? ?(4) 如果阻塞方法完全無法繼續劃分,則必須使用獨立的進程執行這個阻塞方法

65.內存池的設計

? ? 為了避免出現內存碎片、減少向操作系統申請內存的次數、降低各個模塊的開發復雜度,Nginx設計了簡單的內存池。這個內存池沒有很復雜的功能:通常它不負責回收內存池中已經分配出的內存。

? ? 通常每一個請求都有一個這種簡易的獨立內存池(Nginx為每一個TCP連接都分配一個內存池,HTTP框架為每一個HTTP請求又分配了1個內存池),而在請求結束時則會銷毀整個內存池,把曾經分配的內存一次性歸還給操作系統。

66.Nginx核心的框架代碼一直圍繞著一個結構體展開,它就是ngx_cycle_t。無論是master管理進程、worker工作進程還是cache manager(loader)進程,每一個進程都毫無例外地擁有唯一一個ngx_cycle_t結構體。

? ? 作為一個Web服務器,Nginx首先需要監聽端口并處理其中的網絡事件。ngx_cycle_t對象中有一個動態數組成員叫做listening,它的每一個數組元素都是ngx_listening_t結構體,而每個ngx_listen_t結構體又代表著Nginx服務器監聽的一個端口。

typedef struct ngx_listening_s ngx_listening_t; struct ngx_listening_s {//socket套接字句柄ngx_socket_t fd;//監聽sockaddr地址struct sockaddr *sockaddr;//sockaddr地址長度socklen_t socklen;/* 存儲IP地址的字符串addr_text最大長度,即它指定了addr_text所分配的內存大小 */size_t addr_text_max_len;//以字符串形式存儲IP地址ngx_str_t addr_text;//套接字地址。例如,當type是SOCK_STREAM時,表示TCPint type;/* TCP實現監聽時的backlog隊列,它表示允許正在通過三次握手建立TCP連接但還沒有任何進程開始處理的連接最大個數 */int backlog;//內核中對于這個套接字的接收緩沖區大小int rcvbuf;//內核中對于這個套接字的發送緩沖區大小int sndbuf;//當新的TCP連接成功建立后的處理方法ngx_connection_handler_pt handler;/* 實際上框架并不使用servers指針,它更多的是作為一個保留指針,目前主要用于HTTP或者mail等模塊,用于保存當前監聽端口對應著的所有主機名 */void *servers;//log和logp都是可用的日志對象的指針ngx_log_t log;ngx_lot_t *logp;//如果為新的TCP連接創建內存池,則內存池的初始大小應該是pool_sizesize_t pool_size;/* TCP_DEFER_ACCEPT選項將在建立TCP連接成功且接收到用戶的請求數據后,才向對監聽套接字感興趣的進程發送事件通知,而連接建立成功后,如果post_accept_timeout秒后仍然沒有收到的用戶數據,則內核直接丟棄連接 */ngx_msec_t post_accept_timeout;/* 前一個ngx_listening_t 結構,多個ngx_listening_t結構體之間由previous指針組成單鏈表 */ngx_listening_t *previous;//當前監聽句柄對應著的ngx_connection_t結構體ngx_connection_t *connection;/* 標志位,為1則表示在當前監聽句柄有效,且執行ngx_init_cycle時不關閉監聽端口,為0時則正常關閉。該標志位框架代碼會自動設置 */unsigned open:1;/* 標志位,為1表示使用已有的ngx_cycle_t來初始化新的ngx_cycle_t結構體時,不關閉原來打開的監聽端口,這對運行中升級程序很有用,remain為0時,表示正常關閉曾經打開的監聽端口。該標志位框架代碼會自動設置,參見ngx_init_cycle方法 */unsigned remain:1;/* 標志位,為1時表示跳過設置當前ngx_listening_t結構體中的套接字,為0時正常初始化套接字。該標志位框架代碼會自動設置 */unsigned ignore:1;//表示是否已經綁定。實際上目前該標志位沒有使用unsigned bound:1; /* 已經綁定 *//* 表示當前監聽句柄是否來自前一個進程(如升級Nginx程序),如果為1,則表示來自前一個進程。一般會保留之前已經設置好的套接字,不做改變 */unsigned inherited:1; /* 來自前一個進程 *///目前未使用unsigned nonblocking_accept:1;//標志位,為1時表示當前結構體對應的套接字已經監聽unsigned listen:1;//表示套接字是否阻塞,目前該標志位沒有意義unsigned nonblocking:1;//目前該標志位沒有意義unsigned shared:1;//標志位,為1時表示Nginx會將網絡地址轉變為字符串形式的地址unsigned addr_ntop:1; };

67.Nginx框架是圍繞著ngx_cycle_t結構體來控制進程運行的。

typedef struct ngx_cycle_s ngx_cycle_t; struct ngx_cycle_s {/* 保存著所有模塊存儲配置項的結構體的指針,它首先是一個數組,每個數組成員又是一個指針,這個指針指向另一個存儲著指針的數組,因此會看到void **** */void ****conf_ctx;//內存池ngx_pool_t *pool;/* 日志模塊中提供了生成基本ngx_log_t日志對象的功能,這里的log實際上是在還沒有執行ngx_init_cycle方法前,也就是還沒有解析配置前,如果有信息需要輸出到日志,就會暫時使用log對象,它會輸出到屏幕。在ngx_init_cycle方法執行后,將會根據nginx.conf配置文件中的配置項,構造出正確的日志文件,此時會對log重新賦值 */ngx_lot_t *log;/*由nginx.conf配置文件讀取到日志文件路徑后,將開始初始化error_log日志文件,由于log對象還在用于輸出日志到屏幕,這時會用new_log對象暫時性地替代log日志,待初始化成功后,會用new_log的地址覆蓋上面的log指針 */ngx_lot_t new_log;//與下面的files成員配合使用,指出files數組里元素的總數ngx_uint_t files_n;/* 對于poll、rtsig這樣的事件模塊,會以有效文件句柄數來預先建立這些ngx_connection_t結構體,以加速事件的收集、分發。這時files就會保存所有ngx_connection_t的指針組成的數組,files_n就是指針的總數,而文件句柄的值用來訪問files數組成員 */ngx_connection_t **files;//可用連接池,與free_connection_n配合使用ngx_connection_t *free_connections;//可用連接池中連接的總數ngx_uint_t free_connection_n;/* 雙向鏈表容器,元素類型是ngx_connection_t結構體,表示可重復使用連接隊列 */ngx_queue_t reusable_connections_queue;/*動態數組,每個數組元素存儲著ngx_listening_t成員,表示監聽端口及相關的參數 */ngx_array_t listening;/*動態數組容器,它保存著Nginx所有要操作的目錄。如果有目錄不存在,則會視圖創建,而創建目錄失敗將會導致Nginx啟動失敗。例如,上傳文件的臨時目錄也在pathes中,如果沒有權限創建,則會導致Nginx無法啟動 */ngx_array_t pathes;/* 單鏈表容器,元素類型是ngx_open_file_t結構體,它表示Nginx已經打開的所有文件。事實上,Nginx框架不會向open_files鏈表中添加文件,而是由對此感興趣的模塊向其中添加文件路徑名,Nginx框架會有ngx_init_cycle方法中打開這些文件 */ngx_list_t open_files;/* 單鏈表容器,元素的類型是ngx_shm_zone_t結構體,每個元素表示一塊共享內存*/ngx_list_t shared_memory;//當前進程中所有連接對象的總數,與下面的connections成員配合使用ngx_uint_t connection_n;//指向當前進程中的所有連接對象,與connection_n配合使用ngx_connection_t *connections;//指向當前進程中的所有讀事件對象,connection_n同時表示所有讀事件的總數ngx_event_t *read_events;//指向當前進程中的所有寫事件對象,connection_n同時表示所有寫事件的總數ngx_event_t *write_events;/* 舊的ngx_cycle_t對象用于引用上一個ngx_cycle_t對象中的成員。例如ngx_init_cycle方法,在啟動初期,需要建立一個臨時的ngx_cycle_t對象保存一些變量,再調用ngx_init_cycle方法時就可以把舊的ngx_cycle_t對象傳進去,而這時old_cycle對象就會保存這個前期的ngx_cycle_t對象 */ngx_cycle_t *old_cycle;//配置文件相對于安裝目錄的路徑名稱ngx_str_t conf_file;/* Nginx處理配置文件時需要特殊處理的在命令行攜帶的參數,一般是-g選項攜帶的參數 */ngx_str_t conf_param;//Nginx配置文件所在目錄的路徑ngx_str_t conf_prefix;//Nginx安裝目錄的路徑ngx_str_t prefix;//用于進程間同步的文件鎖名稱ngx_str_t lock_file;//使用gethostname系統調用得到的主機名ngx_str_t hostname; };

68.Nginx啟動過程的流程圖

? ?

69.worker進程正常工作、退出時的流程圖

? ??

70.master進程不需要處理網絡事件,它不負責業務的執行,只會通過管理worker等子進程來實現重啟服務、平滑升級、更換日志文件、配置文件實時生效等功能。

71.epoll是目前Linux操作系統上最強大的事件管理機制。

72.首先,Nginx定義了一個核心模塊ngx_events_module,這樣在Nginx啟動時會調用ngx_init_cycle方法解析配置項,一旦在nginx.conf配置文件中找到ngx_events_module感興趣的“events{}”配置項,ngx_events_module模塊就開始工作了。ngx_events_module模塊定義了事件類型的模塊,它的全部工作就是為所有的事件模塊解析"events{}"中的配置項,同時管理這些事件模塊存儲配置項的結構體。

? ? 其次,Nginx定義了一個非常重要的事件模塊ngx_event_core_module,這個模塊會決定使用哪種事件驅動機制,以及如何管理事件。

? ? 最后,Nginx定義了一系列運行在不同操作系統、不同內核版本上的事件驅動模塊,包括:ngx_epoll_module、ngx_kqueue_module、ngx_poll_module、ngx_select_module、ngx_devpoll_module、ngx_eventport_module、ngx_aio_module、ngx_rtsig_module和基于Windows的ngx_select_module模塊。在ngx_event_core_module模塊的初始化過程中,將會從以上模塊中選取一個作為Nginx進程的事件驅動模塊。

73.ngx_connection_t連接池示意圖

? ??

74.所有事件模塊配置項結構體的指針是如何管理的。

??

75.ngx_event_core_module事件模塊啟動時的工作流程

? ? ?

? 76.epoll在Linux內核中申請了一個簡易的文件系統,把原來的一個select或者poll調用分成了3個部分:調用epoll_create建立1個epoll對象(在epoll文件系統中給這個句柄分配資源)、調用epoll_ctx向epoll對象中添加這100萬個連接的套接字、調用epoll_wait收集發生事件的連接。

77.ngx_event_accept方法建立新連接的流程

? ?

78.ngx_process_events_and_times方法中的事件框架處理流程

? ?

79.解析server{}塊內配置項的流程

? ?

80.解析location{}配置塊的流程

? ??

81.HTTP框架的初始化流程

? ??

82.接收、解析HTTP請求行的流程圖

? ??

83.ngx_http_process_request_headers方法接收HTTP頭部的流程圖

? ??

84.ngx_http_process_request處理HTTP請求的流程圖

? ??

85.ngx_http_core_run_phases方法的執行流程

? ??

86.ngx_http_request_handler方法的執行流程

? ??

87.ngx_http_read_client_request_body方法的流程圖

? ??

88.upstream機制的場景示意圖

? ??

89.ngx_http_upstream_connect方法的流程圖

? ??

90.ngx_http_upstream_send_request方法的流程圖

? ? ?

91.郵件代理功能的示意序列圖

? ??

? ?從網絡通信的角度來看,Nginx實現郵件代理功能時會把一個請求分為以下4個階段。

? ?1) 接收并解析客戶端初始請求的階段;

? ?2) 向認證服務器驗證請求合法性,并獲取上游郵件服務器地址的階段;

? ?3) Nginx根據用戶信息多次與上游郵件服務器交互驗證合法性的階段;

? ?4) Nginx在客戶端與上游郵件服務器間純粹透傳TCP流的階段。

92.初始化郵件請求的流程

? ??

93.啟動郵件認證、向認證服務器發起連接的流程

? ?

94.Nginx框架使用了3種傳遞消息傳遞方式:共享內存、套接字、信號。Nginx各進程間共享數據的主要方式就是使用共享內存.

總結

以上是生活随笔為你收集整理的《深入理解NGINX 模块开发与架构解析》之摘抄学习的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

婷婷六月久久综合丁香 | 永久免费观看美女裸体的网站 | 国产97在线 | 亚洲 | 天堂亚洲2017在线观看 | 国产在线精品一区二区高清不卡 | 国产又爽又黄又刺激的视频 | 亚洲爆乳精品无码一区二区三区 | 大地资源网第二页免费观看 | 老头边吃奶边弄进去呻吟 | 欧美黑人乱大交 | 亚洲精品综合五月久久小说 | 天堂а√在线地址中文在线 | 色妞www精品免费视频 | 一本久道久久综合婷婷五月 | 日本精品人妻无码免费大全 | 亚洲毛片av日韩av无码 | aa片在线观看视频在线播放 | 综合激情五月综合激情五月激情1 | 99久久人妻精品免费二区 | 伦伦影院午夜理论片 | 波多野结衣aⅴ在线 | 久久精品国产亚洲精品 | 天天摸天天透天天添 | 亚洲a无码综合a国产av中文 | 欧洲精品码一区二区三区免费看 | 亚洲s码欧洲m码国产av | 人人爽人人澡人人高潮 | 一本大道伊人av久久综合 | 亚洲国产精华液网站w | 狠狠色丁香久久婷婷综合五月 | 色综合久久久久综合一本到桃花网 | 国产成人人人97超碰超爽8 | 国产精品欧美成人 | 国产精品久久久久久亚洲毛片 | 国产suv精品一区二区五 | 欧美乱妇无乱码大黄a片 | 无码中文字幕色专区 | 男女猛烈xx00免费视频试看 | 亚洲精品一区三区三区在线观看 | 国产av久久久久精东av | 日欧一片内射va在线影院 | 国产福利视频一区二区 | 日韩av激情在线观看 | 天堂а√在线地址中文在线 | 成人欧美一区二区三区 | 国产精品久久久av久久久 | 在线观看国产一区二区三区 | 国产美女精品一区二区三区 | 呦交小u女精品视频 | 日本丰满熟妇videos | 国产电影无码午夜在线播放 | 国产午夜亚洲精品不卡下载 | aⅴ亚洲 日韩 色 图网站 播放 | 亚洲国产欧美国产综合一区 | 自拍偷自拍亚洲精品10p | 99国产精品白浆在线观看免费 | 国产精品久久久久7777 | 无码av最新清无码专区吞精 | 激情五月综合色婷婷一区二区 | 国产激情无码一区二区 | 日韩av无码一区二区三区 | 熟妇人妻无码xxx视频 | 久久国产精品_国产精品 | 色综合久久88色综合天天 | 我要看www免费看插插视频 | 精品成人av一区二区三区 | www成人国产高清内射 | 日韩欧美群交p片內射中文 | 无码人妻丰满熟妇区毛片18 | 亚洲熟妇色xxxxx欧美老妇y | 国产精品亚洲综合色区韩国 | 亚洲色www成人永久网址 | 狠狠亚洲超碰狼人久久 | 四虎永久在线精品免费网址 | 在教室伦流澡到高潮hnp视频 | 久久综合狠狠综合久久综合88 | 成人免费无码大片a毛片 | 亚洲熟妇自偷自拍另类 | 国产精品无码一区二区桃花视频 | 亚洲熟妇色xxxxx欧美老妇 | 人妻无码αv中文字幕久久琪琪布 | 日本饥渴人妻欲求不满 | 免费无码午夜福利片69 | 在线观看免费人成视频 | 国产免费久久精品国产传媒 | 欧洲熟妇色 欧美 | 国产精品免费大片 | 日本一本二本三区免费 | 成熟女人特级毛片www免费 | 国产美女精品一区二区三区 | 亚洲熟妇自偷自拍另类 | 国产成人人人97超碰超爽8 | 又粗又大又硬又长又爽 | 欧美人与物videos另类 | 成人av无码一区二区三区 | 国产成人综合色在线观看网站 | 麻豆国产丝袜白领秘书在线观看 | 国产成人无码av在线影院 | 草草网站影院白丝内射 | 青春草在线视频免费观看 | 国产在线一区二区三区四区五区 | 国产亚洲精品久久久久久大师 | 欧美 亚洲 国产 另类 | 亚洲欧美综合区丁香五月小说 | 精品久久综合1区2区3区激情 | 永久黄网站色视频免费直播 | 亚洲综合另类小说色区 | 激情五月综合色婷婷一区二区 | 激情爆乳一区二区三区 | 国产精品人妻一区二区三区四 | аⅴ资源天堂资源库在线 | 国产精品久久国产三级国 | 亚洲精品一区二区三区在线 | 亚洲国产精品久久人人爱 | 一个人看的www免费视频在线观看 | 亚洲欧洲日本综合aⅴ在线 | 蜜桃视频插满18在线观看 | 亚洲精品综合五月久久小说 | 国产真实夫妇视频 | 蜜桃视频韩日免费播放 | 精品国产麻豆免费人成网站 | 少妇被黑人到高潮喷出白浆 | 国产亚洲精品久久久久久大师 | 久热国产vs视频在线观看 | 国产精品久久久久9999小说 | 欧美激情一区二区三区成人 | 国产av一区二区精品久久凹凸 | 中文字幕无码日韩欧毛 | 99精品视频在线观看免费 | 欧美日韩视频无码一区二区三 | 波多野结衣一区二区三区av免费 | 午夜无码人妻av大片色欲 | 最新国产乱人伦偷精品免费网站 | 大肉大捧一进一出好爽视频 | a国产一区二区免费入口 | 成年美女黄网站色大免费视频 | 欧美国产亚洲日韩在线二区 | 免费播放一区二区三区 | 国产免费久久精品国产传媒 | 人妻尝试又大又粗久久 | 三上悠亚人妻中文字幕在线 | 十八禁真人啪啪免费网站 | 亚洲精品国产a久久久久久 | 日本饥渴人妻欲求不满 | 亚洲欧美精品aaaaaa片 | 亚洲 另类 在线 欧美 制服 | 欧美激情内射喷水高潮 | 国产黄在线观看免费观看不卡 | 久久久成人毛片无码 | 国产成人精品三级麻豆 | 高清国产亚洲精品自在久久 | 欧美人与牲动交xxxx | 亚洲国产成人av在线观看 | 免费无码av一区二区 | 欧美熟妇另类久久久久久多毛 | 日韩少妇内射免费播放 | 国产又粗又硬又大爽黄老大爷视 | 内射白嫩少妇超碰 | 亚洲人成网站在线播放942 | 狠狠色噜噜狠狠狠7777奇米 | 国产精品久久久久9999小说 | 精品欧美一区二区三区久久久 | 国产一区二区三区精品视频 | 日韩视频 中文字幕 视频一区 | 中文字幕人妻无码一夲道 | 国产精品美女久久久久av爽李琼 | 装睡被陌生人摸出水好爽 | 偷窥日本少妇撒尿chinese | 大肉大捧一进一出好爽视频 | 亚洲熟妇色xxxxx亚洲 | 牲交欧美兽交欧美 | 曰韩少妇内射免费播放 | 又粗又大又硬毛片免费看 | 亚洲精品国偷拍自产在线观看蜜桃 | 最近的中文字幕在线看视频 | 日韩人妻系列无码专区 | 精品无码成人片一区二区98 | aa片在线观看视频在线播放 | 精品久久久无码人妻字幂 | 国产成人无码a区在线观看视频app | 亚洲一区二区三区香蕉 | 久久久久久av无码免费看大片 | 午夜精品久久久久久久久 | 国产av无码专区亚洲a∨毛片 | 无码人妻精品一区二区三区下载 | 亚洲爆乳精品无码一区二区三区 | 久久久久亚洲精品男人的天堂 | 久9re热视频这里只有精品 | 色综合天天综合狠狠爱 | 成熟人妻av无码专区 | 久久精品国产一区二区三区肥胖 | 国内揄拍国内精品少妇国语 | 精品偷拍一区二区三区在线看 | 丰满少妇高潮惨叫视频 | 色婷婷av一区二区三区之红樱桃 | 亚洲 另类 在线 欧美 制服 | 99久久精品午夜一区二区 | 日本精品少妇一区二区三区 | 无码纯肉视频在线观看 | 欧美国产日韩久久mv | 亚洲国产综合无码一区 | 亚欧洲精品在线视频免费观看 | 亚洲成av人在线观看网址 | 亚洲中文字幕av在天堂 | 装睡被陌生人摸出水好爽 | 国产熟妇另类久久久久 | 3d动漫精品啪啪一区二区中 | 天堂久久天堂av色综合 | 性欧美牲交xxxxx视频 | 西西人体www44rt大胆高清 | 永久免费精品精品永久-夜色 | 无码成人精品区在线观看 | 精品国产麻豆免费人成网站 | 波多野结衣一区二区三区av免费 | 国产精品第一国产精品 | 狂野欧美激情性xxxx | 亚洲人成无码网www | 亚洲啪av永久无码精品放毛片 | 九一九色国产 | 亚洲精品午夜无码电影网 | 精品水蜜桃久久久久久久 | 狂野欧美性猛交免费视频 | 99久久久无码国产aaa精品 | 4hu四虎永久在线观看 | 国产特级毛片aaaaaa高潮流水 | 国产精品.xx视频.xxtv | 3d动漫精品啪啪一区二区中 | 日韩欧美群交p片內射中文 | 国产xxx69麻豆国语对白 | 精品无人区无码乱码毛片国产 | 天天躁夜夜躁狠狠是什么心态 | 久久久www成人免费毛片 | 在线播放免费人成毛片乱码 | 欧美熟妇另类久久久久久不卡 | 人人超人人超碰超国产 | 久久综合色之久久综合 | 国产av一区二区精品久久凹凸 | 骚片av蜜桃精品一区 | 国产乱人伦app精品久久 国产在线无码精品电影网 国产国产精品人在线视 | 成人aaa片一区国产精品 | 精品欧洲av无码一区二区三区 | 亚洲中文字幕久久无码 | 色欲av亚洲一区无码少妇 | 噜噜噜亚洲色成人网站 | 久久久久免费精品国产 | 强辱丰满人妻hd中文字幕 | 亚洲熟熟妇xxxx | 国产成人无码av片在线观看不卡 | 国产精品欧美成人 | 亚洲阿v天堂在线 | 欧美精品无码一区二区三区 | 又黄又爽又色的视频 | 久久午夜无码鲁丝片秋霞 | 日韩欧美群交p片內射中文 | 人人爽人人爽人人片av亚洲 | 久久综合给久久狠狠97色 | 东京热无码av男人的天堂 | 99久久久无码国产精品免费 | 牲交欧美兽交欧美 | 国产精品久久久久9999小说 | 呦交小u女精品视频 | 成人动漫在线观看 | 亚洲综合无码久久精品综合 | 日日橹狠狠爱欧美视频 | 久久精品视频在线看15 | 无码精品人妻一区二区三区av | 亚洲综合在线一区二区三区 | 日韩精品无码一区二区中文字幕 | 免费播放一区二区三区 | 国产精品亚洲а∨无码播放麻豆 | 人人爽人人澡人人人妻 | 亚欧洲精品在线视频免费观看 | 国产精品va在线观看无码 | 久久zyz资源站无码中文动漫 | 日日橹狠狠爱欧美视频 | 国产精品va在线观看无码 | 国色天香社区在线视频 | 国产深夜福利视频在线 | 久久人人爽人人爽人人片av高清 | 国产成人无码区免费内射一片色欲 | 国产亚洲精品久久久ai换 | 欧美野外疯狂做受xxxx高潮 | 亚洲一区二区三区国产精华液 | 人妻天天爽夜夜爽一区二区 | 欧美 日韩 人妻 高清 中文 | 精品国产一区av天美传媒 | a在线观看免费网站大全 | 黑人大群体交免费视频 | 成年美女黄网站色大免费全看 | 国产亚洲精品久久久久久久久动漫 | 国内综合精品午夜久久资源 | 国产精品香蕉在线观看 | 大屁股大乳丰满人妻 | 亚洲精品一区二区三区四区五区 | 国产乱子伦视频在线播放 | 国产精品人人爽人人做我的可爱 | 亚洲国产成人a精品不卡在线 | 伊人久久大香线焦av综合影院 | 久久综合香蕉国产蜜臀av | 少妇人妻av毛片在线看 | 亚洲精品国产精品乱码视色 | 婷婷六月久久综合丁香 | 亚洲s码欧洲m码国产av | 中文字幕无码日韩欧毛 | 一本一道久久综合久久 | 亚洲综合无码久久精品综合 | 青青青手机频在线观看 | 女人和拘做爰正片视频 | 国产偷自视频区视频 | 天天躁日日躁狠狠躁免费麻豆 | 丰满岳乱妇在线观看中字无码 | 国产精品鲁鲁鲁 | 人人澡人人妻人人爽人人蜜桃 | 国产在线一区二区三区四区五区 | 精品久久久中文字幕人妻 | 少妇人妻大乳在线视频 | 18禁黄网站男男禁片免费观看 | 国产一区二区三区影院 | 狠狠色欧美亚洲狠狠色www | 成人无码视频免费播放 | 亚洲中文字幕无码一久久区 | 婷婷色婷婷开心五月四房播播 | 久久久久久av无码免费看大片 | 欧美成人午夜精品久久久 | 激情爆乳一区二区三区 | 欧美人与牲动交xxxx | 亚洲熟妇色xxxxx欧美老妇 | 少妇愉情理伦片bd | 国产精品内射视频免费 | 国产成人无码av在线影院 | 无码av中文字幕免费放 | 亚洲成av人片天堂网无码】 | 亚洲の无码国产の无码影院 | 99久久精品日本一区二区免费 | 久久人妻内射无码一区三区 | 乱人伦人妻中文字幕无码 | 午夜免费福利小电影 | 国产激情无码一区二区 | 国产激情精品一区二区三区 | 荫蒂被男人添的好舒服爽免费视频 | 亚洲中文无码av永久不收费 | 精品国产精品久久一区免费式 | 亚洲精品国偷拍自产在线麻豆 | 国产乱人伦偷精品视频 | 女人高潮内射99精品 | 国产亚洲精品久久久久久久 | 成 人 免费观看网站 | 亚洲成a人片在线观看无码3d | 中文字幕无码热在线视频 | 99久久人妻精品免费一区 | 亚洲午夜久久久影院 | 免费观看黄网站 | 高清无码午夜福利视频 | 久久无码专区国产精品s | 任你躁国产自任一区二区三区 | 亚洲日韩av一区二区三区中文 | 亚洲熟熟妇xxxx | 男女猛烈xx00免费视频试看 | 大地资源中文第3页 | 国产小呦泬泬99精品 | 图片区 小说区 区 亚洲五月 | 国内揄拍国内精品少妇国语 | 国内精品人妻无码久久久影院 | 又粗又大又硬毛片免费看 | 国产色视频一区二区三区 | 色五月丁香五月综合五月 | 婷婷色婷婷开心五月四房播播 | 俄罗斯老熟妇色xxxx | 亚洲一区二区三区在线观看网站 | 久久久久久九九精品久 | 大胆欧美熟妇xx | 99麻豆久久久国产精品免费 | 国产精品对白交换视频 | 天天躁夜夜躁狠狠是什么心态 | 国产成人精品无码播放 | 国产猛烈高潮尖叫视频免费 | 大屁股大乳丰满人妻 | 国产精品对白交换视频 | 久久久精品国产sm最大网站 | 亚洲中文无码av永久不收费 | 国产成人午夜福利在线播放 | 国产成人久久精品流白浆 | 成人片黄网站色大片免费观看 | yw尤物av无码国产在线观看 | 麻豆精品国产精华精华液好用吗 | 日日摸天天摸爽爽狠狠97 | 亚洲国产精品一区二区第一页 | 午夜肉伦伦影院 | 国产无av码在线观看 | 国产绳艺sm调教室论坛 | 国产精品内射视频免费 | av人摸人人人澡人人超碰下载 | 欧美人与善在线com | 国内揄拍国内精品少妇国语 | 欧美人与动性行为视频 | 国产九九九九九九九a片 | 乱码午夜-极国产极内射 | 国产香蕉尹人视频在线 | 伊人久久大香线蕉午夜 | 人人妻人人藻人人爽欧美一区 | 精品国产一区av天美传媒 | 国产suv精品一区二区五 | 四十如虎的丰满熟妇啪啪 | 欧美日韩视频无码一区二区三 | 亚洲国产精品一区二区美利坚 | 亚洲 a v无 码免 费 成 人 a v | 麻豆成人精品国产免费 | 免费网站看v片在线18禁无码 | 婷婷六月久久综合丁香 | 中国大陆精品视频xxxx | 欧美阿v高清资源不卡在线播放 | 无码人妻av免费一区二区三区 | 国产热a欧美热a在线视频 | 久精品国产欧美亚洲色aⅴ大片 | 亚洲乱码中文字幕在线 | 日韩精品无码一本二本三本色 | 大肉大捧一进一出好爽视频 | 无码av中文字幕免费放 | 2020久久香蕉国产线看观看 | 伦伦影院午夜理论片 | 久久精品人人做人人综合试看 | 亚洲中文字幕无码中字 | 中文无码伦av中文字幕 | 久久久久久久人妻无码中文字幕爆 | 黑人粗大猛烈进出高潮视频 | 亚洲乱码日产精品bd | 无码人妻黑人中文字幕 | 欧美日韩综合一区二区三区 | 精品国产成人一区二区三区 | 国产性生交xxxxx无码 | 国产精品亚洲专区无码不卡 | 少妇一晚三次一区二区三区 | 免费中文字幕日韩欧美 | 老太婆性杂交欧美肥老太 | 亚洲一区二区三区偷拍女厕 | 成人性做爰aaa片免费看不忠 | 成人无码精品一区二区三区 | 天堂а√在线中文在线 | 18禁黄网站男男禁片免费观看 | 熟女俱乐部五十路六十路av | 国产av人人夜夜澡人人爽麻豆 | 中文字幕无码日韩欧毛 | 免费网站看v片在线18禁无码 | 中文字幕无码免费久久9一区9 | 一本久道久久综合婷婷五月 | 国产精品二区一区二区aⅴ污介绍 | 久久 国产 尿 小便 嘘嘘 | 俺去俺来也在线www色官网 | 少妇性l交大片欧洲热妇乱xxx | 真人与拘做受免费视频一 | 精品国产青草久久久久福利 | 欧美日韩色另类综合 | 日本一卡2卡3卡四卡精品网站 | 国产精品美女久久久网av | 日日天干夜夜狠狠爱 | 欧美丰满少妇xxxx性 | 国产成人精品一区二区在线小狼 | 十八禁视频网站在线观看 | 无码精品人妻一区二区三区av | 麻豆人妻少妇精品无码专区 | 黑森林福利视频导航 | 国产无遮挡又黄又爽又色 | 亚洲精品国偷拍自产在线麻豆 | 精品无码国产一区二区三区av | 国产内射老熟女aaaa | 白嫩日本少妇做爰 | av无码久久久久不卡免费网站 | 日韩欧美群交p片內射中文 | 伊人久久大香线蕉亚洲 | 亚洲精品久久久久中文第一幕 | 国产精品沙发午睡系列 | 国产无遮挡吃胸膜奶免费看 | 人人妻人人澡人人爽欧美一区九九 | 午夜精品久久久久久久久 | 国产两女互慰高潮视频在线观看 | 18禁止看的免费污网站 | 国产区女主播在线观看 | 99精品国产综合久久久久五月天 | 在线а√天堂中文官网 | aⅴ亚洲 日韩 色 图网站 播放 | 少妇一晚三次一区二区三区 | 国产网红无码精品视频 | 久久国语露脸国产精品电影 | 久久无码专区国产精品s | 全球成人中文在线 | 国产精品va在线观看无码 | 亚洲色在线无码国产精品不卡 | 亚洲成色在线综合网站 | 精品国产国产综合精品 | 双乳奶水饱满少妇呻吟 | 国内老熟妇对白xxxxhd | √天堂中文官网8在线 | 黑森林福利视频导航 | 亚洲色www成人永久网址 | 国产精品手机免费 | 国内综合精品午夜久久资源 | 国产亚洲精品久久久闺蜜 | 无码乱肉视频免费大全合集 | 精品乱子伦一区二区三区 | 十八禁视频网站在线观看 | 亚洲日韩乱码中文无码蜜桃臀网站 | 蜜桃av蜜臀av色欲av麻 999久久久国产精品消防器材 | 乱中年女人伦av三区 | 亚洲另类伦春色综合小说 | 亚洲国产成人a精品不卡在线 | 成熟人妻av无码专区 | 亚洲阿v天堂在线 | 人妻夜夜爽天天爽三区 | 精品国产一区av天美传媒 | 中文字幕人成乱码熟女app | 丰满少妇人妻久久久久久 | 欧美日本免费一区二区三区 | 精品久久久无码中文字幕 | 久久精品国产一区二区三区肥胖 | 国产精品沙发午睡系列 | 亚洲色大成网站www国产 | 国产成人久久精品流白浆 | 久久精品国产99精品亚洲 | 国产激情艳情在线看视频 | 成人无码精品一区二区三区 | 国产成人无码一二三区视频 | 精品厕所偷拍各类美女tp嘘嘘 | 女人和拘做爰正片视频 | 精品一区二区三区波多野结衣 | 亚洲日本va午夜在线电影 | 又粗又大又硬又长又爽 | 精品国产一区二区三区四区在线看 | a片在线免费观看 | 国产亚洲精品久久久久久久久动漫 | 青草视频在线播放 | 亚洲 另类 在线 欧美 制服 | 伊人久久大香线蕉亚洲 | 狂野欧美性猛xxxx乱大交 | 亚洲欧美国产精品专区久久 | 熟妇人妻无乱码中文字幕 | 亚洲综合在线一区二区三区 | 波多野结衣av一区二区全免费观看 | 少妇太爽了在线观看 | 亚洲精品国产精品乱码视色 | 国产黄在线观看免费观看不卡 | 欧美性生交活xxxxxdddd | 欧美黑人乱大交 | 亚洲国产精品久久人人爱 | 无码午夜成人1000部免费视频 | 亚洲色成人中文字幕网站 | 学生妹亚洲一区二区 | 国产精品永久免费视频 | 99久久人妻精品免费一区 | 亚洲精品成a人在线观看 | 97无码免费人妻超级碰碰夜夜 | 久久综合色之久久综合 | 久久久久久a亚洲欧洲av冫 | 欧美三级不卡在线观看 | 激情内射日本一区二区三区 | 无码精品国产va在线观看dvd | 中文字幕亚洲情99在线 | 一区二区传媒有限公司 | 国产精品爱久久久久久久 | 国产在热线精品视频 | 亚洲熟妇色xxxxx亚洲 | 黑人巨大精品欧美黑寡妇 | 国产国产精品人在线视 | 无码免费一区二区三区 | 日韩视频 中文字幕 视频一区 | 免费看男女做好爽好硬视频 | 国产农村妇女aaaaa视频 撕开奶罩揉吮奶头视频 | 国产性生交xxxxx无码 | 大肉大捧一进一出好爽视频 | 亚洲区欧美区综合区自拍区 | 日本xxxx色视频在线观看免费 | 亚洲欧美精品aaaaaa片 | 国产女主播喷水视频在线观看 | 全黄性性激高免费视频 | 亚洲爆乳大丰满无码专区 | 亚洲一区二区三区国产精华液 | 国产人成高清在线视频99最全资源 | 亚洲精品美女久久久久久久 | 思思久久99热只有频精品66 | 亚洲精品午夜国产va久久成人 | 国产无遮挡又黄又爽免费视频 | 永久免费观看美女裸体的网站 | 亚洲熟悉妇女xxx妇女av | 在线视频网站www色 | 国产日产欧产精品精品app | 欧美zoozzooz性欧美 | 天天摸天天透天天添 | 高清无码午夜福利视频 | 夜先锋av资源网站 | 亚洲中文字幕无码中文字在线 | 秋霞成人午夜鲁丝一区二区三区 | 丰满肥臀大屁股熟妇激情视频 | 国产精品-区区久久久狼 | 国产成人综合在线女婷五月99播放 | 亚洲成a人片在线观看无码3d | 欧美精品国产综合久久 | 国语精品一区二区三区 | 牲欲强的熟妇农村老妇女视频 | 强伦人妻一区二区三区视频18 | 少妇无码吹潮 | 久久精品国产大片免费观看 | 午夜福利一区二区三区在线观看 | 亚洲精品久久久久久一区二区 | 国产精品无码一区二区桃花视频 | 精品日本一区二区三区在线观看 | 秋霞特色aa大片 | 国产两女互慰高潮视频在线观看 | 亚洲熟妇色xxxxx欧美老妇 | √8天堂资源地址中文在线 | 99久久久国产精品无码免费 | 国产精品自产拍在线观看 | 国产精品自产拍在线观看 | 一二三四在线观看免费视频 | 精品久久久无码中文字幕 | 久久婷婷五月综合色国产香蕉 | 无套内谢的新婚少妇国语播放 | 玩弄人妻少妇500系列视频 | 日本精品人妻无码免费大全 | 无码人妻精品一区二区三区不卡 | 亚洲最大成人网站 | 青青青手机频在线观看 | 少妇性俱乐部纵欲狂欢电影 | 熟妇女人妻丰满少妇中文字幕 | 亚洲成a人片在线观看无码3d | 人妻少妇精品久久 | 欧美 日韩 人妻 高清 中文 | 久久 国产 尿 小便 嘘嘘 | 夫妻免费无码v看片 | 在线播放免费人成毛片乱码 | 国产精品二区一区二区aⅴ污介绍 | 亚洲自偷自拍另类第1页 | 丁香花在线影院观看在线播放 | 久久这里只有精品视频9 | 国产亚洲视频中文字幕97精品 | 欧美丰满老熟妇xxxxx性 | 亚洲精品国偷拍自产在线观看蜜桃 | 日本爽爽爽爽爽爽在线观看免 | 欧美亚洲日韩国产人成在线播放 | 精品无码国产一区二区三区av | 亚洲国产av精品一区二区蜜芽 | 乱码av麻豆丝袜熟女系列 | 欧美激情内射喷水高潮 | 久久久久国色av免费观看性色 | av在线亚洲欧洲日产一区二区 | 国产真实夫妇视频 | 午夜成人1000部免费视频 | 在线视频网站www色 | 国产成人精品无码播放 | 美女毛片一区二区三区四区 | 久久人人爽人人爽人人片av高清 | 国产猛烈高潮尖叫视频免费 | 精品国产一区二区三区av 性色 | 欧美丰满熟妇xxxx | 亚洲狠狠色丁香婷婷综合 | 亚洲国产成人av在线观看 | 欧美精品免费观看二区 | 99久久婷婷国产综合精品青草免费 | 国产偷国产偷精品高清尤物 | 人妻无码久久精品人妻 | 色欲久久久天天天综合网精品 | 国产熟妇高潮叫床视频播放 | 国产偷抇久久精品a片69 | 亚洲欧美精品aaaaaa片 | 人人超人人超碰超国产 | 免费观看又污又黄的网站 | 无码人妻丰满熟妇区毛片18 | 宝宝好涨水快流出来免费视频 | 在线精品国产一区二区三区 | 成人欧美一区二区三区黑人 | 免费男性肉肉影院 | 久久久久人妻一区精品色欧美 | 日韩精品久久久肉伦网站 | 国产精品99久久精品爆乳 | 欧美喷潮久久久xxxxx | 熟妇人妻激情偷爽文 | 欧美老妇与禽交 | 午夜时刻免费入口 | 日本一本二本三区免费 | 国产欧美精品一区二区三区 | 巨爆乳无码视频在线观看 | 免费无码午夜福利片69 | 日本熟妇人妻xxxxx人hd | 一本久久a久久精品vr综合 | 亚洲日韩乱码中文无码蜜桃臀网站 | 亚洲天堂2017无码中文 | 日本爽爽爽爽爽爽在线观看免 | 国产激情无码一区二区 | 内射白嫩少妇超碰 | 国产激情综合五月久久 | 免费乱码人妻系列无码专区 | 亚洲gv猛男gv无码男同 | 久久久久亚洲精品中文字幕 | 中文字幕人妻无码一夲道 | 麻豆人妻少妇精品无码专区 | 国产 浪潮av性色四虎 | 午夜肉伦伦影院 | 午夜免费福利小电影 | 国产精品igao视频网 | 伊人久久大香线焦av综合影院 | 日产精品99久久久久久 | 天天躁日日躁狠狠躁免费麻豆 | 日本成熟视频免费视频 | 国产精品亚洲专区无码不卡 | 99久久婷婷国产综合精品青草免费 | 俄罗斯老熟妇色xxxx | 国产午夜无码精品免费看 | 国产精品va在线播放 | 午夜精品久久久久久久 | 久久亚洲中文字幕无码 | 亚洲aⅴ无码成人网站国产app | 欧美日本免费一区二区三区 | 亚洲精品久久久久avwww潮水 | 亚洲第一无码av无码专区 | 东京热一精品无码av | 亚洲精品国产第一综合99久久 | 99视频精品全部免费免费观看 | 丰满岳乱妇在线观看中字无码 | 中文字幕无码av波多野吉衣 | 网友自拍区视频精品 | 国内精品久久久久久中文字幕 | 欧美性生交活xxxxxdddd | 亚洲精品成人福利网站 | 爱做久久久久久 | 国产亚洲精品久久久久久 | 欧美喷潮久久久xxxxx | 少妇久久久久久人妻无码 | 国产乱人偷精品人妻a片 | 国产免费久久精品国产传媒 | 精品国产福利一区二区 | 无码一区二区三区在线 | 精品无人国产偷自产在线 | 国语自产偷拍精品视频偷 | 又大又黄又粗又爽的免费视频 | 精品无码国产自产拍在线观看蜜 | a片免费视频在线观看 | 成人影院yy111111在线观看 | 曰韩少妇内射免费播放 | 又色又爽又黄的美女裸体网站 | 亚洲国产欧美在线成人 | 亚洲一区av无码专区在线观看 | 在线a亚洲视频播放在线观看 | 无码国产乱人伦偷精品视频 | 亚洲精品www久久久 | 国产午夜无码视频在线观看 | 亚洲国产精品毛片av不卡在线 | √天堂资源地址中文在线 | 毛片内射-百度 | 国产免费观看黄av片 | 国产成人无码a区在线观看视频app | 97夜夜澡人人双人人人喊 | 国产凸凹视频一区二区 | 久久久无码中文字幕久... | 国产精品嫩草久久久久 | 精品人妻人人做人人爽夜夜爽 | 精品乱子伦一区二区三区 | 成人免费视频一区二区 | 色综合久久88色综合天天 | 日本大香伊一区二区三区 | 少妇厨房愉情理9仑片视频 | 成人毛片一区二区 | 午夜时刻免费入口 | 无码国产激情在线观看 | 日韩成人一区二区三区在线观看 | 夜夜高潮次次欢爽av女 | 中文字幕无码av激情不卡 | 国产精品久久国产三级国 | 18黄暴禁片在线观看 | 丝袜足控一区二区三区 | 日本护士毛茸茸高潮 | 奇米综合四色77777久久 东京无码熟妇人妻av在线网址 | 野狼第一精品社区 | 精品国偷自产在线 | 99精品视频在线观看免费 | 亚洲熟悉妇女xxx妇女av | 欧美精品国产综合久久 | 成 人影片 免费观看 | av无码电影一区二区三区 | 亚洲综合无码久久精品综合 | 黑人巨大精品欧美黑寡妇 | 日本一区二区更新不卡 | 中文字幕av无码一区二区三区电影 | 国产精品久久久久7777 | 久久久成人毛片无码 | 久久精品女人天堂av免费观看 | 亚洲精品久久久久久一区二区 | 红桃av一区二区三区在线无码av | 给我免费的视频在线观看 | 亚洲欧美日韩成人高清在线一区 | 奇米影视7777久久精品 | 国产成人综合色在线观看网站 | 欧美freesex黑人又粗又大 | 天天综合网天天综合色 | 粗大的内捧猛烈进出视频 | 国产精品美女久久久 | 久久亚洲中文字幕精品一区 | 成人亚洲精品久久久久 | 国产精品手机免费 | 丰满少妇高潮惨叫视频 | 狠狠色色综合网站 | 日韩精品a片一区二区三区妖精 | 久久久国产一区二区三区 | 偷窥村妇洗澡毛毛多 | aⅴ在线视频男人的天堂 | 无码国内精品人妻少妇 | 少妇高潮喷潮久久久影院 | 精品 日韩 国产 欧美 视频 | 黑人粗大猛烈进出高潮视频 | 日韩无码专区 | 熟女俱乐部五十路六十路av | 国产无av码在线观看 | 人妻无码αv中文字幕久久琪琪布 | 亚洲高清偷拍一区二区三区 | 九九在线中文字幕无码 | 国产精品久久精品三级 | 亚洲欧美日韩成人高清在线一区 | 图片小说视频一区二区 | 国产人妖乱国产精品人妖 | 美女黄网站人色视频免费国产 | 国产精品亚洲综合色区韩国 | 国产在线aaa片一区二区99 | 日本www一道久久久免费榴莲 | 久久精品中文字幕大胸 | 午夜时刻免费入口 | 熟女少妇人妻中文字幕 | 久久综合激激的五月天 | 97精品人妻一区二区三区香蕉 | 俺去俺来也在线www色官网 | 久久午夜无码鲁丝片 | 中文字幕日产无线码一区 | 久久国语露脸国产精品电影 | 国产精品人人妻人人爽 | 国产 精品 自在自线 | 日本在线高清不卡免费播放 | 青草视频在线播放 | 国产性生大片免费观看性 | 久久精品国产99精品亚洲 | 亚洲日韩中文字幕在线播放 | 在线精品亚洲一区二区 | 国内精品久久久久久中文字幕 | 高清国产亚洲精品自在久久 | 精品国产乱码久久久久乱码 | 亚洲一区二区三区四区 | 99久久亚洲精品无码毛片 | 精品夜夜澡人妻无码av蜜桃 | 精品厕所偷拍各类美女tp嘘嘘 | 国产精品99爱免费视频 | 扒开双腿疯狂进出爽爽爽视频 | 中文无码成人免费视频在线观看 | 婷婷五月综合激情中文字幕 | 久久久久久av无码免费看大片 | 麻豆人妻少妇精品无码专区 | 东京热无码av男人的天堂 | 纯爱无遮挡h肉动漫在线播放 | 2020最新国产自产精品 | 欧美日韩在线亚洲综合国产人 | 国产农村乱对白刺激视频 | 国产香蕉97碰碰久久人人 | 国产精品美女久久久久av爽李琼 | 国产九九九九九九九a片 | 成人亚洲精品久久久久软件 | 无码国产乱人伦偷精品视频 | 色婷婷久久一区二区三区麻豆 | 日韩精品无码一本二本三本色 | 亚洲精品久久久久中文第一幕 | 国产精品亚洲一区二区三区喷水 | 曰本女人与公拘交酡免费视频 | 熟女俱乐部五十路六十路av | 少妇太爽了在线观看 | 久久99精品久久久久久 | 成 人 免费观看网站 | 精品无人国产偷自产在线 | 极品嫩模高潮叫床 | 欧美变态另类xxxx | 亚洲 另类 在线 欧美 制服 | 欧美午夜特黄aaaaaa片 | 国产精品久久精品三级 | 日韩精品a片一区二区三区妖精 | 久久精品视频在线看15 | 人人妻人人澡人人爽人人精品浪潮 | 永久免费观看国产裸体美女 | 成人片黄网站色大片免费观看 | 国产情侣作爱视频免费观看 | 日韩在线不卡免费视频一区 | 内射后入在线观看一区 | 男女作爱免费网站 | 97人妻精品一区二区三区 | 国产后入清纯学生妹 | 波多野结衣av一区二区全免费观看 | 领导边摸边吃奶边做爽在线观看 | 性色av无码免费一区二区三区 | 国产精品无码一区二区桃花视频 | 亚洲人成网站在线播放942 | 精品熟女少妇av免费观看 | 性啪啪chinese东北女人 | 国产国产精品人在线视 | 久久精品国产亚洲精品 | 奇米综合四色77777久久 东京无码熟妇人妻av在线网址 | 久久精品一区二区三区四区 | 久久久久久久久888 | 人人妻在人人 | 国内精品人妻无码久久久影院蜜桃 | 高中生自慰www网站 | 欧美日韩视频无码一区二区三 | 国产亚洲美女精品久久久2020 | 国产婷婷色一区二区三区在线 | 国产午夜无码精品免费看 | 妺妺窝人体色www在线小说 | 午夜福利电影 | 久久久久成人精品免费播放动漫 | 精品亚洲成av人在线观看 | 免费网站看v片在线18禁无码 | 任你躁在线精品免费 | 波多野结衣av在线观看 | 狠狠色丁香久久婷婷综合五月 | 欧美人与牲动交xxxx | 精品亚洲韩国一区二区三区 | 性欧美熟妇videofreesex | 欧美一区二区三区 | 亚洲色大成网站www国产 | 55夜色66夜色国产精品视频 | aa片在线观看视频在线播放 | 欧美丰满熟妇xxxx | 精品无码国产自产拍在线观看蜜 | 帮老师解开蕾丝奶罩吸乳网站 | 中文字幕乱码人妻二区三区 | 国产97在线 | 亚洲 | 漂亮人妻洗澡被公强 日日躁 | 欧美成人高清在线播放 | 久久久久免费看成人影片 | 女人被男人爽到呻吟的视频 | 成年美女黄网站色大免费视频 | 无码av最新清无码专区吞精 | 亚洲国产精品一区二区美利坚 | 97久久精品无码一区二区 | 天堂在线观看www | 国产激情艳情在线看视频 | 中文字幕日韩精品一区二区三区 | 亚洲成a人一区二区三区 | 人妻人人添人妻人人爱 | 少妇厨房愉情理9仑片视频 | 亚洲国产精品久久久天堂 | 伊在人天堂亚洲香蕉精品区 | 人妻尝试又大又粗久久 | 久久国产精品精品国产色婷婷 | 18精品久久久无码午夜福利 | 亚洲精品中文字幕久久久久 | 扒开双腿疯狂进出爽爽爽视频 | 在线播放免费人成毛片乱码 | 亚洲熟熟妇xxxx | 国产精品永久免费视频 | 99久久无码一区人妻 | aⅴ在线视频男人的天堂 | 国产 精品 自在自线 | 扒开双腿疯狂进出爽爽爽视频 | 在线 国产 欧美 亚洲 天堂 | 波多野结衣乳巨码无在线观看 | 久久久久久国产精品无码下载 | 领导边摸边吃奶边做爽在线观看 | 久激情内射婷内射蜜桃人妖 | 久久综合给合久久狠狠狠97色 | 国产精品久久久 | 青青青手机频在线观看 | 亚洲中文字幕乱码av波多ji | 久精品国产欧美亚洲色aⅴ大片 | 欧美大屁股xxxxhd黑色 | 强伦人妻一区二区三区视频18 | 99精品视频在线观看免费 | 人妻体内射精一区二区三四 | 嫩b人妻精品一区二区三区 | 国产农村乱对白刺激视频 | 久久婷婷五月综合色国产香蕉 | 亚洲色偷偷偷综合网 | 中文字幕精品av一区二区五区 | 日韩精品无码免费一区二区三区 | 国内精品九九久久久精品 | 又粗又大又硬又长又爽 | 麻豆果冻传媒2021精品传媒一区下载 | 国产高清av在线播放 | 日韩人妻无码一区二区三区久久99 | 久久久av男人的天堂 | 欧美日韩一区二区免费视频 | 国产美女极度色诱视频www | av无码不卡在线观看免费 | 日韩人妻少妇一区二区三区 | 国产成人精品久久亚洲高清不卡 | 宝宝好涨水快流出来免费视频 | 久久久久人妻一区精品色欧美 | 欧美乱妇无乱码大黄a片 | a国产一区二区免费入口 | 亚洲成a人片在线观看无码 | 久精品国产欧美亚洲色aⅴ大片 | 国产色在线 | 国产 | 亚洲精品成a人在线观看 | 99久久精品国产一区二区蜜芽 | 久久无码中文字幕免费影院蜜桃 | 欧美激情内射喷水高潮 | 国产 精品 自在自线 | 青青草原综合久久大伊人精品 | 少女韩国电视剧在线观看完整 | 国产农村妇女aaaaa视频 撕开奶罩揉吮奶头视频 | 亚洲第一网站男人都懂 | 国产亲子乱弄免费视频 | 成 人 网 站国产免费观看 | 强奷人妻日本中文字幕 | 少妇一晚三次一区二区三区 | 天干天干啦夜天干天2017 | 亚洲色大成网站www | 少妇人妻偷人精品无码视频 | 日本高清一区免费中文视频 | 在线 国产 欧美 亚洲 天堂 | 国产人妻人伦精品 | 日韩欧美中文字幕公布 | 国产欧美亚洲精品a | 67194成是人免费无码 | 国产亚洲视频中文字幕97精品 | 狠狠综合久久久久综合网 | 国内精品人妻无码久久久影院 | 亚洲а∨天堂久久精品2021 | 国产无套粉嫩白浆在线 | 午夜不卡av免费 一本久久a久久精品vr综合 | 一本色道婷婷久久欧美 | 乱中年女人伦av三区 | 女人被男人爽到呻吟的视频 | 久热国产vs视频在线观看 | a片在线免费观看 | 久久国语露脸国产精品电影 | 好爽又高潮了毛片免费下载 | 欧美国产亚洲日韩在线二区 | 大胆欧美熟妇xx | 99久久精品国产一区二区蜜芽 | 丰满人妻翻云覆雨呻吟视频 | 欧美老妇交乱视频在线观看 | 久久99精品久久久久久动态图 | 久激情内射婷内射蜜桃人妖 | 亚洲日本va午夜在线电影 | 成人精品视频一区二区三区尤物 | 色婷婷香蕉在线一区二区 | 18黄暴禁片在线观看 | 久久五月精品中文字幕 | 国产在线无码精品电影网 | 久久天天躁狠狠躁夜夜免费观看 | 免费无码av一区二区 | 九九在线中文字幕无码 | aⅴ在线视频男人的天堂 | 国产麻豆精品精东影业av网站 | 欧美老人巨大xxxx做受 | а√资源新版在线天堂 | 久久精品人妻少妇一区二区三区 | 国产精品亚洲а∨无码播放麻豆 | 久久综合网欧美色妞网 | 国色天香社区在线视频 | 熟女少妇在线视频播放 | 欧美阿v高清资源不卡在线播放 | 窝窝午夜理论片影院 | 国产又粗又硬又大爽黄老大爷视 | 久久亚洲a片com人成 | 国产欧美亚洲精品a | 大地资源中文第3页 | 国产又爽又猛又粗的视频a片 | 国产成人无码区免费内射一片色欲 | 少妇高潮喷潮久久久影院 | 亚洲欧洲无卡二区视頻 | 国产香蕉尹人综合在线观看 | 性色欲网站人妻丰满中文久久不卡 | 国语精品一区二区三区 | 久久人妻内射无码一区三区 | 欧美猛少妇色xxxxx | 99久久婷婷国产综合精品青草免费 | 国产成人午夜福利在线播放 | 精品久久综合1区2区3区激情 | 在线看片无码永久免费视频 | 亚洲乱码中文字幕在线 | 国产乱人无码伦av在线a | 色噜噜亚洲男人的天堂 | 双乳奶水饱满少妇呻吟 | 国产亚洲美女精品久久久2020 | 青草视频在线播放 | 欧美野外疯狂做受xxxx高潮 | 极品尤物被啪到呻吟喷水 | 2020久久香蕉国产线看观看 | 又色又爽又黄的美女裸体网站 | 无码帝国www无码专区色综合 | 少妇无套内谢久久久久 | 色综合久久久无码中文字幕 | 波多野结衣乳巨码无在线观看 | 亚洲中文字幕无码中字 | 老熟妇仑乱视频一区二区 | 精品厕所偷拍各类美女tp嘘嘘 | 国产在线精品一区二区高清不卡 | 双乳奶水饱满少妇呻吟 | 人人妻人人澡人人爽人人精品 | 爽爽影院免费观看 | 久久精品中文字幕一区 | 国产两女互慰高潮视频在线观看 | 欧美日韩精品 | 曰韩无码二三区中文字幕 | 久久人人97超碰a片精品 | 日欧一片内射va在线影院 | 欧美一区二区三区 | 亲嘴扒胸摸屁股激烈网站 | 日韩av无码一区二区三区不卡 | 亚洲中文字幕va福利 | 精品少妇爆乳无码av无码专区 | 少妇激情av一区二区 | 国产明星裸体无码xxxx视频 | 午夜性刺激在线视频免费 | 国产九九九九九九九a片 | 内射爽无广熟女亚洲 | 欧美亚洲国产一区二区三区 | 亚洲精品一区二区三区婷婷月 | 三上悠亚人妻中文字幕在线 | 久久视频在线观看精品 | 国产精品久久久久久久9999 | 嫩b人妻精品一区二区三区 | 欧美日韩视频无码一区二区三 | 亚洲一区二区三区国产精华液 | 久久综合香蕉国产蜜臀av | 国产sm调教视频在线观看 | 亚欧洲精品在线视频免费观看 | 在线精品亚洲一区二区 | 国产综合在线观看 | 欧美人与物videos另类 | 亚洲中文字幕无码中文字在线 | 亚洲成熟女人毛毛耸耸多 | 中文精品无码中文字幕无码专区 | 国产精品第一国产精品 | 日日橹狠狠爱欧美视频 | 亚洲欧美日韩成人高清在线一区 | 国产精品人人爽人人做我的可爱 | 丁香啪啪综合成人亚洲 | 亚洲成av人影院在线观看 | 久久天天躁狠狠躁夜夜免费观看 | 又色又爽又黄的美女裸体网站 | 人人妻人人澡人人爽欧美一区九九 | 亚洲精品www久久久 | 无码帝国www无码专区色综合 | 久久久久国色av免费观看性色 | 色综合久久久无码网中文 | 亚洲无人区午夜福利码高清完整版 | 中文字幕无码日韩专区 | 在线观看欧美一区二区三区 | 无码福利日韩神码福利片 | 动漫av网站免费观看 | 国产莉萝无码av在线播放 | 人妻夜夜爽天天爽三区 | 亚洲高清偷拍一区二区三区 | 少妇被粗大的猛进出69影院 | 婷婷丁香五月天综合东京热 | 国产亲子乱弄免费视频 | 欧洲精品码一区二区三区免费看 | 特大黑人娇小亚洲女 | 扒开双腿疯狂进出爽爽爽视频 | 理论片87福利理论电影 | 国产免费久久久久久无码 | 亚洲欧美日韩综合久久久 | 亚洲国产欧美在线成人 | 无码一区二区三区在线 | 男女猛烈xx00免费视频试看 | 中文字幕中文有码在线 | 精品久久久久香蕉网 | 国产区女主播在线观看 | 国产精品va在线观看无码 | 免费人成网站视频在线观看 | 亚欧洲精品在线视频免费观看 | 少妇无套内谢久久久久 | 亚洲 激情 小说 另类 欧美 | 中文字幕无码视频专区 | 四虎影视成人永久免费观看视频 | 99er热精品视频 | 久久亚洲日韩精品一区二区三区 | 男女猛烈xx00免费视频试看 | 久久久久久久久888 | 好男人www社区 | 日本护士毛茸茸高潮 | 国产成人无码午夜视频在线观看 | 六十路熟妇乱子伦 | a在线亚洲男人的天堂 | 国产精品怡红院永久免费 | 精品人妻中文字幕有码在线 | 国产亚洲美女精品久久久2020 | 风流少妇按摩来高潮 | 色老头在线一区二区三区 | 女人高潮内射99精品 | 国产乱人伦偷精品视频 | 欧美性猛交xxxx富婆 | 国产人妖乱国产精品人妖 | 亚洲国产成人av在线观看 | 国产精品va在线播放 | 在线视频网站www色 | 狠狠色噜噜狠狠狠狠7777米奇 | 国产无遮挡又黄又爽又色 | 久久97精品久久久久久久不卡 | 色偷偷av老熟女 久久精品人妻少妇一区二区三区 | 欧洲精品码一区二区三区免费看 | 婷婷色婷婷开心五月四房播播 | 日日麻批免费40分钟无码 | 午夜精品一区二区三区的区别 | 东京热无码av男人的天堂 | 久久无码专区国产精品s | 日本丰满熟妇videos | 澳门永久av免费网站 | 老头边吃奶边弄进去呻吟 | 亚洲国产午夜精品理论片 | 欧洲欧美人成视频在线 | 成 人影片 免费观看 | 男人扒开女人内裤强吻桶进去 | 四十如虎的丰满熟妇啪啪 | 亚洲 高清 成人 动漫 | 久久国产36精品色熟妇 | 午夜丰满少妇性开放视频 | 亚洲色偷偷偷综合网 | 中文字幕无码av激情不卡 | 久久婷婷五月综合色国产香蕉 | 55夜色66夜色国产精品视频 | 亚洲成熟女人毛毛耸耸多 | 国产av久久久久精东av | 免费无码一区二区三区蜜桃大 | 亚洲国产精品美女久久久久 | 欧美日韩一区二区综合 | 久久久国产一区二区三区 | 亚洲国产精品美女久久久久 | 天堂一区人妻无码 | 伊在人天堂亚洲香蕉精品区 | 波多野结衣 黑人 | 日韩人妻系列无码专区 | 色狠狠av一区二区三区 | 国产免费久久久久久无码 | 中文字幕乱码人妻无码久久 | 久久亚洲中文字幕精品一区 | 久久久久亚洲精品中文字幕 | 伊人久久大香线焦av综合影院 | 沈阳熟女露脸对白视频 | 少妇无码一区二区二三区 | 奇米影视7777久久精品人人爽 | 亚洲精品久久久久avwww潮水 | 国产精品-区区久久久狼 | 一个人看的视频www在线 | 国产精品无套呻吟在线 | 午夜男女很黄的视频 | 美女张开腿让人桶 | 国产莉萝无码av在线播放 | 99精品视频在线观看免费 | 5858s亚洲色大成网站www | 日本护士毛茸茸高潮 | 免费无码午夜福利片69 | 黑森林福利视频导航 | 亚洲热妇无码av在线播放 | 真人与拘做受免费视频 | 国产午夜精品一区二区三区嫩草 | 日韩欧美中文字幕公布 | 亚洲精品一区二区三区大桥未久 | 午夜男女很黄的视频 | 中文精品无码中文字幕无码专区 | 中文精品久久久久人妻不卡 | 在线亚洲高清揄拍自拍一品区 | 午夜成人1000部免费视频 | 亚洲熟妇色xxxxx欧美老妇 | 久久亚洲a片com人成 | 性色欲情网站iwww九文堂 | 人妻夜夜爽天天爽三区 | 国产明星裸体无码xxxx视频 | 国产人妻精品一区二区三区不卡 | 午夜精品久久久内射近拍高清 | 欧美成人午夜精品久久久 | 国产一区二区三区影院 | 亚洲精品一区二区三区大桥未久 | 亚洲春色在线视频 | а天堂中文在线官网 | 国产乱子伦视频在线播放 | 亚洲自偷自偷在线制服 | 成人无码精品一区二区三区 | 欧美精品一区二区精品久久 | 精品久久久无码中文字幕 | 天堂在线观看www | 国产精品久久久久久久影院 | 狠狠色丁香久久婷婷综合五月 | 亚洲一区二区三区香蕉 | 国产精品99爱免费视频 | 久久精品中文闷骚内射 | 中文字幕日韩精品一区二区三区 | 亚洲综合无码久久精品综合 | 国产人成高清在线视频99最全资源 | 亚洲精品国产第一综合99久久 | 免费中文字幕日韩欧美 | 小泽玛莉亚一区二区视频在线 | 奇米影视7777久久精品人人爽 | 内射老妇bbwx0c0ck | 无码国产乱人伦偷精品视频 | 国产人妻精品一区二区三区不卡 | 无码国产色欲xxxxx视频 | 精品人妻av区 | 任你躁在线精品免费 | 极品尤物被啪到呻吟喷水 | 成人无码影片精品久久久 | 爱做久久久久久 | 亚洲成av人影院在线观看 | 久久99热只有频精品8 | 欧美自拍另类欧美综合图片区 | 色综合天天综合狠狠爱 | 麻豆国产97在线 | 欧洲 | 7777奇米四色成人眼影 | 国产99久久精品一区二区 | 国产成人无码一二三区视频 | 色欲av亚洲一区无码少妇 | 少妇人妻av毛片在线看 | 精品熟女少妇av免费观看 | 精品国偷自产在线视频 | 亚洲欧美色中文字幕在线 | 无套内谢的新婚少妇国语播放 | 奇米影视7777久久精品 | 亚洲乱码日产精品bd | 亚洲成av人片天堂网无码】 | 亚洲精品久久久久avwww潮水 | 大乳丰满人妻中文字幕日本 | 香蕉久久久久久av成人 | 日本xxxx色视频在线观看免费 | 日本欧美一区二区三区乱码 | 中文字幕 人妻熟女 | 澳门永久av免费网站 | 久久久久久久人妻无码中文字幕爆 | 人人妻人人澡人人爽精品欧美 | 欧美自拍另类欧美综合图片区 | 无套内谢的新婚少妇国语播放 | 国产亚洲精品久久久久久大师 | 丰满少妇弄高潮了www | 国产精品亚洲一区二区三区喷水 | 欧美人与动性行为视频 | 国产舌乚八伦偷品w中 | 野外少妇愉情中文字幕 | 国产精品无套呻吟在线 | 高清国产亚洲精品自在久久 | 国语自产偷拍精品视频偷 | 97精品国产97久久久久久免费 | 亚洲精品国产精品乱码视色 | 国产va免费精品观看 | 丰满少妇熟乱xxxxx视频 | 18精品久久久无码午夜福利 | 国产精品久久久一区二区三区 | 亚洲高清偷拍一区二区三区 | 亚洲大尺度无码无码专区 | 性色欲网站人妻丰满中文久久不卡 | 国产午夜手机精彩视频 | 国内精品人妻无码久久久影院蜜桃 | 亚洲无人区一区二区三区 | 波多野结衣av一区二区全免费观看 | 亚洲日本va中文字幕 | 奇米综合四色77777久久 东京无码熟妇人妻av在线网址 | 蜜桃av蜜臀av色欲av麻 999久久久国产精品消防器材 | 国产精品久久久午夜夜伦鲁鲁 | 国产精品无码成人午夜电影 | 色一情一乱一伦一视频免费看 | 国产女主播喷水视频在线观看 | 久久精品国产99精品亚洲 | 台湾无码一区二区 | 人人超人人超碰超国产 | 精品人妻人人做人人爽 | 欧美变态另类xxxx | 又大又黄又粗又爽的免费视频 | 日日碰狠狠丁香久燥 | 性欧美熟妇videofreesex | 精品无码成人片一区二区98 | 伊人色综合久久天天小片 | 国产精品香蕉在线观看 | 中文字幕精品av一区二区五区 | 亚洲中文字幕无码一久久区 | 国产av一区二区精品久久凹凸 | 性生交片免费无码看人 | 亚洲男人av香蕉爽爽爽爽 | 兔费看少妇性l交大片免费 | 人妻人人添人妻人人爱 | 人妻体内射精一区二区三四 | 一本一道久久综合久久 | 欧美三级不卡在线观看 | 久久综合给久久狠狠97色 | 久久视频在线观看精品 | 国产精品毛片一区二区 | 男人的天堂av网站 | 亚洲乱码中文字幕在线 | 性欧美熟妇videofreesex | 国产深夜福利视频在线 | 成人综合网亚洲伊人 | 大肉大捧一进一出好爽视频 | 少妇性l交大片欧洲热妇乱xxx | 久久久无码中文字幕久... | 国产成人一区二区三区在线观看 | 国产午夜无码精品免费看 | 精品久久久中文字幕人妻 | 内射白嫩少妇超碰 | 亚洲精品久久久久avwww潮水 | 国内少妇偷人精品视频 | 婷婷六月久久综合丁香 | 久久久久久av无码免费看大片 | 久久久久av无码免费网 | 国产精品爱久久久久久久 | 久久亚洲中文字幕精品一区 | 国产精品成人av在线观看 | 久久久国产精品无码免费专区 | 国产午夜无码精品免费看 | 天天躁夜夜躁狠狠是什么心态 | 在线欧美精品一区二区三区 | 性色欲网站人妻丰满中文久久不卡 | 大色综合色综合网站 | 亚洲国产成人a精品不卡在线 | 久久久久免费看成人影片 | 少妇人妻av毛片在线看 | 国产麻豆精品精东影业av网站 | 国产亚洲精品久久久ai换 | 67194成是人免费无码 | 国产成人精品久久亚洲高清不卡 | 久久亚洲精品中文字幕无男同 | 在线观看国产午夜福利片 | 亚洲自偷自偷在线制服 | 国内揄拍国内精品人妻 | 狠狠色丁香久久婷婷综合五月 | 最近免费中文字幕中文高清百度 | 激情五月综合色婷婷一区二区 | 夜先锋av资源网站 | 午夜嘿嘿嘿影院 | 夫妻免费无码v看片 | 国产内射老熟女aaaa | 亚洲自偷自拍另类第1页 | 国产猛烈高潮尖叫视频免费 | 国产精品亚洲专区无码不卡 | 色 综合 欧美 亚洲 国产 | 欧美日韩色另类综合 | 国产av人人夜夜澡人人爽麻豆 | 久久久久免费看成人影片 | 夜夜躁日日躁狠狠久久av | 日本饥渴人妻欲求不满 | 中文字幕+乱码+中文字幕一区 | 国产女主播喷水视频在线观看 | 久久99国产综合精品 | 性欧美videos高清精品 | 俄罗斯老熟妇色xxxx | 久久 国产 尿 小便 嘘嘘 | 18黄暴禁片在线观看 | 国产午夜亚洲精品不卡下载 | 久久精品中文字幕大胸 | 中文字幕av无码一区二区三区电影 | 老太婆性杂交欧美肥老太 | 丁香啪啪综合成人亚洲 | 在教室伦流澡到高潮hnp视频 | 亚洲一区二区三区含羞草 | 国产成人精品一区二区在线小狼 | 久久久久久亚洲精品a片成人 | 熟女俱乐部五十路六十路av | 亚洲成av人综合在线观看 | 无码人妻黑人中文字幕 | 久久综合香蕉国产蜜臀av | 国产激情精品一区二区三区 | 国产精品久久国产精品99 | 国产成人精品视频ⅴa片软件竹菊 | 中文字幕色婷婷在线视频 | 久久亚洲中文字幕精品一区 | 中文字幕av伊人av无码av | 午夜肉伦伦影院 | 国产免费无码一区二区视频 | 精品 日韩 国产 欧美 视频 | 97久久国产亚洲精品超碰热 | 美女极度色诱视频国产 | 正在播放东北夫妻内射 | 亚洲人成无码网www | 欧美午夜特黄aaaaaa片 | 国产女主播喷水视频在线观看 | www国产亚洲精品久久网站 | 国产亚洲精品精品国产亚洲综合 | 国产特级毛片aaaaaaa高清 | 国产精品沙发午睡系列 | 国产麻豆精品精东影业av网站 | 国产农村妇女高潮大叫 | 中文字幕无码日韩欧毛 | 偷窥日本少妇撒尿chinese | 网友自拍区视频精品 | 亚洲国产综合无码一区 | 亚洲中文字幕在线观看 | 国产美女精品一区二区三区 | 成人一在线视频日韩国产 | 国产日产欧产精品精品app | 国産精品久久久久久久 | 免费播放一区二区三区 | 一本大道久久东京热无码av | 性生交大片免费看女人按摩摩 | 久久 国产 尿 小便 嘘嘘 | 男人的天堂2018无码 | 狂野欧美性猛交免费视频 | 免费网站看v片在线18禁无码 | 亚洲无人区午夜福利码高清完整版 | 免费男性肉肉影院 | 国产精品久久久午夜夜伦鲁鲁 | 亚洲欧洲无卡二区视頻 | 国产农村妇女aaaaa视频 撕开奶罩揉吮奶头视频 | 国产成人午夜福利在线播放 | 免费无码一区二区三区蜜桃大 | 日产精品99久久久久久 | 国产精品.xx视频.xxtv | 大肉大捧一进一出好爽视频 | 精品人妻中文字幕有码在线 | 日产精品高潮呻吟av久久 | 精品偷拍一区二区三区在线看 | 青草青草久热国产精品 | 亚洲一区二区三区国产精华液 | 高中生自慰www网站 | 亚洲小说图区综合在线 | 免费中文字幕日韩欧美 | 精品久久8x国产免费观看 | 亚洲日韩一区二区 | 黑人粗大猛烈进出高潮视频 | 99久久99久久免费精品蜜桃 | 成人综合网亚洲伊人 | 国产精品久久久久久亚洲毛片 | 色欲久久久天天天综合网精品 | 日本精品久久久久中文字幕 | 中国大陆精品视频xxxx | 日本va欧美va欧美va精品 | 日本爽爽爽爽爽爽在线观看免 | 国产精品美女久久久 | 5858s亚洲色大成网站www | 欧洲熟妇色 欧美 | 亚洲 a v无 码免 费 成 人 a v | 欧美亚洲国产一区二区三区 | 又湿又紧又大又爽a视频国产 | 伊人久久大香线焦av综合影院 | 国产精品久久久久久久影院 | 鲁大师影院在线观看 | 美女张开腿让人桶 | 国产绳艺sm调教室论坛 | 亚洲成av人片在线观看无码不卡 | 国产两女互慰高潮视频在线观看 | 乱人伦人妻中文字幕无码 | 免费国产黄网站在线观看 | 国产精品亚洲а∨无码播放麻豆 | 97色伦图片97综合影院 | 狂野欧美性猛xxxx乱大交 | 国产精品久免费的黄网站 | 狠狠cao日日穞夜夜穞av | 日日摸天天摸爽爽狠狠97 | 亚洲码国产精品高潮在线 | 牲交欧美兽交欧美 | 欧美精品一区二区精品久久 | 激情内射亚州一区二区三区爱妻 | 美女黄网站人色视频免费国产 | 精品欧洲av无码一区二区三区 | 国产特级毛片aaaaaaa高清 | 中文字幕日韩精品一区二区三区 | 免费无码午夜福利片69 | 国产精品99久久精品爆乳 | 一区二区三区高清视频一 | 久久久久免费看成人影片 | 无遮无挡爽爽免费视频 | 特大黑人娇小亚洲女 | 国产乱人伦偷精品视频 | 国产精品久久久一区二区三区 | 国产区女主播在线观看 | 亚洲精品中文字幕乱码 | 日本乱人伦片中文三区 | 国产真人无遮挡作爱免费视频 | 又紧又大又爽精品一区二区 | 在线精品亚洲一区二区 | 一本久久a久久精品亚洲 | 男女爱爱好爽视频免费看 | aa片在线观看视频在线播放 | 中文亚洲成a人片在线观看 | 日本大香伊一区二区三区 | 国产乱人伦app精品久久 国产在线无码精品电影网 国产国产精品人在线视 | 成熟女人特级毛片www免费 | 国产精品福利视频导航 | 18无码粉嫩小泬无套在线观看 | 国产精品成人av在线观看 | 水蜜桃av无码 | 无码国产色欲xxxxx视频 | 国产乱人无码伦av在线a | 亚洲熟妇自偷自拍另类 | 牲欲强的熟妇农村老妇女视频 | 又大又硬又爽免费视频 | www一区二区www免费 | 色情久久久av熟女人妻网站 | 大乳丰满人妻中文字幕日本 | 久久久久久久女国产乱让韩 | 成人欧美一区二区三区 | 亚洲午夜福利在线观看 | 丝袜人妻一区二区三区 | 大乳丰满人妻中文字幕日本 | 麻豆精品国产精华精华液好用吗 | 无码任你躁久久久久久久 | 欧洲熟妇色 欧美 | 国产熟女一区二区三区四区五区 | 在线观看国产一区二区三区 | 久久这里只有精品视频9 | 成 人 网 站国产免费观看 | 高潮毛片无遮挡高清免费 | 国产亚洲视频中文字幕97精品 | 激情内射亚州一区二区三区爱妻 | 在线看片无码永久免费视频 | 色综合久久网 | 激情爆乳一区二区三区 | 中文无码成人免费视频在线观看 | 麻豆av传媒蜜桃天美传媒 | 亚洲国产一区二区三区在线观看 | 无码人妻久久一区二区三区不卡 | 99精品久久毛片a片 | 人人爽人人澡人人人妻 | 久久久亚洲欧洲日产国码αv | 日本一本二本三区免费 | 免费无码的av片在线观看 | 无遮无挡爽爽免费视频 | 老子影院午夜精品无码 | 麻豆国产人妻欲求不满谁演的 | 伊人久久大香线蕉亚洲 | 免费无码一区二区三区蜜桃大 | 无码国产色欲xxxxx视频 | 无码帝国www无码专区色综合 | 免费国产成人高清在线观看网站 | 国内少妇偷人精品视频 | 老熟女乱子伦 | 免费视频欧美无人区码 | а√资源新版在线天堂 | 精品久久久久久亚洲精品 | 国产乱人无码伦av在线a | 一二三四在线观看免费视频 | 国内精品久久毛片一区二区 | 少妇无码av无码专区在线观看 | 久久精品国产一区二区三区 | 久久婷婷五月综合色国产香蕉 | 兔费看少妇性l交大片免费 | 又湿又紧又大又爽a视频国产 | 国产精品亚洲综合色区韩国 | 四虎影视成人永久免费观看视频 | 亚洲第一无码av无码专区 | 人妻无码αv中文字幕久久琪琪布 | 色婷婷av一区二区三区之红樱桃 | 少妇一晚三次一区二区三区 | 国产精品人人爽人人做我的可爱 | 青青久在线视频免费观看 | 亚洲欧美日韩成人高清在线一区 | 精品一区二区三区波多野结衣 | 少妇无码av无码专区在线观看 | 成 人 网 站国产免费观看 | 妺妺窝人体色www在线小说 | 丝袜足控一区二区三区 | 日本熟妇乱子伦xxxx | 亚洲精品鲁一鲁一区二区三区 | 久久久国产一区二区三区 | 亚洲熟妇色xxxxx欧美老妇y | 性欧美疯狂xxxxbbbb | 老熟妇仑乱视频一区二区 | 国产后入清纯学生妹 | 麻豆人妻少妇精品无码专区 | 亚洲色欲久久久综合网东京热 | 无码播放一区二区三区 | 欧美丰满熟妇xxxx性ppx人交 | 国产无遮挡又黄又爽免费视频 | 夜夜高潮次次欢爽av女 | 中文字幕精品av一区二区五区 | 亚洲中文字幕久久无码 | 久久久久人妻一区精品色欧美 | 欧美人与牲动交xxxx | 欧美熟妇另类久久久久久不卡 | 亚洲欧美色中文字幕在线 | 国产av无码专区亚洲awww | 少妇厨房愉情理9仑片视频 | 又大又黄又粗又爽的免费视频 | 荡女精品导航 | 天天摸天天透天天添 | 双乳奶水饱满少妇呻吟 | 久久精品人人做人人综合试看 | 51国偷自产一区二区三区 | av香港经典三级级 在线 | 88国产精品欧美一区二区三区 | 午夜福利试看120秒体验区 | 久久亚洲国产成人精品性色 | 人妻与老人中文字幕 | 呦交小u女精品视频 | 国内综合精品午夜久久资源 | 蜜桃av抽搐高潮一区二区 | 人人澡人人透人人爽 | 国产精品无码久久av | 国产成人精品一区二区在线小狼 |