青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

<2009年9月>
303112345
6789101112
13141516171819
20212223242526
27282930123
45678910

統計

  • 隨筆 - 21
  • 文章 - 0
  • 評論 - 2
  • 引用 - 0

常用鏈接

留言簿

隨筆分類

隨筆檔案

搜索

  •  

最新評論

閱讀排行榜

評論排行榜

手把手教你玩轉網絡編程模型之完成例程(Completion Routine)篇

手把手教你玩轉網絡編程模型之完成例程(Completion Routine)

                   ----- By PiggyXP(小豬)

 

  

  記得寫這個系列的上一篇文章的時候已經是四年前了,準確的說是四年半以前了,翻開我塵封已久的blog,感覺到上面已經落了厚厚的一層塵土,突然又來了感覺,于是我翻箱倒柜的找出以前的資料,上傳到了我的空間里,而且,順便又為在網絡編程苦海中苦苦尋覓的朋友帶來一份禮物,這次為大家帶來的是重疊IO模型里面的“完成例程”的實現方式及示例代碼。

本文凝聚著筆者心血,如要轉載,請指明原作者及出處,謝謝!不過代碼寫得不好,歡迎改進,而且沒有版權,請隨便散播、使用。^_^

OK, Let’s go !  Have fun!

 

本文配套的示例源碼下載地址(在我的下載空間里)

http://download.csdn.net/user/PiggyXP

 (VC++ 2008編寫的多客戶端MFC代碼,配有非常非常詳盡的注釋,功能只是簡單的顯示一下各個客戶端發來的字符,作為教學代碼,為了使得代碼結構清晰明了,簡化了很多地方,用于產品開發的話還需要做很多改進,有錯誤或者不足的地方,非常歡迎大家不吝指出。)

代碼界面示意圖:

完成例程模型示例

本文假設你已經對重疊I/O的機制已有了解,否則請先參考本系列的前一篇《手把手教你玩轉重疊IO模型》

 

目錄:

1 完成例程的優點

2 完成例程的基本原理

3 關于完成例程的函數介紹

4 完成例程的實現步驟

5 實際應用中應該進一步完善的地方

 

 

一.         完成例程的優點

1.    首先需要指明的是,這里的“完成例程”(Completion Routine)并非是大家所常聽到的 “完成端口”(Completion Port),而是另外一種管理重疊I/O請求的方式,而至于什么是重疊I/O,簡單來講就是Windows系統內部管理I/O的一種方式,核心就是調用的ReadFileWriteFile函數,在制定設備上執行I/O操作,不光是可用于網絡通信,也可以用于其他需要的地方。

Windows系統中,管理重疊I/O可以有三種方式:

(1)  上一篇中提到的基于事件通知的重疊I/O模型

 (2)  本篇中將要講述的基于“完成例程”的重疊I/O模型

 (3)  下一篇中將要講到的“完成端口”模型

雖然都是基于重疊I/O,但是因為前兩種模型都是需要自己來管理任務的分派 ,所以性能上沒有區別,而完成端口是創建完成端口對象使操作系統親自來管理任務的分派,所以完成端口肯定是能獲得最好的性能。

2.    如果你想要使用重疊I/O機制帶來的高性能模型,又懊惱于基于事件通知的重疊模型要收到64個等待事件的限制,還有點畏懼完成端口稍顯復雜的初始化過程,那么“完成例程”無疑是你最好的選擇!^_^ 因為完成例程擺脫了事件通知的限制,可以連入任意數量客戶端而不用另開線程,也就是說只用很簡單的一些代碼就可以利用Windows內部的I/O機制來獲得網絡服務器的高性能,是不是心動了呢?那就一起往下看。。。。。。。。。。

3.    而且個人感覺“完成例程”的方式比重疊I/O更好理解,因為就和我們傳統的“回調函數”是一樣的,也更容易使用一些,推薦!

 

二.         完成例程的基本原理

概括一點說,上一篇拙作中提到的那個基于事件通知的重疊I/O模型,在你投遞了一個請求以后(比如WSARecv),系統在完成以后是用事件來通知你的,而在完成例程中,系統在網絡操作完成以后會自動調用你提供的回調函數,區別僅此而已,是不是很簡單呢?

首先這里統一幾個名詞,包括“重疊操作”、“重疊請求”、“投遞請求”等等,這是為了配合這的重疊I/O才這么講的,說的直白一些,也就是你在代碼中發出的WSARecv()WSASend()等等網絡函數調用。

 上篇文章中偷懶沒畫圖,這次還是畫個流程圖來說明吧,采用完成例程的服務器端,通信流程簡單的來講是這樣的:

 完成例程流程圖

 

從圖中可以看到,服務器端存在一個明顯的異步過程,也就是說我們把客戶端連入的SOCKET與一個重疊結構綁定之后,便可以將通訊過程全權交給系統內部自己去幫我們調度處理了,我們在主線程中就可以去做其他的事情,邊等候系統完成的通知就OK,這也就是完成例程高性能的原因所在。

如果還沒有看明白,我們打個通俗易懂的比方,完成例程的處理過程,也就像我們告訴系統,說“我想要在網絡上接收網絡數據,你去幫我辦一下”(投遞WSARecv操作),“不過我并不知道網絡數據合適到達,總之在接收到網絡數據之后,你直接就調用我給你的這個函數(比如_CompletionProess),把他們保存到內存中或是顯示到界面中等等,全權交給你處理了”,于是乎,系統在接收到網絡數據之后,一方面系統會給我們一個通知,另外同時系統也會自動調用我們事先準備好的回調函數,就不需要我們自己操心了。

看到這里,各位應該已經對完成例程的體系結構有了比價清晰的了解了吧,下面各位喝點咖啡轉轉脖子休息休息,然后就進入到下面的具體實現部分了。

 

一.         完成例程的函數介紹

這個部分將要介紹在完成例程模型中會使用到的關鍵函數,內容比較枯燥,大家要做好心理準備。不過在實際應用以前,很多東西肯定也不會理解得太深刻,可以先泛泛的了解一下,以后再回頭復習這里的知識就可以了。

厄。。。。。。仔細審查了一下代碼,發現其實這里也沒有什么新函數好介紹了,大部分都是使用重疊模型那一章里介紹的一樣的函數,需要查看的朋友請看這里《手把手教你玩轉重疊IO模型》

,這里就不再重復了:

這里只補充一個知識點,就是咱們完成例程方式和前面的事件通知方式最大的不同之處就在于,我們需要提供一個回調函數供系統收到網絡數據后自動調用,回調函數的參數定義應該遵照如下的函數原型:

 

1.  完成例程回調函數原型及傳遞方式

函數應該是這樣定義的,函數名字隨便起,但是參數類型不能錯

 

view plaincopy to clipboardprint?

  1. Void CALLBACK _CompletionRoutineFunc(  
  2.   DWORD dwError, // 標志咱們投遞的重疊操作,比如WSARecv,完成的狀態是什么  
  3.   DWORD cbTransferred, // 指明了在重疊操作期間,實際傳輸的字節量是多大  
  4.   LPWSAOVERLAPPED lpOverlapped, // 參數指明傳遞到最初的IO調用內的一個重疊  結構  
  5.   DWORD dwFlags  // 返回操作結束時可能用的標志(一般沒用));  

      

還有一點需要重點提一下的是,因為我們需要給系統提供一個如上面定義的那樣的回調函數,以便系統在完成了網絡操作后自動調用,這里就需要提一下究竟是如何把這個函數與系統內部綁定的呢?如下所示,在WSARecv函數中是這樣綁定的

view plaincopy to clipboardprint?

1.        int WSARecv(  

2.                    SOCKET s,                      // 當然是投遞這個操作的套接字  

3.                    LPWSABUF lpBuffers,          // 接收緩沖區,與Recv函數不同  

4.        // 這里需要一個由WSABUF結構構成的數組  

5.         DWORD dwBufferCount,        // 數組中WSABUF結構的數量,設置為1即可  

6.           LPDWORD lpNumberOfBytesRecvd,  // 如果接收操作立即完成,這里會返回函數調用  

7.        // 所接收到的字節數  

8.          LPDWORD lpFlags,             // 說來話長了,我們這里設置為即可  

9.          LPWSAOVERLAPPED lpOverlapped,  // “綁定”的重疊結構  

10.       LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine  

11.                                       // 我們的完成例程函數的指針  

12.     );  

其他參數我們可以先不用先細看,只看最后一個,看到了嗎?直接在WSARecv的最后一個參數上,傳遞一下我們回調函數的指針就行了,這里注意一下,咱們這次多次提到的這個“完成例程”,其實就是指的咱們提供的這個回調函數。

 

     

view plaincopy to clipboardprint?

1.    舉個例子:(變量的定義順序和上面的說明的順序是對應的,下同)  

2.    SOCKET s;  

3.    WSABUF DataBuf;           // 定義WSABUF結構的緩沖區  

4.    // 初始化一下DataBuf  

5.    #define DATA_BUFSIZE 4096  

6.    char buffer[DATA_BUFSIZE];  

7.    ZeroMemory(buffer, DATA_BUFSIZE);  

8.    DataBuf.len = DATA_BUFSIZE;  

9.    DataBuf.buf = buffer;  

10.  DWORD dwBufferCount = 1, dwRecvBytes = 0, Flags = 0;  

11.  // 建立需要的重疊結構,每個連入的SOCKET上的每一個重疊操作都得綁定一個  

12.  WSAOVERLAPPED AcceptOverlapped ;// 如果要處理多個操作,這里當然需要一個  

13.  // WSAOVERLAPPED數組  

14.  ZeroMemory(&AcceptOverlapped, sizeof(WSAOVERLAPPED));  

15.    

16.  // 作了這么多工作,終于可以使用WSARecv來把我們的完成例程函數綁定上了  

17.  // 當然,假設我們的_CompletionRoutine函數已經定義好了  

18.  WSARecv(s, &DataBuf, dwBufferCount, &dwRecvBytes,   

19.  &Flags, &AcceptOverlapped, _CompletionRoutine);  

其他的函數我這里就不一一介紹了,因為我們畢竟還有MSDN這么個好幫手,而且在講后面的完成例程和完成端口的時候我還會講到一些 ^_^

四.         完成例程的實現步驟

基礎知識方面需要知道的就是這么多,下面我們配合代碼,來一步步的講解如何親手實現一個完成例程模型(前面幾步的步驟和基于事件通知的重疊I/O方法是一樣的)。

【第一步】創建一個套接字,開始在指定的端口上監聽連接請求

和其他的SOCKET初始化全無二致,直接照搬即可,在此也不多費唇舌了,需要注意的是為了一目了然,我去掉了錯誤處理,平常可不要這樣啊,盡管這里出錯的幾率比較小。

view plaincopy to clipboardprint?

1.    WSADATA wsaData;  

2.    WSAStartup(MAKEWORD(2,2),&wsaData);  

3.      

4.    ListenSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);  //創建TCP套接字  

5.      

6.    SOCKADDR_IN ServerAddr;                           //分配端口及協議族并綁定  

7.    ServerAddr.sin_family=AF_INET;                                  

8.    ServerAddr.sin_addr.S_un.S_addr  =htonl(INADDR_ANY);            

9.    ServerAddr.sin_port=htons(11111);        // 11111端口監聽  

10.                                      // 端口號可以隨意更改,但最好不要少于1024  

11.    

12.  bind(ListenSocket,(LPSOCKADDR)&ServerAddr, sizeof(ServerAddr)); // 綁定套接字  

13.    

14.  listen(ListenSocket, 5);                                   //開始監聽  

【第二步】接受一個入站的連接請求

  一個accept就完了,都是一樣一樣一樣一樣的啊~~~~~~~~~~

 至于AcceptEx的使用,在完成端口中我會講到,這里就先不一次灌輸這么多了,不消化啊^_^

view plaincopy to clipboardprint?

1.    AcceptSocket = accept (ListenSocket, NULL,NULL) ;   

當然,這里是我偷懶,如果想要獲得連入客戶端的信息(記得論壇上也常有人問到),accept的后兩個參數就不要用NULL,而是這樣

view plaincopy to clipboardprint?

1.    SOCKADDR_IN ClientAddr;                   // 定義一個客戶端得地址結構作為參數  

2.    int addr_length=sizeof(ClientAddr);  

3.    AcceptSocket = accept(ListenSocket,(SOCKADDR*)&ClientAddr, &addr_length);  

4.    // 于是乎,我們就可以輕松得知連入客戶端的信息了  

5.    LPCTSTR lpIP =  inet_ntoa(ClientAddr.sin_addr);      // 連入客戶端的 IP  

6.    UINT nPort = ClientAddr.sin_port;                      // 連入客戶端的Port  

【第三步】準備好我們的重疊結構

有新的套接字連入以后,新建立一個WSAOVERLAPPED重疊結構(當然也可以提前建立好),準備綁定到我們的重疊操作上去。這里也可以看到和上一篇中的明顯區別,就是不用再為WSAOVERLAPPED結構綁定一個hEvent了。

view plaincopy to clipboardprint?

  1. // 這里只定義一個,實際上是每一個SOCKET的每一個操作都需要綁定一個重疊結構的,所以在實際使用面對多個客戶端的時候要定義為數組,詳見示例代碼;  
  2. WSAOVERLAPPED AcceptOverlapped   
  3. ZeroMemory(&AcceptOverlapped, sizeof(WSAOVERLAPPED));      // 置零  

    

【第四步】開始在套接字上投遞WSARecv請求,需要將第三步準備的WSAOVERLAPPED結構和我們定義的完成例程函數為參數

各個變量都已經初始化OK以后,我們就可以開始進行具體的Socket通信函數調用了,然后讓系統內部的重疊結構來替我們管理I/O請求,我們只用等待網絡通信完成后調用咱們的回調函數就OK了。

這個步驟的重點就是 綁定一個Overlapped變量和一個完成例程函數

view plaincopy to clipboardprint?

1.   // WSAOVERLAPPED結構指定為一個參數,在套接字上投遞一個異步WSARecv()請求  

2.   // 并提供下面的作為完成例程的_CompletionRoutine回調函數(函數名字)  

3.   if(WSARecv(  

4.       AcceptSocket,  

5.       &DataBuf,  

6.       1,  

7.       &dwRecvBytes,  

8.       &Flags,  

9.       &AcceptOverlapped,  

10.      _CompletionRoutine) == SOCKET_ERROR)  // 注意我們傳入的回調函數指針  

11.      {  

12.          if(WSAGetLastError() != WSA_IO_PENDING)  

13.          {  

14.              ReleaseSocket(nSockIndex);  

15.              continue;  

16.              }  

17.          }  

18.  }  

  

【第五步】 調用WSAWaitForMultipleEvents函數或者SleepEx函數等待重疊操作返回的結果

  我們在前面提到過,投遞完WSARecv操作,并綁定了Overlapped結構和完成例程函數之后,我們基本就是完事大吉了,等了系統自己去完成網絡通信,并在接收到數據的時候,會自動調用我們的完成例程函數。

  而我們在主線程中需要做的事情只有:做別的事情,并且等待系統完成了完成例程調用后的返回結果。

就是說在WSARecv調用發起完畢之后,我們不得不在后面再緊跟上一些等待完成結果的代碼。有兩種辦法可以實現:

1)    和上一篇重疊I/O中講到的一樣,我們可以使用WSAWaitForMultipleEvent來等待重疊操作的事件通知, 方法如下:

view plaincopy to clipboardprint?

1.    // 因為WSAWaitForMultipleEvents() API要求  

2.    // 在一個或多個事件對象上等待但是這個事件數組已經不是和SOCKET相關聯的了  

3.    // 因此不得不創建一個偽事件對象  

4.    WSAEVENT EventArray[1];       

5.    EventArray[0] = WSACreateEvent();                        // 建立一個事件  

6.            ////////////////////////////////////////////////////////////////////////////////  

7.    // 然后就等待重疊請求完成就可以了,注意保存返回值,這個很重要  

8.    DWORD dwIndex = WSAWaitForMultipleEvents(1,EventArray,FALSE,WSA_INFINITE,TRUE);  

這里參數的含義我就不細說了,MSDN上一看就明白,調用這個函數以后,線程就會置于一個警覺的等待狀態,注意 fAlertable 參數一定要設置為 TRUE

2)    可以直接使用SleepEx函數來完成等待,效果都是一樣的。

SleepEx函數調用起來就簡單得多,它的函數原型定義是這樣的

    

view plaincopy to clipboardprint?

  1. DWORD SleepEx(  
  2.              DWORD dwMilliseconds,  // 等待的超時時間,如果設置為INFINITE就會一直等待下去  
  3.              BOOL   bAlertable   // 是否置于警覺狀態,如果為FALSE,則一定要等待超時時間完畢之后才會返回,這里我們是希望重疊操作一完成就能返回,所以同(1)一樣,我們一定要設置為TRUE  
  4.  );  

    調用這個函數的時候,同樣注意用一個DWORD類型變量來保存它的返回值,后面會派上用場。

【第六步】通過等待函數的返回值取得重疊操作的完成結果

這是我們最關心的事情,費了那么大勁投遞的這個重疊操作究竟是個什么結果呢?就是通過上一步中我們調用的等待函數的DWORD類型的返回值,正常情況下,在操作完成之后,應該是返回WAIT_IO_COMPLETION,如果返回的是 WAIT_TIMEOUT,則表示等待設置的超時時間到了,但是重疊操作依舊沒有完成,應該通過循環再繼續等待。如果是其他返回值,那就壞事了,說明網絡通信出現了其他異常,程序就可以報錯退出了……

判斷返回值的代碼大致如下:

view plaincopy to clipboardprint?

  1. ///////////////////////////////////////////////////////////////////////////////////  
  2. // 返回WAIT_IO_COMPLETION表示一個重疊請求完成例程代碼的結束。繼續為更多的完成例程服務  
  3. if(dwIndex == WAIT_IO_COMPLETION)  
  4. {  
  5. TRACE("重疊操作完成...\n");  
  6. }  
  7. else if( dwIndex==WAIT_TIMEOUT )  
  8. {  
  9.      TRACE(“超時了,繼續調用等待函數”);  
  10. }  
  11. else  
  12. {  
  13.     TRACE(“廢了…”);  
  14. }  

 

操作完成了之后,就說明我們上一個操作已經成功了,成功了之后做什么?當然是繼續投遞下一個重疊操作了啊…..繼續上面的循環。

 

【第七步】繼續回到第四步,在套接字上繼續投遞WSARecv請求,重復步驟4-7

 大家可以參考我的代碼,在這里就先不寫了,因為各位都一定比我smart,領悟了關鍵所在以后,稍作思考就可以靈活變通了。

 

【第八步】“享受”接收到的數據

朋友們看到這里一定會問,我忙活了這么久,那客戶端傳來的數據在哪里接收啊?怎么一點都沒有提到呢……

這個問題問得好,我們寫了這么多代碼圖個什么呢?

其實想要讀取客戶端的數據很簡單,因為我們在WSARecv調用的時候,是傳遞了一個WSABUF的變量的,用于保存網絡數據,而在我們寫的完成例程回調函數里面,就可以取到客戶端傳送來的網絡數據了。

因為系統在調用我們完成例程函數的時候,其實網絡操作已經完成了,WSABUF里面已經有我們需要的數據了,只是通過完成例程來進行后期的處理。具體可以參考示例代碼。 DataBuf.buf就是一個char*字符串指針,聽憑你的處理吧,我就不多說了。

 

一.         實際應用中應該完善的地方

實我一直都很想把我以前做的工程中的代碼貼出來給大家分享,但是代碼實在是太繁雜了,僅僅把網絡通信的部分剝離出來,不經過測試的話,肯定還會有其他的很 多問題,反而誤導了初學者,不過我的計劃是在寫下一個“完成端口”部分的時候,直接把項目中的一部分代碼拿出來試試看吧……

總之網絡服務器端程序,在實際應用的時候,關鍵的幾點就是:

1)    要考慮到客戶端很多、通信量很大的時候,如何去處理,如何盡可能的減小開銷,提高效率;

2)    多個線程之間共用一些變量的時候,一定要注意到同步問題;

3)    作為一個網絡程序,出現異常是家常便飯,一定要把代碼寫得盡可能的健壯,要盡量全面的考慮處理各種各樣的錯誤;

4)    盡量不要出現各種字符緩沖區的問題,寫安全的代碼,防止被黑客利用……(這點似乎扯遠了,但是確實是一個很現實的問題)

     其他的問題,還希望各位這方面的網絡專家使勁批評指正,因為代碼是很多年前的了,一定存在著很多的問題。

 

                                                                                                                                           --- Finished at DLUT

                                                                                                                                           --- 2009-02-16

 

 

 

posted on 2009-09-04 15:48 ChinaPanda 閱讀(925) 評論(0)  編輯 收藏 引用

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            99这里有精品| 日韩午夜在线| 久久爱www久久做| 国产日韩欧美在线播放| 先锋影音国产精品| 欧美在线视频日韩| 亚洲高清在线| 这里只有精品视频| 国产一区二区欧美| 欧美成人69av| 国产精品va在线| 久久人人爽人人爽爽久久| 久色成人在线| 亚洲视频一区二区| 久久精品视频免费观看| 亚洲免费观看视频| 性高湖久久久久久久久| 91久久精品一区| 亚洲直播在线一区| 亚洲国产精品日韩| 亚洲淫性视频| 亚洲激情综合| 午夜精品网站| 日韩网站在线观看| 久久国产精品久久久| 一区二区不卡在线视频 午夜欧美不卡在| 亚洲看片一区| 精品999在线观看| 一本色道久久加勒比精品| 激情小说亚洲一区| 亚洲一区二区免费看| 亚洲欧洲精品天堂一级| 午夜精品久久久久久久99樱桃| 亚洲精美视频| 欧美与欧洲交xxxx免费观看| 一本色道精品久久一区二区三区| 久久精品1区| 欧美一级一区| 欧美日韩成人综合| 欧美激情亚洲国产| 国模精品一区二区三区| 亚洲天堂成人在线视频| 亚洲精品国产精品国自产在线| 亚洲一区二区高清| 亚洲一区二区动漫| 欧美日韩免费观看一区三区| 欧美成人免费全部| 激情久久综合| 久久国产精品第一页| 欧美制服丝袜| 国产精品一区二区在线观看网站 | 亚洲韩国日本中文字幕| 欧美一区二区播放| 亚洲欧美一区二区视频| 欧美日韩免费看| 亚洲人体偷拍| 亚洲三级免费观看| 欧美激情亚洲激情| 最近看过的日韩成人| 亚洲国产精品一区二区三区| 久久国产免费| 欧美88av| 91久久精品一区二区三区| 免费国产一区二区| 亚洲黄色片网站| 99精品热视频| 欧美精品一区视频| 99精品热6080yy久久| 亚洲无吗在线| 国产精品一区免费在线观看| 亚洲综合首页| 久久久久国产精品www| 黄页网站一区| 欧美成人黑人xx视频免费观看| 亚洲国产91| 亚洲视频在线看| 国产精品羞羞答答| 久久se精品一区二区| 牛牛国产精品| 一区二区三区四区精品| 欧美亚男人的天堂| 欧美在线free| 亚洲国产精品女人久久久| 亚洲一二三区精品| 国产亚洲二区| 欧美电影免费观看高清| 一区二区日韩欧美| 久久人91精品久久久久久不卡| 亚洲国产精品999| 欧美视频在线免费| 久久不射电影网| 亚洲精品视频免费观看| 久久国产综合精品| 亚洲美女尤物影院| 国产欧美日韩三区| 欧美高清视频| 欧美一区二区三区在线播放| 欧美国产日韩一二三区| 亚洲欧美韩国| 亚洲国产精品久久| 国产麻豆成人精品| 欧美激情精品久久久久久大尺度| 亚洲视频一区| 亚洲激情成人| 久久午夜精品| 亚洲一区视频在线| 亚洲激情一区二区| 国产在线精品一区二区夜色| 欧美日韩一区高清| 欧美777四色影视在线| 亚洲一区中文| 日韩视频免费观看高清完整版| 久久久蜜桃一区二区人| 亚洲一区区二区| 亚洲美女精品成人在线视频| 国内精品久久久久影院薰衣草| 欧美日本韩国在线| 欧美成人免费全部| 久久久久女教师免费一区| 亚洲欧美日韩专区| 中文有码久久| 亚洲精品永久免费精品| 欧美激情成人在线| 蜜桃av一区二区| 久久久精品国产免费观看同学| 亚洲欧美日韩精品久久久| 亚洲精品欧美极品| 91久久精品美女| 亚洲第一中文字幕| 一区二区三区在线免费观看| 国产精品综合久久久| 国产精品亚洲综合天堂夜夜| 国产精品国产三级国产aⅴ无密码| 男人插女人欧美| 免费不卡在线视频| 免费成人美女女| 男女av一区三区二区色多| 欧美.日韩.国产.一区.二区| 久久在精品线影院精品国产| 久久影院亚洲| 欧美1区免费| 欧美精品一线| 国产精品v日韩精品| 国产精品久久久久影院色老大| 欧美日韩喷水| 国产精品裸体一区二区三区| 国产精品一香蕉国产线看观看 | 国产精品久久久久久久久免费樱桃 | 91久久午夜| 99精品国产热久久91蜜凸| 日韩天堂在线视频| 亚洲天天影视| 欧美一区二区三区另类| 久久精品综合一区| 欧美18av| 日韩视频中文字幕| 亚洲免费在线视频| 久久久国产精品一区二区中文 | 国产亚洲一二三区| 亚洲风情在线资源站| 亚洲狼人精品一区二区三区| 中文在线不卡| 久久成人国产精品| 你懂的视频一区二区| 日韩午夜激情电影| 午夜精品一区二区三区在线| 久久精品亚洲一区二区| 欧美二区在线看| 国产精品一区二区三区免费观看 | 一区二区免费在线播放| 欧美一二区视频| 欧美高清视频免费观看| 在线一区二区日韩| 久久久久99精品国产片| 欧美精品日韩www.p站| 国产女优一区| 亚洲精品在线免费观看视频| 午夜视频在线观看一区二区三区 | 欧美大片在线影院| 亚洲一区二区三区777| 麻豆成人综合网| 国产精品综合| av不卡在线| 免费中文字幕日韩欧美| 一本一本久久| 老色批av在线精品| 国产视频一区二区在线观看| 日韩网站在线观看| 蜜臀av性久久久久蜜臀aⅴ| 亚洲视频在线视频| 欧美韩日一区二区三区| 国产一区二区三区观看| 亚洲视频日本| 亚洲人成在线影院| 久久亚洲不卡| 国产午夜精品一区理论片飘花| 亚洲色在线视频| 亚洲第一级黄色片| 久久一日本道色综合久久| 国产精品一区在线观看|