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

教父的告白
一切都是紙老虎
posts - 82,  comments - 7,  trackbacks - 0
作者博客:
http://blog.csdn.net/yahle
大綱:
項目的歷史背景
服務器的設計思路
服務器的技術
服務器的設計
服務器的改進
圖形引擎myhoho及UI庫的設計

客戶端與服務器的集成


網 絡游戲一般采用C\S模式,網絡游戲的設計重點,我認為在于Server端,也就是我們說的服務器。在服務器端的設計,我把服務器按照功能分為2個部分, 一個負責游戲世界的處理,一個服務器服務器與客戶端的通訊。在負責游戲世界的處理的服務器,我又按照功能分為地圖服務器和邏輯服務器。這樣劃分的依據是他 們處理的內容不同進行。當初的設計還考慮到系統的集群功能,可以把游戲的地圖移動處理和游戲的邏輯處理都分別分攤到其它服務器里面去。但是做到最后,發現 這樣的設計也不是太好,主要是因為在處理一些游戲事件的時候需要兩個服務器之間進行協同,這樣勢必要創建一定的網絡游戲消息,在開始制作游戲的時候,因為 需要系統的東西不是很多,所以沒有太注意,到項目的后期,想增加一個功能的時候,就發現在處理船只沉沒的時候,服務器需要傳遞很多同步數據,而且服務器各 自在設置玩家數據的時候,也有很多重復的地方。如果今后還要再加點什么其它功能,那要同步的地方就實在是太多了,所以按照功能把服務器分為2個部分的設計 還是存在缺陷的,如果讓我重新再來,我會選擇單服務器的設計,當然這個服務器還是要和連接服務器進行分離,因為游戲的邏輯處理和與玩家的通訊還是很好分開 的,而且分開的話,也有利于邏輯服務器的設計。







登陸(連接)服務器的設計:



   在網絡游戲里,其中一個很大的難點就是玩家與服務器的通訊,在Windos的服務器架構下,網絡游戲服務器端采用的I/O模型,通常是完成端口。在項目 開始時研究完成端口,感覺很難,根本看不懂,因為它在很多地方與以前寫網絡通訊軟件時用的方法不同。但是當我分析過3個完成端口的程序后,基本了解的它的 使用方法。而且在懂以后,回過頭來看,其它完成端口的概念也不是很復雜,只要能清楚的了解幾個函數的使用方法以及基本的處理框架流程,你就會發現它其實非 常的簡單。



   完成端口的一些需要理解的地方:



1。消息隊列



2。工作線程



3。網絡消息返回結構體







   一般我們在設計服務器端的時候,最關鍵的地方是如何分辯剛剛收到的網絡數據是由那個玩家發送過來的,如果是采用消息事件驅動的話,是可以得到一個 socket的值,然后再用這個值與系統里存在的socket進行比對,這樣就可以得到是那位玩家發送過來的游戲消息。我在還沒有使用完成端口的時候,就 是使用這個方法。這樣的設計有一個缺點就是每次收到數據的時候回浪費很多時間在于確定消息發送者身份上。但是在完成端口的設計里,我們可以采用一個取巧的 方法進行設計。所以,這個問題很輕易的就結局了,而且系統開銷也不是很大,關于完成端口,可以參考一下的文章:



《關于Winsock異步I/O模型中的事件模型》



http://search.csdn.net/Expert/topic/166/166227.xml?temp=.4639093



《手把手教你玩轉SOCKET模型之重疊I/O篇》



http://blog.csdn.net/piggyxp/archive/2004/09/23/114883.aspx



《學習日記]IOCP的學習--初步理解》



http://www.gameres.com/bbs/showthread.asp?threadid=25898



《用完成端口開發大響應規模的Winsock應用程序》



http://www.xiaozhou.net/ReadNews.asp?NewsID=901



《理解I/O Completion Port》



http://dev.gameres.com/Program/Control/IOCP.htm



幾個關鍵函數的說明:



http://msdn.microsoft.com/library/en-us/fileio/fs/postqueuedcompletionstatus.asp?frame=true



http://msdn.microsoft.com/library/en-us/fileio/fs/createiocompletionport.asp?frame=true



http://msdn.microsoft.com/library/en-us/fileio/fs/getqueuedcompletionstatus.asp?frame=true



http://msdn.microsoft.com/library/en-us/winsock/winsock/wsarecv_2.asp?frame=true







如果你能認真的搞清楚上面的東西,我估計你離理解完成端口就只有一步了。剩下的這一步就是自己編碼實現一個下了。有些時候,看得懂了不一定會實際應用,不實實在在的寫一點程序,驗證一下你的想法,是不會真正搞清楚原理的。







不 過除非你想深入的研究網絡技術,否則只要知道怎么用就可以了,剩下的就是尋找一個合適的別人封裝好的類來使用。這樣可以節省你很多的事件,當然拿來的東西 最好有源代碼,這樣如果發生什么問題,你也好確定是在那個地方出錯,要改或者擴充功能都會方便很多。當然,還要注意人家的版權,最好在引用別人代碼的地方 加一些小小的注解,這樣用不了多少時間,而且對你,對原作者都有好處^_^。







不過在 完成端口上我還是沒有成為拿來主義者,還是自己封裝了完成端口的操作,原因找到的源代碼代碼封裝的接口函數我怎么看怎么覺得別扭,所以最后還是自己封裝了 一個完成端口,有興趣的可以去看我的源代碼,里面有很詳細的注解。而且就我看來,要拿我封裝的完成端口類使用起來還是很簡單的。使用的時候,只要繼承我的 CIOCP,然后,根據需要覆蓋3個虛函數(OnAccept,OnRead,OnClose)就可以了,最多是在連接函數里,需要用一個函數去設置一下 完成端口信息。當然,我封裝的類稍微簡單了一些,如果要拿來響應大規模連接,還是存在很多的問題,但是如果只是針對少量連接,還是可以應付的。







對 于客戶端的I/O模型,我就沒有那么用心的去尋找什么好的解決方案,采用了一個最簡單的,最原始的阻塞線程的方法做。原理很簡單:創建一個sockt,把 socket設置為阻塞,連接服務器成功后,啟動一個線程,在線程里面用recv()等待服務器發過來的消息。在我的代碼里,也是把阻塞線程的方法封裝成 一個類,在使用的時候,先繼承TClientSocket,然后覆蓋(重載)里面的OnRead()函數,并在里面寫入一些處理收到數據后的操作代碼。在 用的時候,只要connect成功,系統就會自動啟動一個接收線程,一旦有數據就觸發剛才覆蓋的OnRead函數。這個類我也不是完全直接寫的,在里面使 用了別人的一些代碼,主要是讓每個類都能把線程封裝起來,這樣在創建不同的類的實體的時候,每個類的實體自己都會有一個單獨的數據接收線程。



當 然除了阻塞線程的方法,比較常用的還有就是用消息事件的方法收取數據了。我剛開始的時候,也是采用這個方法(以前用過^_^),但是后來發現不太好封裝, 最后采用阻塞線程的方法,這樣做還有一個好處可以讓我的代碼看起來更加舒服一些。不過就我分析《航海世紀》客戶端采用的是消息事件的I/O模型。其它的網 絡游戲就不太清楚了,我想也應該是采用消息事件方式的吧。。



   我記得在gameres上看到過某人寫的一篇關于完成端口的筆記,他在篇末結束的時候,提出一個思考題:我們在學習完成端口的時候,都知道它是用于server端的操作,而且很多文章也是這樣寫的,但是不知道有沒有考慮過,用完成端口做客戶端來使用?



   其實這個問題很好回答,答案是OK。拿IOCP做客戶端也是可行的,就以封裝的IOCP為例,只要在繼承原來的CIOCP類的基礎上,再寫一個Connect(char * ip, int port)的函數,就可以實現客戶端的要求了。
  1. bool CIOCPClient::Connect(char *ip, int port)  
  2. {  
  3.         //  連接服務器  
  4.   
  5.     if (!bInit)  
  6.   
  7.         if (!Init())  
  8.   
  9.             return false;  
  10.   
  11.     //  初始化連接socket  
  12.     SOCKET m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);  
  13.   
  14.     if (m_socket == SOCKET_ERROR)  
  15.         return false;  
  16.   
  17.     // 填寫服務器地址信息  
  18.   
  19.     sockaddr_in ClientAddr;  
  20.   
  21.     ClientAddr.sin_family = AF_INET;  
  22.   
  23.     ClientAddr.sin_port = htons(port);      
  24.   
  25.     ClientAddr.sin_addr.s_addr = inet_addr(ip);  
  26.     // 綁定監聽端口  
  27.     bind(m_socket, (SOCKADDR *)&ClientAddr, sizeof(ClientAddr));  
  28.   
  29.     if (connect(m_socket, (SOCKADDR *)&ClientAddr, sizeof(ClientAddr)) == SOCKET_ERROR)  
  30.   
  31.         return false;  
  32.     this->m_workThread = true;  
  33.   
  34.   
  35.   
  36.     g_hwThread = CreateThread(NULL, 0, WorkThread, (LPVOID)this, 0, &m_wthreadID);  //  創建工作線程,用來處理完成端口消息的  
  37.     this->SetIoCompletionPort(m_socket, NULL);  //  設置完成端口監聽的socket  
  38.     return true;  
  39.   
  40. }  

前面一段是用來連接服務器,所有的客戶端程序都是要這樣做的,當連接成功后,m_socket就是我們想要的用于與服務器 端通訊的socket,然后,我們啟動工作線程,并使用SetIoCompletionPort來設置完成端口監聽的socket。只要在原來的基礎上增 加一個函數,就可以把用于服務器的ICOP變成用于客戶端的IOCP。



   在收到網絡數據以后,下一步就是根據需要,把收到的網絡數據包轉變為游戲消息數據包。在轉換之前,首先是要從收到的網絡數據里面提取出有效的消息。這里 為什么說是要提取有效部分?其主要原因是,我們創建的游戲消息數據,在進行網絡傳輸的時候,不是以消息的長度來傳的,而是根據系統在接收到發送數據請求的 時候,根據實際情況來發送的。例如我這里有一條很長的游戲消息,有3k,但是系統一次只能發送1k的數據,所以,我們的游戲消息,只能把我們的游戲消息分 為3個包,分3次發送,這樣在我們接收消息的時候,就會觸發3次OnRead,而這3次OnRead收到的數據都不是一次完整的游戲消息。所以,我們在收 到網絡數據后,要先和上一次收到的網絡數據進行合并,然后再在里面提取出有效的游戲消息,并在提取后,把已經提取的部分刪除。我在這里把這一步操作封裝到 一個類里CBuftoMsg。這里順便說明一下:一條游戲消息的網絡數據包是以0x00EEEE(16進制)為結束標記(《航海世紀》的做法)。
  1. struct TMessage  
  2.   
  3. {  
  4.   
  5.     char * p;       //  消息頭所在的位置  
  6.   
  7.   
  8.   
  9.     long len;       //  整個消息的長度  
  10.   
  11.   
  12.   
  13. };  
  14.   
  15.   
  16.   
  17.   
  18.    
  19.   
  20.   
  21. class CBuftoMsg  
  22.   
  23.   
  24.   
  25. {  
  26.   
  27.   
  28.   
  29. protected:  
  30.   
  31.   
  32.   
  33.     char msgbuf[BUF_LEN];     
  34.   
  35.   
  36.   
  37.     char * buf_end;  
  38.   
  39.   
  40.   
  41.     char * buf_begin;  
  42.   
  43.   
  44.   
  45.     int buf_len;  
  46.   
  47.   
  48.   
  49. public:  
  50.   
  51.   
  52.   
  53.     CBuftoMsg(void);  
  54.   
  55.   
  56.   
  57.     TMessage getMessage(void);  
  58.   
  59.   
  60.   
  61.     void cleanup_buf(void);  
  62.   
  63.   
  64.   
  65.     bool AddMsgBuf(const char *, int);  
  66.   
  67.   
  68.   
  69.     int tag;  
  70.   
  71.   
  72.   
  73. };  
  74.   
  75.   
  76.   
  77.   
  78.    
  79.   
  80.   
  81. CBuftoMsg::CBuftoMsg(void)  
  82.   
  83.   
  84.   
  85. {  
  86.   
  87.   
  88.   
  89.     buf_begin = msgbuf;  
  90.   
  91.   
  92.   
  93.     buf_end = msgbuf;  
  94.   
  95.   
  96.   
  97.     buf_len = 0;  
  98.   
  99.   
  100.   
  101. }  
  102.   
  103.   
  104.   
  105.   
  106.    
  107.   
  108.   
  109. TMessage CBuftoMsg::getMessage()  
  110.   
  111.   
  112.   
  113. {  
  114.   
  115.   
  116.   
  117.     char * p    = buf_begin;  
  118.   
  119.   
  120.   
  121.     TMessage result;  
  122.   
  123.   
  124.   
  125.     result.len  = 0;  
  126.   
  127.   
  128.   
  129.     result.p    = NULL;  
  130.   
  131.   
  132.   
  133.     while(p <= buf_begin + buf_len - 2)  
  134.   
  135.   
  136.   
  137.     {  
  138.   
  139.   
  140.   
  141.         if ( *p == 0x00)  
  142.   
  143.   
  144.   
  145.         {  
  146.   
  147.   
  148.   
  149.             const static char ce = 0xEE;  
  150.   
  151.   
  152.   
  153.             if (*(p + 1) == ce)  
  154.   
  155.   
  156.   
  157.                 if(*(p + 2) == ce)  
  158.   
  159.   
  160.   
  161.                 {  
  162.   
  163.   
  164.   
  165.                     //  每條消息都是以 00 EE EE 為結束標志  
  166.   
  167.   
  168.   
  169.                     result.p    = buf_begin;  
  170.   
  171.   
  172.   
  173.                     result.len  = p - buf_begin + 3;  
  174.   
  175.   
  176.   
  177.                     buf_begin   =  p + 3;  
  178.   
  179.   
  180.   
  181.                     buf_end     = buf_begin + buf_len;  
  182.   
  183.   
  184.   
  185.                     buf_len -= result.len;  
  186.   
  187.   
  188.   
  189.                     break;  
  190.   
  191.   
  192.   
  193.                 }  
  194.   
  195.   
  196.   
  197.         }  
  198.   
  199.   
  200.   
  201.         p++;  
  202.   
  203.   
  204.   
  205.     }  
  206.   
  207.   
  208.   
  209.     return result;  
  210.   
  211.   
  212.   
  213. }  
  214.   
  215.   
  216.   
  217.   
  218.    
  219.   
  220.   
  221. void CBuftoMsg::cleanup_buf()  
  222.   
  223.   
  224.   
  225. {  
  226.   
  227.   
  228.   
  229.     if (buf_len < BUF_LEN)  
  230.   
  231.   
  232.   
  233.     {  
  234.   
  235.   
  236.   
  237.         if (buf_len == 0)  
  238.   
  239.   
  240.   
  241.         {  
  242.   
  243.   
  244.   
  245.             buf_begin   = msgbuf;  
  246.   
  247.   
  248.   
  249.             buf_end     = msgbuf;  
  250.   
  251.   
  252.   
  253.         }  
  254.   
  255.   
  256.   
  257.         else  
  258.   
  259.   
  260.   
  261.         {  
  262.   
  263.   
  264.   
  265.             memmove(msgbuf, buf_end - buf_len, buf_len);  
  266.   
  267.   
  268.   
  269.             buf_begin = msgbuf;  
  270.   
  271.   
  272.   
  273.             buf_end = buf_end - buf_len;  
  274.   
  275.         }  
  276.   
  277.   
  278.     }  
  279.   
  280.     else  
  281.   
  282.     {  
  283.   
  284.         //  加入緩沖區的數據過多,要拋棄原來的內容  
  285.   
  286.         buf_begin   = msgbuf;  
  287.   
  288.         buf_end     = msgbuf;  
  289.   
  290.         buf_len     = 0;  
  291.   
  292.     }  
  293.   
  294. }  
  295.   
  296. bool CBuftoMsg::AddMsgBuf(const char * buf, int len)  
  297. {  
  298.   
  299.     if (len < 1)  
  300.   
  301.         return false;  
  302.   
  303.     bool result = true;  
  304.   
  305.     buf_len += len;  
  306.   
  307.     if (buf_len >= BUF_LEN)     //  如果緩沖區裝滿了則直接把原來的緩沖區清空再重新復制數據  
  308.     {  
  309.         this->cleanup_buf();      
  310.         result = false;  
  311.   
  312.     }  
  313.   
  314.     memcpy(buf_begin, buf, len);  
  315.   
  316.     return result;  
  317.   
  318. }  


我在這里把 CBuftoMsg 的代碼貼出來,主要是因為,我在寫本文的時候,發現一個驚天動地的bug,有興趣的讀者可以自己去找一下。不過一開始寫代碼的時候,還不是這樣的,當初的 代碼bug比這個還要多,問題還要嚴重,嚴重到經常讓服務器程序莫名其妙的崩潰,而且這個問題,一直到5月份,系統在進行集成測試的時候才發現并解決(還 沒有徹底解決,至少目前我還發現了bug,),以前一直都沒有怎么注意到這個問題,而且我們還把因為這個bug造成的問題,歸結到線程的互斥上去^_^!







我的登陸服務器,除了基本的處理網絡數據包以外,還負責玩家系統的登陸驗證,這部分東西不是很復雜,在我的程序里,只是簡單的從ini文件里讀取玩家的信息而已,有興趣的自己去看我的代碼(不過這部分遠還沒有真正的完善,存在很多問題)。







除 了登陸驗證以外,在登陸程序還負責進行消息轉發,就是把客戶端的消息分別發送到不同的服務器。如果當初設計的是一個邏輯服務器,這個功能就可以簡單很多, 只要發送到一個服務器里就可以了。現在的要發到2個服務器,所以還需要對收到的游戲消息進行分類。為了方便,我對原來定義消息的ID進行了分類,所以,在 GameMessageID.h文件里定義的游戲消息對應的ID編號不是順序編排的。不過也因為這樣,在現在看來,這樣的設計,有一些不太好。在整個系統 里,存在有4個主體,他們之間互相發送,就用了12組的數據,為了方便計算,我把一個變量的范圍分為16個不同的區域,這樣每個區域只有16個值可以用 (我這里是用char類型256/16=16)。在加上用另外一個變量表示邏輯上上的分類(目前按照功能分了12組,有登陸、貿易、銀行、船廠等)這樣對 于貿易這個類型的游戲消息,從客戶端發送到邏輯服務器上,只能有16中可能性,如果要發送更多消息,可能要增加另外一個邏輯分類:貿易2^_^!當初這樣 的設計只是想簡化一下系統的處理過程,不過卻造成了系統的擴充困難,要解決也不是沒有辦法,把類型分類的變量由char類型,改為int類型,這樣對一個 變量分區,在范圍上會款很多,而且不會造成邏輯分類上的困擾,但是,這樣存在一個弊端就是就是每條網絡消息數據包的長度增加了一點點。不要小看這一個字節 的變量,現在設計的一條游戲消息頭的長度是10個字節,如果把char改為int,無形中就增加了3個字節,在和原來的比較,這樣每條消息在消息頭部分, 就多出23%,也就是我們100M的網絡現在只能利用77%而已。



   ^_^呵呵看出什么問題沒有?



   沒有,那我告訴你,有一個概念被偷換了,消息頭的數據不等于整條游戲的消息數據,所以,消息頭部分雖然多出了23%,但是整條游戲消息并不會增加這么 多,最多增加17%,最少應該不會操作5%。平均起來,應該在10%左右(游戲消息里,很多消息的實際部分可能就一個int變量而已)。不過,就算是 10%,也占用了帶寬。



   ^_^呵呵還看出什么問題沒有?



   ^_^先去讀一下我的代碼,再回頭看看,上面的論述還有什么問題。



   實際上,每條游戲消息由:消息頭、消息實體、結束標記組成,其中固定的是消息頭和結束標記,所以,實際上一條實際上游戲消息的數據包,最多比原來的多15%,平均起來,應該是8%~10%的增量而異。



   好了,不在這個計算細節上扣太多精力了。要解決這個問題,要么是增加網絡數據的發送量,要么,就是調整游戲結構,例如,把兩個功能服務器合并為一個服務 器,這樣服務器的對象實體就由原來的4個分為3個,兩兩間的通訊,就由原來的12路縮減為6路,只要分8個區域就ok了。這樣每個邏輯分類就有32條游戲 消息可以使用。當然,如果進一步合并服務器,把服務器端都合并到一個程序,那就不用分類了^_^!

   在登陸服務器目錄下,還有一組mynet.h/mynet.cpp的文件,是我當初為服務器端設計的函數,封裝的是消息事件網絡響應模型。只不過封裝得 不是怎么好,被拋棄不用了,有興趣的可以去看看,反正我是不推薦看的。只不過是在這里說明一下整個工程目錄的結構而已。
posted on 2009-09-14 13:26 暗夜教父 閱讀(388) 評論(0)  編輯 收藏 引用 所屬分類: Game Development

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

常用鏈接

留言簿(2)

隨筆分類

隨筆檔案

文章分類

文章檔案

搜索

  •  

最新評論

閱讀排行榜

評論排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            亚洲国产精品va在看黑人| 日韩视频亚洲视频| 久久久精品国产免大香伊| 亚洲国产日韩欧美| 国产精品久久久一区麻豆最新章节| 午夜精品久久久久久久蜜桃app| 亚洲午夜在线观看视频在线| 欧美高清在线| 欧美亚洲日本一区| 宅男噜噜噜66一区二区 | 国产精品日日摸夜夜摸av| 久久国产视频网| 午夜日韩在线| 中文网丁香综合网| 久久一区视频| 欧美在线不卡| 欧美高清在线一区二区| 亚洲美女毛片| 亚洲一区二三| 亚洲欧美欧美一区二区三区| 亚洲男人的天堂在线观看| 一区电影在线观看| 一本大道久久a久久精二百| 亚洲精品国产欧美| 亚洲国产国产亚洲一二三| 久久人人爽人人爽爽久久| 午夜精品999| 久久久久久九九九九| 亚洲高清在线观看一区| 亚洲欧洲日本专区| 亚洲精品裸体| 国产日韩精品一区二区| 91久久久亚洲精品| 亚洲天堂男人| 欧美一区91| 久久久999| 免费日韩视频| 欧美午夜视频在线观看| 国产精品自在线| 久久综合色天天久久综合图片| 亚洲欧洲精品一区二区| 亚洲精品久久久久久久久| 亚洲天堂av图片| 亚洲影视中文字幕| 欧美日韩一二三四五区| 国产一区清纯| 亚洲一区二区精品视频| 欧美成人首页| 亚洲午夜精品久久| 欧美电影免费观看高清| 欧美一区二粉嫩精品国产一线天| 亚洲第一中文字幕| 久久人人97超碰国产公开结果| 欧美日韩综合视频| 一二三区精品| 一区二区三区免费观看| 欧美巨乳在线观看| 一本久久综合亚洲鲁鲁五月天| 亚洲国产精品专区久久| 老司机精品久久| 亚洲一区区二区| 亚洲天天影视| 国产婷婷一区二区| 亚洲国产专区| 国产精品久久久久久福利一牛影视 | 久久综合导航| a4yy欧美一区二区三区| 宅男精品视频| 亚洲欧美中文字幕| 中文久久精品| 在线电影国产精品| 亚洲精品系列| 欧美在线影院| 亚洲激情六月丁香| 亚洲一区二区三区四区五区黄| 亚洲私人黄色宅男| 午夜伦欧美伦电影理论片| 亚洲人人精品| 欧美日韩mp4| 亚洲网站啪啪| 久色成人在线| 亚洲精品一区二区三| 国产精品久久久亚洲一区 | 日韩视频免费在线| 亚洲婷婷综合久久一本伊一区| 亚洲第一综合天堂另类专| 亚洲欧美久久久| 久久精品一本久久99精品| 国产性天天综合网| 久久精品视频导航| 欧美激情亚洲自拍| 中文久久乱码一区二区| 国产精品va在线播放| 午夜精品久久久久久| 欧美韩日视频| 亚洲在线中文字幕| 激情久久久久久| 国产精品一卡二| 亚洲欧美视频一区| 在线观看成人小视频| 99国产精品视频免费观看一公开| 国产精品专区h在线观看| 亚洲激情av| 欧美日本视频在线| 91久久极品少妇xxxxⅹ软件| 国产日韩专区| av成人免费| 久久久久久久久岛国免费| 香蕉乱码成人久久天堂爱免费| 伊人精品久久久久7777| 欧美手机在线| 久久综合色播五月| 亚洲伦理在线免费看| 午夜精品亚洲一区二区三区嫩草| 在线日韩视频| 国产一级一区二区| 国产精品毛片高清在线完整版| 亚洲美女尤物影院| 免费av成人在线| 亚洲视频狠狠| 亚洲一区二区视频在线| 99精品视频免费观看视频| 影音先锋一区| 尤妮丝一区二区裸体视频| 国产精品va| 国产三区精品| 亚洲福利在线视频| 欧美日韩国产精品自在自线| 农村妇女精品| 久久琪琪电影院| 欧美成人免费一级人片100| 欧美大胆成人| 欧美成人三级在线| 老**午夜毛片一区二区三区| 女仆av观看一区| 欧美网站在线| 狠狠色狠狠色综合日日91app| 国产日韩精品视频一区| 欧美日韩情趣电影| 欧美午夜精品久久久久久人妖| 欧美日韩一级视频| 国产深夜精品福利| 欧美中文在线字幕| 欧美成人有码| 亚洲欧洲日产国产综合网| 日韩一区二区福利| 美女精品在线| 米奇777超碰欧美日韩亚洲| 久久精品日产第一区二区| 亚洲国产第一| 欧美在线观看视频一区二区| 欧美日韩国产高清视频| 国产欧美精品日韩精品| 精东粉嫩av免费一区二区三区| 艳女tv在线观看国产一区| 欧美大片免费观看在线观看网站推荐 | 午夜视频在线观看一区| 亚洲国产一区二区三区高清| 欧美日韩一区二区三区视频| 国产综合自拍| 欧美一区二区在线播放| 亚洲免费在线视频一区 二区| 欧美视频在线不卡| 亚洲成人资源| 久久久久久久久蜜桃| 亚洲欧美日韩在线观看a三区| 国产精品扒开腿做爽爽爽软件| 久久久久久一区二区| a91a精品视频在线观看| 欧美精品一区二区三区很污很色的 | 国产女人精品视频| 亚洲在线观看| 久久精品国产精品| 一区二区91| 欧美国产日韩在线| 久久躁狠狠躁夜夜爽| 精品999在线播放| 欧美一区二区精美| 亚洲一区二区三区国产| 欧美日韩免费一区| 日韩视频一区二区三区在线播放| 99国产麻豆精品| 在线观看精品视频| 久久精品国产第一区二区三区最新章节 | 久久精品二区| 亚洲免费av电影| 欧美午夜免费| 亚洲第一久久影院| 狠狠爱www人成狠狠爱综合网| 亚洲欧美99| 亚洲乱码久久| 性视频1819p久久| 这里只有精品视频在线| 久久精品免费看| 亚洲少妇在线| 欧美激情中文字幕在线| 欧美成人国产一区二区| 亚洲第一黄网| 久久日韩精品| 鲁大师成人一区二区三区|