精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

這次答應我,一舉拿下 I/O 多路復用!

系統 Linux
這次,我們以最簡單 socket 網絡模型,一步一步的過度到 I/O 多路復用。但我不會具體細節說到每個系統調用的參數,這方面書上肯定比我說的詳細。

[[388226]]

本文轉載自微信公眾號「小林coding」,作者小林coding。轉載本文請聯系小林coding公眾號。

這次,我們以最簡單 socket 網絡模型,一步一步的過度到 I/O 多路復用。

但我不會具體細節說到每個系統調用的參數,這方面書上肯定比我說的詳細。

好了,發車!

 

最基本的 Socket 模型

要想客戶端和服務器能在網絡中通信,那必須得使用 Socket 編程,它是進程間通信里比較特別的方式,特別之處在于它是可以跨主機間通信。

Socket 的中文名叫作插口,咋一看還挺迷惑的。事實上,雙方要進行網絡通信前,各自得創建一個 Socket,這相當于客戶端和服務器都開了一個“口子”,雙方讀取和發送數據的時候,都通過這個“口子”。這樣一看,是不是覺得很像弄了一根網線,一頭插在客戶端,一頭插在服務端,然后進行通信。

創建 Socket 的時候,可以指定網絡層使用的是 IPv4 還是 IPv6,傳輸層使用的是 TCP 還是 UDP。

UDP 的 Socket 編程相對簡單些,這里我們只介紹基于 TCP 的 Socket 編程。

服務器的程序要先跑起來,然后等待客戶端的連接和數據,我們先來看看服務端的 Socket 編程過程是怎樣的。

服務端首先調用 socket() 函數,創建網絡協議為 IPv4,以及傳輸協議為 TCP 的 Socket ,接著調用 bind() 函數,給這個 Socket 綁定一個 IP 地址和端口,綁定這兩個的目的是什么?

  • 綁定端口的目的:當內核收到 TCP 報文,通過 TCP 頭里面的端口號,來找到我們的應用程序,然后把數據傳遞給我們。
  • 綁定 IP 地址的目的:一臺機器是可以有多個網卡的,每個網卡都有對應的 IP 地址,當綁定一個網卡時,內核在收到該網卡上的包,才會發給我們;

綁定完 IP 地址和端口后,就可以調用 listen() 函數進行監聽,此時對應 TCP 狀態圖中的 listen,如果我們要判定服務器中一個網絡程序有沒有啟動,可以通過netstate 命令查看對應的端口號是否有被監聽。

服務端進入了監聽狀態后,通過調用 accept() 函數,來從內核獲取客戶端的連接,如果沒有客戶端連接,則會阻塞等待客戶端連接的到來。

那客戶端是怎么發起連接的呢?客戶端在創建好 Socket 后,調用 connect() 函數發起連接,該函數的參數要指明服務端的 IP 地址和端口號,然后萬眾期待的 TCP 三次握手就開始了。

在 TCP 連接的過程中,服務器的內核實際上為每個 Socket 維護了兩個隊列:

一個是還沒完全建立連接的隊列,稱為 TCP 半連接隊列,這個隊列都是沒有完成三次握手的連接,此時服務端處于 syn_rcvd 的狀態;

一個是一件建立連接的隊列,稱為 TCP 全連接隊列,這個隊列都是完成了三次握手的連接,此時服務端處于 established 狀態;

當 TCP 全連接隊列不為空后,服務端的 accept() 函數,就會從內核中的 TCP 全連接隊列里拿出一個已經完成連接的 Socket 返回應用程序,后續數據傳輸都用這個 Socket。

注意,監聽的 Socket 和真正用來傳數據的 Socket 是兩個:

  • 一個叫作監聽 Socket;
  • 一個叫作已連接 Socket;

連接建立后,客戶端和服務端就開始相互傳輸數據了,雙方都可以通過 read() 和write() 函數來讀寫數據。

至此, TCP 協議的 Socket 程序的調用過程就結束了,整個過程如下圖:

 

看到這,不知道你有沒有覺得讀寫 Socket 的方式,好像讀寫文件一樣。

是的,基于 Linux 一切皆文件的理念,在內核中 Socket 也是以「文件」的形式存在的,也是有對應的文件描述符。

PS : 下面會說到內核里的數據結構,不感興趣的可以跳過這一部分,不會對后續的內容有影響。

文件描述符的作用是什么?每一個進程都有一個數據結構 task_struct,該結構體里有一個指向「文件描述符數組」的成員指針。該數組里列出這個進程打開的所有文件的文件描述符。數組的下標是文件描述符,是一個整數,而數組的內容是一個指針,指向內核中所有打開的文件的列表,也就是說內核可以通過文件描述符找到對應打開的文件。

然后每個文件都有一個 inode,Socket 文件的 inode 指向了內核中的 Socket 結構,在這個結構體里有兩個隊列,分別是發送隊列和接收隊列,這個兩個隊列里面保存的是一個個 struct sk_buff,用鏈表的組織形式串起來。

sk_buff 可以表示各個層的數據包,在應用層數據包叫 data,在 TCP 層我們稱為 segment,在 IP 層我們叫 packet,在數據鏈路層稱為 frame。

你可能會好奇,為什么全部數據包只用一個結構體來描述呢?協議棧采用的是分層結構,上層向下層傳遞數據時需要增加包頭,下層向上層數據時又需要去掉包頭,如果每一層都用一個結構體,那在層之間傳遞數據的時候,就要發生多次拷貝,這將大大降低 CPU 效率。

于是,為了在層級之間傳遞數據時,不發生拷貝,只用 sk_buff 一個結構體來描述所有的網絡包,那它是如何做到的呢?是通過調整 sk_buff 中 data 的指針,比如:

  • 當接收報文時,從網卡驅動開始,通過協議棧層層往上傳送數據報,通過增加 skb->data 的值,來逐步剝離協議首部。
  • 當要發送報文時,創建 sk_buff 結構體,數據緩存區的頭部預留足夠的空間,用來填充各層首部,在經過各下層協議時,通過減少 skb->data 的值來增加協議首部。

你可以從下面這張圖看到,當發送報文時,data 指針的移動過程。

 

如何服務更多的用戶?

前面提到的 TCP Socket 調用流程是最簡單、最基本的,它基本只能一對一通信,因為使用的是同步阻塞的方式,當服務端在還沒處理完一個客戶端的網絡 I/O 時,或者 讀寫操作發生阻塞時,其他客戶端是無法與服務端連接的。

可如果我們服務器只能服務一個客戶,那這樣就太浪費資源了,于是我們要改進這個網絡 I/O 模型,以支持更多的客戶端。

在改進網絡 I/O 模型前,我先來提一個問題,你知道服務器單機理論最大能連接多少個客戶端?

相信你知道 TCP 連接是由四元組唯一確認的,這個四元組就是:本機IP, 本機端口, 對端IP, 對端端口。

服務器作為服務方,通常會在本地固定監聽一個端口,等待客戶端的連接。因此服務器的本地 IP 和端口是固定的,于是對于服務端 TCP 連接的四元組只有對端 IP 和端口是會變化的,所以最大 TCP 連接數 = 客戶端 IP 數×客戶端端口數。

對于 IPv4,客戶端的 IP 數最多為 2 的 32 次方,客戶端的端口數最多為 2 的 16 次方,也就是服務端單機最大 TCP 連接數約為 2 的 48 次方。

這個理論值相當“豐滿”,但是服務器肯定承載不了那么大的連接數,主要會受兩個方面的限制:

  • 文件描述符,Socket 實際上是一個文件,也就會對應一個文件描述符。在 Linux 下,單個進程打開的文件描述符數是有限制的,沒有經過修改的值一般都是 1024,不過我們可以通過 ulimit 增大文件描述符的數目;
  • 系統內存,每個 TCP 連接在內核中都有對應的數據結構,意味著每個連接都是會占用一定內存的;

那如果服務器的內存只有 2 GB,網卡是千兆的,能支持并發 1 萬請求嗎?

并發 1 萬請求,也就是經典的 C10K 問題 ,C 是 Client 單詞首字母縮寫,C10K 就是單機同時處理 1 萬個請求的問題。

從硬件資源角度看,對于 2GB 內存千兆網卡的服務器,如果每個請求處理占用不到 200KB 的內存和 100Kbit 的網絡帶寬就可以滿足并發 1 萬個請求。

不過,要想真正實現 C10K 的服務器,要考慮的地方在于服務器的網絡 I/O 模型,效率低的模型,會加重系統開銷,從而會離 C10K 的目標越來越遠。

多進程模型

基于最原始的阻塞網絡 I/O, 如果服務器要支持多個客戶端,其中比較傳統的方式,就是使用多進程模型,也就是為每個客戶端分配一個進程來處理請求。

服務器的主進程負責監聽客戶的連接,一旦與客戶端連接完成,accept() 函數就會返回一個「已連接 Socket」,這時就通過 fork() 函數創建一個子進程,實際上就把父進程所有相關的東西都復制一份,包括文件描述符、內存地址空間、程序計數器、執行的代碼等。

這兩個進程剛復制完的時候,幾乎一摸一樣。不過,會根據返回值來區分是父進程還是子進程,如果返回值是 0,則是子進程;如果返回值是其他的整數,就是父進程。

正因為子進程會復制父進程的文件描述符,于是就可以直接使用「已連接 Socket 」和客戶端通信了,

可以發現,子進程不需要關心「監聽 Socket」,只需要關心「已連接 Socket」;父進程則相反,將客戶服務交給子進程來處理,因此父進程不需要關心「已連接 Socket」,只需要關心「監聽 Socket」。

下面這張圖描述了從連接請求到連接建立,父進程創建生子進程為客戶服務。

 

另外,當「子進程」退出時,實際上內核里還會保留該進程的一些信息,也是會占用內存的,如果不做好“回收”工作,就會變成僵尸進程,隨著僵尸進程越多,會慢慢耗盡我們的系統資源。

因此,父進程要“善后”好自己的孩子,怎么善后呢?那么有兩種方式可以在子進程退出后回收資源,分別是調用 wait() 和 waitpid() 函數。

這種用多個進程來應付多個客戶端的方式,在應對 100 個客戶端還是可行的,但是當客戶端數量高達一萬時,肯定扛不住的,因為每產生一個進程,必會占據一定的系統資源,而且進程間上下文切換的“包袱”是很重的,性能會大打折扣。

進程的上下文切換不僅包含了虛擬內存、棧、全局變量等用戶空間的資源,還包括了內核堆棧、寄存器等內核空間的資源。

多線程模型

既然進程間上下文切換的“包袱”很重,那我們就搞個比較輕量級的模型來應對多用戶的請求 —— 多線程模型。

線程是運行在進程中的一個“邏輯流”,單進程中可以運行多個線程,同進程里的線程可以共享進程的部分資源的,比如文件描述符列表、進程空間、代碼、全局數據、堆、共享庫等,這些共享些資源在上下文切換時是不需要切換,而只需要切換線程的私有數據、寄存器等不共享的數據,因此同一個進程下的線程上下文切換的開銷要比進程小得多。

當服務器與客戶端 TCP 完成連接后,通過 pthread_create() 函數創建線程,然后將「已連接 Socket」的文件描述符傳遞給線程函數,接著在線程里和客戶端進行通信,從而達到并發處理的目的。

如果每來一個連接就創建一個線程,線程運行完后,還得操作系統還得銷毀線程,雖說線程切換的上寫文開銷不大,但是如果頻繁創建和銷毀線程,系統開銷也是不小的。

那么,我們可以使用線程池的方式來避免線程的頻繁創建和銷毀,所謂的線程池,就是提前創建若干個線程,這樣當由新連接建立時,將這個已連接的 Socket 放入到一個隊列里,然后線程池里的線程負責從隊列中取出已連接 Socket 進程處理。

 

需要注意的是,這個隊列是全局的,每個線程都會操作,為了避免多線程競爭,線程在操作這個隊列前要加鎖。

上面基于進程或者線程模型的,其實還是有問題的。新到來一個 TCP 連接,就需要分配一個進程或者線程,那么如果要達到 C10K,意味著要一臺機器維護 1 萬個連接,相當于要維護 1 萬個進程/線程,操作系統就算死扛也是扛不住的。

I/O 多路復用

既然為每個請求分配一個進程/線程的方式不合適,那有沒有可能只使用一個進程來維護多個 Socket 呢?答案是有的,那就是 I/O 多路復用技術。

 

一個進程雖然任一時刻只能處理一個請求,但是處理每個請求的事件時,耗時控制在 1 毫秒以內,這樣 1 秒內就可以處理上千個請求,把時間拉長來看,多個請求復用了一個進程,這就是多路復用,這種思想很類似一個 CPU 并發多個進程,所以也叫做時分多路復用。

我們熟悉的 select/poll/epoll 內核提供給用戶態的多路復用系統調用,進程可以通過一個系統調用函數從內核中獲取多個事件。

select/poll/epoll 是如何獲取網絡事件的呢?在獲取事件時,先把所有連接(文件描述符)傳給內核,再由內核返回產生了事件的連接,然后在用戶態中再處理這些連接對應的請求即可。

select/poll/epoll 這是三個多路復用接口,都能實現 C10K 嗎?接下來,我們分別說說它們。

select/poll

select 實現多路復用的方式是,將已連接的 Socket 都放到一個文件描述符集合,然后調用 select 函數將文件描述符集合拷貝到內核里,讓內核來檢查是否有網絡事件產生,檢查的方式很粗暴,就是通過遍歷文件描述符集合的方式,當檢查到有事件產生后,將此 Socket 標記為可讀或可寫, 接著再把整個文件描述符集合拷貝回用戶態里,然后用戶態還需要再通過遍歷的方法找到可讀或可寫的 Socket,然后再對其處理。

所以,對于 select 這種方式,需要進行 2 次「遍歷」文件描述符集合,一次是在內核態里,一個次是在用戶態里 ,而且還會發生 2 次「拷貝」文件描述符集合,先從用戶空間傳入內核空間,由內核修改后,再傳出到用戶空間中。

select 使用固定長度的 BitsMap,表示文件描述符集合,而且所支持的文件描述符的個數是有限制的,在 Linux 系統中,由內核中的 FD_SETSIZE 限制, 默認最大值為 1024,只能監聽 0~1023 的文件描述符。

poll 不再用 BitsMap 來存儲所關注的文件描述符,取而代之用動態數組,以鏈表形式來組織,突破了 select 的文件描述符個數限制,當然還會受到系統文件描述符限制。

但是 poll 和 select 并沒有太大的本質區別,都是使用「線性結構」存儲進程關注的 Socket 集合,因此都需要遍歷文件描述符集合來找到可讀或可寫的 Socket,時間復雜度為 O(n),而且也需要在用戶態與內核態之間拷貝文件描述符集合,這種方式隨著并發數上來,性能的損耗會呈指數級增長。

epoll

epoll 通過兩個方面,很好解決了 select/poll 的問題。

第一點,epoll 在內核里使用紅黑樹來跟蹤進程所有待檢測的文件描述字,把需要監控的 socket 通過 epoll_ctl() 函數加入內核中的紅黑樹里,紅黑樹是個高效的數據結構,增刪查一般時間復雜度是 O(logn),通過對這棵黑紅樹進行操作,這樣就不需要像 select/poll 每次操作時都傳入整個 socket 集合,只需要傳入一個待檢測的 socket,減少了內核和用戶空間大量的數據拷貝和內存分配。

第二點, epoll 使用事件驅動的機制,內核里維護了一個鏈表來記錄就緒事件,當某個 socket 有事件發生時,通過回調函數內核會將其加入到這個就緒事件列表中,當用戶調用 epoll_wait() 函數時,只會返回有事件發生的文件描述符的個數,不需要像 select/poll 那樣輪詢掃描整個 socket 集合,大大提高了檢測的效率。

從下圖你可以看到 epoll 相關的接口作用:

 

epoll 的方式即使監聽的 Socket 數量越多的時候,效率不會大幅度降低,能夠同時監聽的 Socket 的數目也非常的多了,上限就為系統定義的進程打開的最大文件描述符個數。因而,epoll 被稱為解決 C10K 問題的利器。

插個題外話,網上文章不少說,epoll_wait 返回時,對于就緒的事件,epoll使用的是共享內存的方式,即用戶態和內核態都指向了就緒鏈表,所以就避免了內存拷貝消耗。

這是錯的!看過 epoll 內核源碼的都知道,壓根就沒有使用共享內存這個玩意。你可以從下面這份代碼看到, epoll_wait 實現的內核代碼中調用了 __put_user 函數,這個函數就是將數據從內核拷貝到用戶空間。

 

好了,這個題外話就說到這了,我們繼續!

epoll 支持兩種事件觸發模式,分別是邊緣觸發(edge-triggered,ET)和水平觸發(level-triggered,LT)。

這兩個術語還挺抽象的,其實它們的區別還是很好理解的。

  • 使用邊緣觸發模式時,當被監控的 Socket 描述符上有可讀事件發生時,服務器端只會從 epoll_wait 中蘇醒一次,即使進程沒有調用 read 函數從內核讀取數據,也依然只蘇醒一次,因此我們程序要保證一次性將內核緩沖區的數據讀取完;
  • 使用水平觸發模式時,當被監控的 Socket 上有可讀事件發生時,服務器端不斷地從 epoll_wait 中蘇醒,直到內核緩沖區數據被 read 函數讀完才結束,目的是告訴我們有數據需要讀取;

舉個例子,你的快遞被放到了一個快遞箱里,如果快遞箱只會通過短信通知你一次,即使你一直沒有去取,它也不會再發送第二條短信提醒你,這個方式就是邊緣觸發;如果快遞箱發現你的快遞沒有被取出,它就會不停地發短信通知你,直到你取出了快遞,它才消停,這個就是水平觸發的方式。

這就是兩者的區別,水平觸發的意思是只要滿足事件的條件,比如內核中有數據需要讀,就一直不斷地把這個事件傳遞給用戶;而邊緣觸發的意思是只有第一次滿足條件的時候才觸發,之后就不會再傳遞同樣的事件了。

如果使用水平觸發模式,當內核通知文件描述符可讀寫時,接下來還可以繼續去檢測它的狀態,看它是否依然可讀或可寫。所以在收到通知后,沒必要一次執行盡可能多的讀寫操作。

如果使用邊緣觸發模式,I/O 事件發生時只會通知一次,而且我們不知道到底能讀寫多少數據,所以在收到通知后應盡可能地讀寫數據,以免錯失讀寫的機會。因此,我們會循環從文件描述符讀寫數據,那么如果文件描述符是阻塞的,沒有數據可讀寫時,進程會阻塞在讀寫函數那里,程序就沒辦法繼續往下執行。所以,邊緣觸發模式一般和非阻塞 I/O 搭配使用,程序會一直執行 I/O 操作,直到系統調用(如 read 和 write)返回錯誤,錯誤類型為 EAGAIN 或 EWOULDBLOCK。

一般來說,邊緣觸發的效率比水平觸發的效率要高,因為邊緣觸發可以減少 epoll_wait 的系統調用次數,系統調用也是有一定的開銷的的,畢竟也存在上下文的切換。

select/poll 只有水平觸發模式,epoll 默認的觸發模式是水平觸發,但是可以根據應用場景設置為邊緣觸發模式。

另外,使用 I/O 多路復用時,最好搭配非阻塞 I/O 一起使用,Linux 手冊關于 select 的內容中有如下說明:

Under Linux, select() may report a socket file descriptor as "ready for reading", while nevertheless a subsequent read blocks. This could for example happen when data has arrived but upon examination has wrong checksum and is discarded. There may be other circumstances in which a file descriptor is spuriously reported as ready. Thus it may be safer to use O_NONBLOCK on sockets that should not block.

我谷歌翻譯的結果:

在Linux下,select() 可能會將一個 socket 文件描述符報告為 "準備讀取",而后續的讀取塊卻沒有。例如,當數據已經到達,但經檢查后發現有錯誤的校驗和而被丟棄時,就會發生這種情況。也有可能在其他情況下,文件描述符被錯誤地報告為就緒。因此,在不應該阻塞的 socket 上使用 O_NONBLOCK 可能更安全。

簡單點理解,就是多路復用 API 返回的事件并不一定可讀寫的,如果使用阻塞 I/O, 那么在調用 read/write 時則會發生程序阻塞,因此最好搭配非阻塞 I/O,以便應對極少數的特殊情況。

總結

最基礎的 TCP 的 Socket 編程,它是阻塞 I/O 模型,基本上只能一對一通信,那為了服務更多的客戶端,我們需要改進網絡 I/O 模型。

比較傳統的方式是使用多進程/線程模型,每來一個客戶端連接,就分配一個進程/線程,然后后續的讀寫都在對應的進程/線程,這種方式處理 100 個客戶端沒問題,但是當客戶端增大到 10000 個時,10000 個進程/線程的調度、上下文切換以及它們占用的內存,都會成為瓶頸。

為了解決上面這個問題,就出現了 I/O 的多路復用,可以只在一個進程里處理多個文件的 I/O,Linux 下有三種提供 I/O 多路復用的 API,分別是:select、poll、epoll。

select 和 poll 并沒有本質區別,它們內部都是使用「線性結構」來存儲進程關注的 Socket 集合。

在使用的時候,首先需要把關注的 Socket 集合通過 select/poll 系統調用從用戶態拷貝到內核態,然后由內核檢測事件,當有網絡事件產生時,內核需要遍歷進程關注 Socket 集合,找到對應的 Socket,并設置其狀態為可讀/可寫,然后把整個 Socket 集合從內核態拷貝到用戶態,用戶態還要繼續遍歷整個 Socket 集合找到可讀/可寫的 Socket,然后對其處理。

很明顯發現,select 和 poll 的缺陷在于,當客戶端越多,也就是 Socket 集合越大,Socket 集合的遍歷和拷貝會帶來很大的開銷,因此也很難應對 C10K。

epoll 是解決 C10K 問題的利器,通過兩個方面解決了 select/poll 的問題。

epoll 在內核里使用「紅黑樹」來關注進程所有待檢測的 Socket,紅黑樹是個高效的數據結構,增刪查一般時間復雜度是 O(logn),通過對這棵黑紅樹的管理,不需要像 select/poll 在每次操作時都傳入整個 Socket 集合,減少了內核和用戶空間大量的數據拷貝和內存分配。

epoll 使用事件驅動的機制,內核里維護了一個「鏈表」來記錄就緒事件,只將有事件發生的 Socket 集合傳遞給應用程序,不需要像 select/poll 那樣輪詢掃描整個集合(包含有和無事件的 Socket ),大大提高了檢測的效率。

而且,epoll 支持邊緣觸發和水平觸發的方式,而 select/poll 只支持水平觸發,一般而言,邊緣觸發的方式會比水平觸發的效率高。

參考資料

https://www.zhihu.com/question/39792257

https://journey-c.github.io/io-multiplexing/#25-io-multiplexing

https://panqiincs.me/2015/08/01/io-multiplexing-with-epoll/

原文鏈接:https://mp.weixin.qq.com/s/Qpa0qXxuIM8jrBqDaXmVNA

 

責任編輯:武曉燕 來源: 小林coding
相關推薦

2023-05-08 00:06:45

Go語言機制

2021-02-10 08:09:48

Netty網絡多路復用

2021-03-24 08:03:38

NettyJava NIO網絡技術

2020-10-13 07:51:03

五種IO模型

2024-12-30 00:00:05

2023-11-08 09:22:14

I/ORedis阻塞

2025-05-08 08:01:05

2019-12-23 14:53:26

IO復用

2021-06-09 19:25:13

IODubbo

2024-08-08 14:57:32

2023-01-09 10:04:47

IO多路復用模型

2022-03-26 08:49:13

MySQL數據存儲

2022-09-12 06:33:15

Select多路復用

2011-12-08 10:51:25

JavaNIO

2023-08-07 08:52:03

Java多路復用機制

2021-05-31 06:50:47

SelectPoll系統

2020-10-14 09:11:44

IO 多路復用實現機

2009-06-29 18:09:12

多路復用Oracle

2020-09-08 07:01:01

調度算法

2023-12-06 07:16:31

Go語言語句
點贊
收藏

51CTO技術棧公眾號

激情综合色综合久久综合| 欧美独立站高清久久| 偷窥少妇高潮呻吟av久久免费| 激情久久av| 中文字幕在线播出| 欧美三级视频| 伊人伊成久久人综合网站| 加勒比av中文字幕| 亚洲风情在线资源| 国产精品视频yy9299一区| 91免费在线观看网站| 国产在线观看黄色| 亚洲91久久| 亚洲精品小视频| www.污网站| av高清一区| 亚洲一区二区三区四区的| 日本精品国语自产拍在线观看| 国产色片在线观看| 久久久久久9| 久久人人看视频| 免费一级suv好看的国产网站| 国产精品色在线网站| 欧美精品高清视频| 久久国产色av免费观看| 色噜噜狠狠狠综合欧洲色8| 国产亚洲自拍一区| 国产精品国产一区二区| 91丨九色丨蝌蚪丨对白| 免费永久网站黄欧美| 欧美高清视频免费观看| 婷婷国产成人精品视频| 精品一区二区三区的国产在线观看| 欧美不卡一区二区| 热久久久久久久久| 2019年精品视频自拍| 黄色一区二区在线观看| 欧美亚洲色图视频| a级片国产精品自在拍在线播放| 久久九九影视网| 久久草视频在线看| 欧美一区二区三区激情| 国产精品一区二区在线播放 | 九九精品视频在线看| 日本国产高清不卡| 久久黄色精品视频| 国产日韩欧美一区在线| 国内精品美女av在线播放| 日韩成人毛片视频| 亚洲成人最新网站| 久久精品国产69国产精品亚洲| 卡一卡二卡三在线观看| 国产毛片一区二区三区| 国产视频欧美视频| 国产又爽又黄无码无遮挡在线观看| 大伊香蕉精品在线品播放| 日韩免费电影网站| 日本女人性视频| 日韩激情精品| 亚洲成人在线网| 午夜不卡久久精品无码免费| 波多野结衣欧美| 欧美不卡在线视频| 国模私拍在线观看| 一区二区三区四区在线看| 亚洲欧美日韩另类| 蜜臀久久99精品久久久久久| 国产a久久精品一区二区三区 | 成人在线高清免费| 亚洲va韩国va欧美va精品| 欧美日韩在线一| jizz内谢中国亚洲jizz| 欧美亚洲丝袜传媒另类| 国产成年人视频网站| 亚洲精品第一| 欧美电视剧在线看免费| 久久午夜夜伦鲁鲁片| 要久久电视剧全集免费| 在线中文字幕日韩| 国产精品久久久久久久精| 亚洲视频一区| 日本亚洲欧美成人| 一区二区不卡视频在线观看| 激情图区综合网| 国产富婆一区二区三区| 免费动漫网站在线观看| 国产精品久久三| 少妇一晚三次一区二区三区| 亚洲精品动漫| 制服丝袜av成人在线看| 亚洲天堂2024| 日产精品一区二区| 久久久亚洲影院| 国产偷人爽久久久久久老妇app| 狠狠色狠狠色合久久伊人| 国产美女99p| eeuss影院www在线观看| 亚洲欧洲国产日韩| 欧美日本视频在线观看| 亚洲一区二区av| 日韩经典一区二区三区| 任我爽在线视频| 午夜在线视频观看日韩17c| 国产在线久久久| 五月天婷婷在线观看| 国产精品成人在线观看| 每日在线更新av| 激情视频亚洲| 国产一区二区成人| 久久久精品99| 精品写真视频在线观看| 欧美一区1区三区3区公司 | 爽爽视频在线观看| 一区二区欧美在线观看| 污污视频网站免费观看| 国产精品99久久免费观看| 中文字幕av一区中文字幕天堂| 久久久全国免费视频| 奇米精品一区二区三区在线观看一| 97视频资源在线观看| 成年人视频在线看| 欧美日韩亚洲视频| 欧美成人精品一区二区综合免费| 99久久.com| 国产精品99久久久久久白浆小说| 国模无码一区二区三区| 亚洲男人的天堂网| 第四色婷婷基地| 国产一区二区欧美| 欧美最近摘花xxxx摘花| 婷婷色在线视频| 亚洲国产综合人成综合网站| 红桃视频一区二区三区免费| 国产精品伦理久久久久久| 国产精品第3页| 美丽的姑娘在线观看免费动漫| 亚洲综合精品久久| 99久久国产宗和精品1上映| 免费福利视频一区| 97碰在线观看| 无码国产精品一区二区色情男同 | 成人在线黄色| 亚洲国产精品高清久久久| 国产一级做a爰片在线看免费| 国产美女久久久久| 国产手机视频在线观看| 国产一区二区三区黄网站| 日日骚久久av| 伊人免费在线观看| 中文字幕一区二区视频| 99国产精品久久久久久| 国产高清久久| 亚洲一区二区中文| a级毛片免费观看在线| 欧美一区二区三区喷汁尤物| 久久精品视频免费在线观看| 国产伦精品一区二区三区视频青涩 | 麻豆传媒在线完整视频| 91麻豆精品国产91久久久资源速度| www亚洲色图| 毛片av一区二区| 91社在线播放| 一本色道69色精品综合久久| 久久久久国产一区二区三区| 色偷偷在线观看| 色综合天天综合在线视频| 无码 人妻 在线 视频| 日本欧美在线观看| 椎名由奈jux491在线播放 | 亚洲成av人片在线观看香蕉| 国产精品免费av一区二区| 久久综合色一综合色88| 三级在线免费看| 中文字幕一区二区精品区| 国产精成人品localhost| 黑森林国产精品av| 在线一区二区日韩| www.久久久久久| 欧美日韩免费观看中文| 国产视频三区四区| 国产精品影视在线观看| 99精品人妻少妇一区二区 | 日韩一区二区av| 亚洲男人天堂久久| 在线观看视频一区二区欧美日韩| 亚洲区一区二区三| 成人免费视频caoporn| 日韩免费毛片视频| 91精品国产乱码久久久久久久 | 天堂中文在线观看视频| 欧美在线观看视频在线| 久久久久久欧美精品se一二三四| 26uuu精品一区二区| 污污的视频免费观看| 激情久久久久久| 午夜精品一区二区在线观看 | 国产制服丝袜一区| 成人在线免费在线观看| 91成人精品视频| 欧美成人综合一区| 天堂av一区| 国产精品午夜一区二区欲梦| 2019中文字幕在线电影免费 | 美女在线一区二区| 日韩中字在线观看| 99视频精品全部免费在线视频| 久久99蜜桃综合影院免费观看| 日日夜夜亚洲| 日韩av电影在线免费播放| 久操av在线| 日韩一中文字幕| 黄色在线视频观看网站| 精品国产99国产精品| 91女人18毛片水多国产| 日韩欧美一区二区在线| 国产一级免费av| 亚洲天堂福利av| www.日本高清视频| 久久色中文字幕| 中文在线观看免费视频| 国产美女久久久久| jizz大全欧美jizzcom| 香蕉久久夜色精品| 免费拍拍拍网站| 99精品视频在线| 视频一区视频二区视频三区视频四区国产| 粉嫩av一区二区| 91免费观看| 麻豆视频久久| 91中文在线观看| 国产精品.xx视频.xxtv| 国产精品国产三级国产专播精品人| 欧美aa免费在线| 97精品国产91久久久久久| 青草在线视频在线观看| 欧美成人久久久| а√天堂官网中文在线| www.xxxx欧美| 一区二区高清不卡| 中文字幕不卡在线视频极品| 国产有码在线| 一个色综合导航| 九色网友自拍视频手机在线| 国产视频久久久久久久| 精品亚洲综合| 亚洲最新中文字幕| seseavlu视频在线| 中文综合在线观看| 欧美96在线| 欧美成人三级视频网站| 成人短视频在线| 欧美激情第一页xxx| 国产精品69xx| 97色在线观看免费视频| 中文在线资源| 国产精品6699| 69堂精品视频在线播放| 成人免费视频在线观看超级碰| 四虎国产精品免费久久5151| 91网站免费观看| 成人乱码手机视频| 国产精品美女诱惑| 日韩精选在线| 四虎永久在线精品免费一区二区| 久久亚洲国产| 国产黄色激情视频| 香蕉成人久久| 日本黄色的视频| 成人丝袜18视频在线观看| 少妇大叫太粗太大爽一区二区| 亚洲国产精品二十页| 成年人二级毛片| 亚洲国产精品久久久久秋霞影院| 日韩视频在线观看一区| 欧美日韩国产片| 国产 日韩 欧美 精品| 亚洲免费成人av电影| 男人在线资源站| 午夜精品一区二区三区在线视频| 网友自拍亚洲| 91久久精品一区二区别| 性人久久久久| 日本丰满少妇黄大片在线观看| 亚洲久久视频| 久久国产精品国产精品| 成人午夜看片网址| 日本理论中文字幕| 亚洲成av人综合在线观看| 欧美在线视频精品| 精品国产三级电影在线观看| 成人一区二区不卡免费| 色综合久久天天综线观看| 欧美人体一区二区三区| 91国产丝袜在线放| 精品色999| 欧美午夜小视频| 精品一区二区免费在线观看| 50一60岁老妇女毛片| 日本一区二区综合亚洲| 九九免费精品视频| 亚洲成人www| 在线免费av片| 亚洲欧美在线一区| 国产超级va在线视频| 欧美巨乳在线观看| 韩国成人在线| 国产高清一区二区三区| 午夜激情久久| 免费观看日韩毛片| 麻豆亚洲精品| 波多野结衣加勒比| 综合久久一区二区三区| 老熟妇一区二区三区啪啪| 亚洲成人av在线| 久久黄色美女电影| 国产精品久久久久久久久久ktv| 久久久久毛片免费观看| 视频在线一区二区三区| 亚洲国产免费看| 国产精品区在线| 国产亚洲综合av| 日韩成人免费在线视频| 91精品免费观看| аⅴ资源新版在线天堂| 国模视频一区二区三区| 五月亚洲婷婷| 一区二区三区国| 国产亚洲精品bv在线观看| 秘密基地免费观看完整版中文| 国产精品美女www爽爽爽| 成年人视频免费| 亚洲成av人影院在线观看| www视频在线免费观看| 国产精品美女在线| 妖精视频一区二区三区免费观看| 六月丁香激情网| 处破女av一区二区| 黄色录像一级片| 欧美精品18+| www免费网站在线观看| 国产精品www网站| 九一精品国产| 欧美做受777cos| 国产精品99精品久久免费| 极品美妇后花庭翘臀娇吟小说| 精品视频一区二区不卡| 国产高清视频在线观看| 国产91精品久| 国产剧情一区| 黄色一级大片在线观看| 国产欧美日韩另类视频免费观看| 国产又黄又粗又爽| 亚洲国产精品成人一区二区| 天堂av在线| 精品亚洲一区二区三区四区五区高| 国产亚洲成人一区| av无码av天天av天天爽| 欧美主播一区二区三区| 国产粉嫩一区二区三区在线观看 | 懂色av.com| 欧美刺激脚交jootjob| 国产丝袜在线播放| 国产高清不卡av| 久久久精品日韩| 国产熟妇搡bbbb搡bbbb| 午夜电影一区二区| 黄色毛片在线看| 国产精品久久久久久久久免费看| 色婷婷色综合| 91视频福利网| 精品日本高清在线播放| 男人天堂综合| 国产精品电影网| 欧美1区视频| 无码人妻一区二区三区在线| 欧美午夜宅男影院在线观看| 黄色国产在线| eeuss一区二区三区| 最新亚洲一区| 18禁裸乳无遮挡啪啪无码免费| 欧美网站大全在线观看| 欧美天天影院| 久久免费视频1| 日本不卡视频在线观看| 免费网站看av| 日韩精品视频三区| 奇米777日韩| 99re6这里有精品热视频| 99免费精品在线观看| 一级二级三级视频| 久久久亚洲福利精品午夜| 成人一二三区| 人妻 丝袜美腿 中文字幕| 欧美丝袜一区二区三区| 91大神xh98hx在线播放| 91九色在线观看| 热久久国产精品| 麻豆成人在线视频| 色七七影院综合| 欧美一级一片|