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

woaidongmao

文章均收錄自他人博客,但不喜標題前加-[轉貼],因其丑陋,見諒!~
隨筆 - 1469, 文章 - 0, 評論 - 661, 引用 - 0
數(shù)據(jù)加載中……

為Linux應用構造有限狀態(tài)機方法

  有限自動機(Finite Automata Machine)是計算機科學的重要基石,它在軟件開發(fā)領域內(nèi)通常被稱作有限狀態(tài)機(Finite State Machine),是一種應用非常廣泛的軟件設計模式(Design Pattern)。本文介紹如何構建基于狀態(tài)機的軟件系統(tǒng),以及如何利用Linux下的工具來自動生成實用的狀態(tài)機框架。

  一、什么是狀態(tài)機

  有限狀態(tài)機是一種用來進行對象行為建模的工具,其作用主要是描述對象在它的生命周期內(nèi)所經(jīng)歷的狀態(tài)序列,以及如何響應來自外界的各種事件。在面向對象的軟件系統(tǒng)中,一個對象無論多么簡單或者多么復雜,都必然會經(jīng)歷一個從開始創(chuàng)建到最終消亡的完整過程,這通常被稱為對象的生命周期。一般說來,對象在其生命期內(nèi)是不可能完全孤立的,它必須通過發(fā)送消息來影響其它對象,或者通過接受消息來改變自身。在大多數(shù)情況下,這些消息都只不過是些簡單的、同步的方法調用而已。例如,在銀行客戶管理系統(tǒng)中,客戶類(Customer)的實例在需要的時候,可能會調用帳戶(Account)類中定義的getBalance()方法。在這種簡單的情況下,類Customer并不需要一個有限狀態(tài)機來描述自己的行為,主要原因在于它當前的行為并不依賴于過去的某個狀態(tài)。

  遺憾的是并不是所有情況都會如此簡單,事實上許多實用的軟件系統(tǒng)都必須維護一兩個非常關鍵的對象,它們通常具有非常復雜的狀態(tài)轉換關系,而且需要對來自外部的各種異步事件進行響應。例如,在VoIP電話系統(tǒng)中,電話類(Telephone)的實例必須能夠響應來自對方的隨機呼叫,來自用戶的按鍵事件,以及來自網(wǎng)絡的信令等。在處理這些消息時,Telephone所要采取的行為完全依賴于它當前所處的狀態(tài),因而此時使用狀態(tài)機就將是一個不錯的選擇。

  游戲引擎是有限狀態(tài)機最為成功的應用領域之一,由于設計良好的狀態(tài)機能夠被用來取代部分的人工智能算法,因此游戲中的每個角色或者器件都有可能內(nèi)嵌一個狀態(tài)機。考慮RPG游戲中城門這樣一個簡單的對象,它具有打開(Opened)、關閉(Closed)、上鎖(Locked)、解鎖(Unlocked)四種狀態(tài),如圖1所示。當玩家到達一個處于狀態(tài)Locked的門時,如果此時他已經(jīng)找到了用來開門的鑰匙,那么他就可以利用它將門的當前狀態(tài)轉變?yōu)?span lang="EN-US">Unlocked,進一步還可以通過旋轉門上的把手將其狀態(tài)轉變?yōu)?span lang="EN-US">Opened,從而成功地進入城內(nèi)。

clip_image001

  圖1 控制城門的狀態(tài)機

  在描述有限狀態(tài)機時,狀態(tài)、事件、轉換和動作是經(jīng)常會碰到的幾個基本概念。

  狀態(tài)(State) 指的是對象在其生命周期中的一種狀況,處于某個特定狀態(tài)中的對象必然會滿足某些條件、執(zhí)行某些動作或者是等待某些事件。"

  事件(Event) 指的是在時間和空間上占有一定位置,并且對狀態(tài)機來講是有意義的那些事情。事件通常會引起狀態(tài)的變遷,促使狀態(tài)機從一種狀態(tài)切換到另一種狀態(tài)。

  轉換(Transition) 指的是兩個狀態(tài)之間的一種關系,表明對象將在第一個狀態(tài)中執(zhí)行一定的動作,并將在某個事件發(fā)生同時某個特定條件滿足時進入第二個狀態(tài)。

  動作(Action) 指的是狀態(tài)機中可以執(zhí)行的那些原子操作,所謂原子操作指的是它們在運行的過程中不能被其他消息所中斷,必須一直執(zhí)行下去。

  二、手工編寫狀態(tài)機

與其他常用的設計模式有所不同,程序員想要在自己的軟件系統(tǒng)中加入狀態(tài)機時,必須再額外編寫一部分用于邏輯控制的代碼,如果系統(tǒng)足夠復雜的話,這部分代碼實現(xiàn)和維護起來還是相當困難的。在實現(xiàn)有限狀態(tài)機時,使用switch語句是最簡單也是最直接的一種方式,其基本思路是為狀態(tài)機中的每一種狀態(tài)都設置一個case分支,專門用于對該狀態(tài)進行控制。下面的代碼示范了如何運用switch語句,來實現(xiàn)圖1中所示的狀態(tài)機:  

switch (state)

{

   // 處理狀態(tài)Opened的分支

   case (Opened): {

    // 執(zhí)行動作Open

    open();

    // 檢查是否有CloseDoor事件

    if (closeDoor()) {

     // 當前狀態(tài)轉換為Closed

     changeState(Closed)

    }

    break;

   }

  

   // 處理狀態(tài)Closed的分支

   case (Closed): {

    // 執(zhí)行動作Close

    close();

    // 檢查是否有OpenDoor事件

    if (openDoor()) {

     // 當前狀態(tài)轉換為Opened

     changeState(Opened);

    }

    // 檢查是否有LockDoor事件

    if (lockDoor()) {

     // 當前狀態(tài)轉換為Locked

     changeState(Locked);

    }

    break;

   }

  

   // 處理狀態(tài)Locked的分支

   case (Locked): {

    // 執(zhí)行動作Lock

    lock();

    // 檢查是否有UnlockDoor事件

    if (unlockDoor()) {

     // 當前狀態(tài)轉換為Unlocked

     changeState(Unlocked);

    }

    break;

   }

  

   // 處理狀態(tài)Unlocked的分支

   case (Unlocked): {

    // 執(zhí)行動作Unlock

    unlock();

    // 檢查是否有LockDoor事件

    if (lockDoor()) {

     // 當前狀態(tài)轉換為Locked  

     changeState(Locked)

    }

    // 檢查是否有OpenDoor事件  

    if (openDoor()) {

     // 當前狀態(tài)轉換為Opened

     changeSate(Opened);

    }

    break;

   }

  

}

 

  使用switch語句實現(xiàn)的有限狀態(tài)機的確能夠很好地工作,但代碼的可讀性并不十分理想,主要原因是在實現(xiàn)狀態(tài)之間的轉換時,檢查轉換條件和進行狀態(tài)轉換都是混雜在當前狀態(tài)中來完成的。例如,當城門處于Opened狀態(tài)時,需要在相應的case中調用closeDoor()函數(shù)來檢查是否有必要進行狀態(tài)轉換,如果是的話則還需要調用changeState()函數(shù)將當前狀態(tài)切換到Closed。顯然,如果在每種狀態(tài)下都需要分別檢查多個不同的轉換條件,并且需要根據(jù)檢查結果讓狀態(tài)機切換到不同的狀態(tài),那么這樣的代碼將是枯燥而難懂的。從代碼重構的角度來講,此時更好的做法是引入checkStateChange()performStateChange()兩個函數(shù),專門用來對轉換條件進行檢查,以及激活轉換時所需要執(zhí)行的各種動作。這樣一來,程序結構將變得更加清晰:

  switch (state) {

  

   // 處理狀態(tài)Opened的分支

   case (Opened): {

    // 執(zhí)行動作Open

    open();

    // 檢查是否有激發(fā)狀態(tài)轉換的事件產(chǎn)生

    if (checkStateChange()) {

     // 對狀態(tài)機的狀態(tài)進行轉換

     performStateChange();

    }

    break;

   }

  

   // 處理狀態(tài)Closed的分支

   case (Closed): {

    // 執(zhí)行動作Close

    close();

    // 檢查是否有激發(fā)狀態(tài)轉換的事件產(chǎn)生

    if (checkStateChange()) {

     // 對狀態(tài)機的狀態(tài)進行轉換

     performStateChange();

    }

    break;

   }

  

   // 處理狀態(tài)Locked的分支

   case (Locked): {

    // 執(zhí)行動作Lock

    lock();

    // 檢查是否有激發(fā)狀態(tài)轉換的事件產(chǎn)生

    if (checkStateChange()) {

     // 對狀態(tài)機的狀態(tài)進行轉換

     performStateChange();

    }

    break;

   }

  

   // 處理狀態(tài)Unlocked的分支

   case (Unlocked): {

    // 執(zhí)行動作Lock

    unlock();

    // 檢查是否有激發(fā)狀態(tài)轉換的事件產(chǎn)生

    if (checkStateChange()) {

     // 對狀態(tài)機的狀態(tài)進行轉換

     performStateChange();

    }

    break;

   }

  

}

 

  在很長一段時期內(nèi),使用switch語句一直是實現(xiàn)有限狀態(tài)機的唯一方法,甚至像編譯器這樣復雜的軟件系統(tǒng),大部分也都直接采用這種實現(xiàn)方式。但之后隨著狀態(tài)機應用的逐漸深入,構造出來的狀態(tài)機越來越復雜,這種方法也開始面臨各種嚴峻的考驗,其中最令人頭痛的是如果狀態(tài)機中的狀態(tài)非常多,或者狀態(tài)之間的轉換關系異常復雜,那么簡單地使用switch語句構造出來的狀態(tài)機將是不可維護的。

  三、自動生成狀態(tài)機

  為實用的軟件系統(tǒng)編寫狀態(tài)機并不是一件十分輕松的事情,特別是當狀態(tài)機本身比較復雜的時候尤其如此,許多有過類似經(jīng)歷的程序員往往將其形容為"毫無創(chuàng)意"的過程,因為他們需要將大量的時間與精力傾注在如何管理好狀態(tài)機中的各種狀態(tài)上,而不是程序本身的運行邏輯。作為一種通用的軟件設計模式,各種軟件系統(tǒng)的狀態(tài)機之間肯定會或多或少地存在著一些共性,因此人們開始嘗試開發(fā)一些工具來自動生成有限狀態(tài)機的框架代碼,而在Linux下就有一個挺不錯的選擇──FSMEFinite State Machine Editor)。

clip_image002

  圖2 可視化的FSME

  FSME是一個基于Qt的有限狀態(tài)機工具,它能夠讓用戶通過圖形化的方式來對程序中所需要的狀態(tài)機進行建模,并且還能夠自動生成用C++或者Python實現(xiàn)的狀態(tài)機框架代碼。下面就以圖1中城門的狀態(tài)機為例,來介紹如何利用FSME來自動生成程序中所需要的狀態(tài)機代碼。

  3.1狀態(tài)機建模

  首先運行fsme命令來啟動狀態(tài)機編輯器,然后單擊工具欄上" "New"按鈕來創(chuàng)建一個新的狀態(tài)機。FSME中用于構建狀態(tài)機的基本元素一共有五種:事件(Event)、輸入(Input)、輸出(Output)、狀態(tài)(State)和轉換(Transition),在界面左邊的樹形列表中可以找到其中的四種。

  狀態(tài)建模

  在FSME界面左邊的樹形列表中選擇"States"項,然后按下鍵盤上的Insert鍵來插入一個新的狀態(tài),接著在右下方的"Name"文本框中輸入狀態(tài)的名稱,再在右上方的繪圖區(qū)域單擊該狀態(tài)所要放置的位置,一個新的狀態(tài)就創(chuàng)建好了。用同樣的辦法可以添加狀態(tài)機所需要的所有狀態(tài)。

clip_image003

  圖3 狀態(tài)建模

  事件建模

  在FSME界面左邊的樹形列表中選" "Events"項,然后按下鍵盤上的Insert鍵來添加一個新的事件,接著在右下方的"Name"文本框中輸入事件的名稱,再單擊"Apply"按鈕,一個新的事件就創(chuàng)建好了。用同樣的辦法可以添加狀態(tài)機所需要的所有事件。

clip_image004

  圖4 事件建模

  狀態(tài)轉換是整個建模過程中最重要的一個部分,它用來定義有限狀態(tài)機中的一個狀態(tài)是如何切換到另一個狀態(tài)的。例如,當用來控制城門的狀態(tài)機處于Opened狀態(tài)時,如果此時有Close事件產(chǎn)生,那么狀態(tài)機的當前狀態(tài)將切換到Closed狀態(tài),這樣一個完整的過程在狀態(tài)機模型中可以用closeDoor這樣一個轉換來進行描述。

  要在FSME中添加這樣一個轉換,首先需要在界面左邊的樹形列表中選" "States"下的"Opened"項,然后按下鍵盤上的Insert鍵來添加一個新的轉換,接著在右下角的"Name"文本框中輸入轉換的名字"closeDoor",在"Condition"文本框中輸入"Close"表明觸發(fā)該轉換的條件是事件Close的產(chǎn)生,在"Target"下拉框中選擇"Closed"項表明該轉換發(fā)生后狀態(tài)機將被切換到Closed狀態(tài),最后再單擊"Apply"按鈕,一個新的狀態(tài)轉換關系就定義好了,如圖5所示。用同樣的辦法可以添加狀態(tài)機所需要的所有轉換。

clip_image005

  圖5 轉換建模

  3.2 生成狀態(tài)機框架

  使用FSME不僅能夠進行可視化的狀態(tài)機建模,更重要的是它還可以根據(jù)得到的模型自動生成用C++或者Python實現(xiàn)的狀態(tài)機框架。首先在FSME界面左邊的樹形列表中選擇"Root"項,然后在右下角的"Name"文本框中輸入狀態(tài)機的名字"DoorFSM",再從"Initial State"下拉列表中選擇狀態(tài)"Opened"作為狀態(tài)機的初始化狀態(tài)。

clip_image006

  圖6 設置初始屬性

  在將狀態(tài)機模型保存為door.fsm文件之后,使用下面的命令可以生成包含有狀態(tài)機定義的頭文件:

  [xiaowp@linuxgam" code]$ fsmc door.fsm -d -o DoorFSM.

  進一步還可以生成包含有狀態(tài)機實現(xiàn)的框架代碼:

  [xiaowp@linuxgam code]$ fsmc door.fsm -d -impl DoorFSM.h -o DoorFSM.cpp

  如果想對生成的狀態(tài)機進行驗證,只需要再手工編寫一段用于測試的代碼就可以了:

  /*
   * TestFSM.cpp
   * 測試生成的狀態(tài)機框架
   */
  
  #include "DoorFSM.h"
  
  int main()
  {
   DoorFSM door;
   door.A(DoorFSM::Close);
   door.A(DoorFSM::Lock);
   door.A(DoorFSM::Unlock);
   door.A(DoorFSM::Open);
  }

  有限狀態(tài)機是由事件來進行驅動的,在FSME生成的狀態(tài)機框架代碼中,方法A()可以被用來向狀態(tài)機發(fā)送相應的事件,從而提供狀態(tài)機正常運轉所需要的"動力"。狀態(tài)機負責在其內(nèi)部維護一個事件隊列,所有到達的事件都會先被放到事件隊列中進行等候,從而能夠保證它們將按照到達的先后順序被依次處理。在處理每一個到達的事件時,狀態(tài)機都會根據(jù)自己當前所處的狀態(tài),檢查與該狀態(tài)對應的轉換條件是否已經(jīng)被滿足,如果滿足的話則激活相應的狀態(tài)轉換過程。

  使用下面的命令能夠將生成的狀態(tài)機框架和測試代碼編譯成一個可執(zhí)行文件:

  [xiaowp@linuxgam code]$ g++ DoorFSM.cpp TestFSM.cpp -o fsm

由于之前在用fsmc命令生成狀態(tài)機代碼時使用了-d選項,生成的狀態(tài)機框架中會包含一定的調試信息,包括狀態(tài)機中每次狀態(tài)轉換時的激活事件、轉換前的狀態(tài)、所經(jīng)歷的轉換、轉換后的狀態(tài)等,如下所示:

  [xiaowp@linuxgam code]$ ./fsm
  DoorFSM:event:'Close'
  DoorFSM:state:'Opened'
  DoorFSM:transition:'closeDoor'
  DoorFSM:new state:'Closed'
  DoorFSM:event:'Lock'
  DoorFSM:state:'Closed'
  DoorFSM:transition:'lockDoor'
  DoorFSM:new state:'Locked'
  DoorFSM:event:'Unlock'
  DoorFSM:state:'Locked'
  DoorFSM:transition:'unlockDoor'
  DoorFSM:new state:'Unlocked'
  DoorFSM:event:'Open'
  DoorFSM:state:'Unlocked'
  DoorFSM:transition:'openDoor'
  DoorFSM:new state:'Opened'

  3.3 定制狀態(tài)機

  目前得到的狀態(tài)機已經(jīng)能夠響應來自外部的各種事件,并適當?shù)卣{整自己當前所處的狀態(tài),也就是說已經(jīng)實現(xiàn)了狀態(tài)機引擎的功能,接下來要做的就是根據(jù)應用的具體需求來進行定制,為狀態(tài)機加入與軟件系統(tǒng)本身相關的那些處理邏輯。在FSME中,與具體應用相關的操作稱為輸出(Output),它們實際上就是一些需要用戶給出具體實現(xiàn)的虛函數(shù),自動生成的狀態(tài)機引擎負責在進入或者退出某個狀態(tài)時調用它們。

  仍然以控制城門的那個狀態(tài)機為例,假設我們希望在進入每個狀態(tài)時都添加一部分處理邏輯。首在FSME界面左邊的樹形列表選擇"Outputs"項,然后按下鍵盤上的Insert鍵來添加一個新的輸出,接著在右下方的"Name"文本框中輸入相應的名稱,再單擊"Apply"按鈕,一個新的輸出就創(chuàng)建好了,如圖7所示。用同樣的辦法可以添加狀態(tài)機所需要的所有輸出。

clip_image007

  圖7 添加輸出

  當所有的輸出都定義好之后,接下來就可以為狀態(tài)機中的每個狀態(tài)綁定相應的輸出。首先在FSME界面左側的"States"項中選擇相應的狀態(tài),然后從右下角的"Available"列表框中選擇與該狀態(tài)對應的輸出,再單擊"<"按鈕將其添加到"In"列表中。用同樣的辦法可以為狀態(tài)機中的所有狀態(tài)設置相應的輸出,同一個狀態(tài)可以對應有多個輸出,其中In列表中的輸出會在進入該狀態(tài)時被調用,而Out列表中的輸出則會在退出該狀態(tài)時被調用,輸出調用的順序是與其在In或者Out列表中的順序相一致的。

由于對狀態(tài)機模型進行了修改,我們需要再次生成狀態(tài)機的框架代碼,不過這次不需要加上-d參數(shù):

  [xiaowp@linuxgam" code]$ fsmc door.fsm -o DoorFSM.h
  [xiaowp@linuxgam code]$ fsmc door.fsm -d -impl DoorFSM.h -o DoorFSM.cpp

我們在新的狀態(tài)機模型中添加了enterOpendenterClosedenterLockedenterUnlocked四個輸出,因此生成的類DoorFSM中會包含如下幾個純虛函數(shù)

    virtual void enterOpened() = 0;
    virtual void enterLocked() = 0;
    virtual void enterUnlocked() = 0;
    virtual void enterClosed() = 0;

 

  顯然,此時生成的狀態(tài)機框架不能夠再被直接編譯了,我們必須從類DoorFSM派生出一個子類,并提供對這幾個純虛函數(shù)的具體實現(xiàn):

  /*
   * DoorFSMLogic.h
   * 狀態(tài)機控制邏輯的頭文件
   */
  #include "DoorFSM.h"
  
  class DoorFSMLogic : public DoorFSM
  {
  
   protected:
   virtual void enterOpened();
   virtual void enterLocked();
   virtual void enterUnlocked();
   virtual void enterClosed();
  };

  正如前面所提到過的,這幾個函數(shù)實際上代表的正是應用系統(tǒng)的處理邏輯,作為例子我們只是簡單地輸出一些提示信息:

  /*
   * DoorFSMLogic.cpp
   * 狀態(tài)機控制邏輯的實現(xiàn)文件
   */
  #include "DoorFSMLogic.h"
  #include
  
  void DoorFSMLogic::enterOpened()
  {
    std::cout << "Enter Opened state." << std::endl;
  }
  
  void DoorFSMLogic::enterClosed()
  {
    std::cout << "Enter Closed state." << std::endl;
  }
  
  void DoorFSMLogic::enterLocked()
  {
    std::cout << "Enter Locked state." << std::endl;
  }
  
  void DoorFSMLogic::enterUnlocked()
  {
    std::cout << "Enter Unlocked state." << std::endl;
  }

  同樣,為了對生成的狀態(tài)機進行驗證,我們還需要手工編寫一段測試代碼:

  /*
   * TestFSM.cpp
   * 測試狀態(tài)機邏輯
   */
  #include "DoorFSMLogic.h"
  
  int main()
  {
   DoorFSMLogic door;
   door.A(DoorFSM::Close);
   door.A(DoorFSM::Lock);
   door.A(DoorFSM::Unlock);
   door.A(DoorFSM::Open);
  }

  使用下面的命令能夠將生成的狀態(tài)機框架和測試代碼編譯成一個可執(zhí)行文件:

[xiaowp@linuxgam code]$ g++ DoorFSM.cpp DoorFSMLogic.cpp TestLogic.cpp -o logic

  運行結果如下所示:

  [xiaowp@linuxgam code]$ ./logic
  Enter Closed state.
  Enter Locked state.
  Enter Unlocked state.
  Enter Opened state.

  四、小結

  在面向對象的軟件系統(tǒng)中,有些對象具有非常復雜的生命周期模型,使用有限狀態(tài)機是描述這類對象最好的方法。作為一種軟件設計模式,有限狀態(tài)機的概念雖然不算復雜,實現(xiàn)起來也并不困難,但它的問題是當狀態(tài)機的模型復雜到一定的程度之后,會帶來實現(xiàn)和維護上的困難。Linux下的FSME是一個可視化的有限狀態(tài)機建模工具,而且支持狀態(tài)機框架代碼的自動生成,借助它可以更加輕松地構建基于有限狀態(tài)機的應用系統(tǒng)。

posted on 2008-12-14 18:40 肥仔 閱讀(750) 評論(0)  編輯 收藏 引用 所屬分類: 狀態(tài)機 & 自動機 & 形式語言

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            久久激情五月激情| 在线观看成人网| 午夜精品一区二区三区电影天堂 | 国产精品毛片a∨一区二区三区|国| 你懂的国产精品| 欧美日韩国产色综合一二三四| 欧美日韩福利视频| 国产精品成av人在线视午夜片| 国产精品久久久久久一区二区三区| 国产精品人成在线观看免费| 国产综合第一页| 99re66热这里只有精品3直播| 亚洲性xxxx| 久久九九免费视频| 欧美国产免费| 亚洲网站视频福利| 久久国内精品自在自线400部| 久久久伊人欧美| 欧美国产精品中文字幕| 国产精品成人va在线观看| 国产原创一区二区| 久久久久久久综合日本| 欧美高清视频免费观看| 国产精品男gay被猛男狂揉视频| 狠狠干综合网| 亚洲永久免费| 亚洲国产精品va在线看黑人动漫| 亚洲人成7777| 久久精品国产96久久久香蕉| 欧美色欧美亚洲高清在线视频| 精品成人乱色一区二区| 亚洲午夜电影| 亚洲国产欧美国产综合一区| 欧美一区二区三区免费视| 欧美日韩不卡一区| 亚洲高清视频在线| 久久精品视频va| 亚洲视频一区在线| 欧美日韩成人在线视频| 亚洲国产精品激情在线观看| 久久国产精品久久国产精品| 一区二区欧美日韩| 欧美人在线观看| 亚洲国产精品尤物yw在线观看| 久久精品卡一| 亚洲欧美日韩综合国产aⅴ| 欧美日韩一区三区四区| 日韩一区二区免费看| 亚洲国产精品成人精品| 免费不卡在线观看| 影音先锋中文字幕一区二区| 久久九九99视频| 欧美一进一出视频| 国产日韩精品一区观看| 欧美主播一区二区三区美女 久久精品人| 99精品国产99久久久久久福利| 欧美黄色一级视频| 亚洲另类在线视频| 亚洲人成精品久久久久| 欧美连裤袜在线视频| 亚洲人午夜精品免费| 欧美肥婆bbw| 欧美福利视频| 日韩亚洲欧美高清| 日韩视频在线一区二区三区| 欧美日韩国产区| 亚洲一区二区三区四区五区午夜 | 亚洲国产网站| 91久久在线播放| 欧美视频在线观看一区| 亚洲在线一区二区| 亚洲一区高清| 激情欧美亚洲| 亚洲国产美女| 国产精品观看| 另类亚洲自拍| 欧美精品一区二区三区很污很色的| 99国产精品久久久久久久久久| 日韩亚洲国产欧美| 国产欧美日韩激情| 在线日韩中文| 亚洲精品乱码久久久久久黑人| 欧美日韩亚洲高清| 久久福利资源站| 欧美暴力喷水在线| 亚洲女优在线| 美女爽到呻吟久久久久| 亚洲午夜91| 久久精品观看| 一区二区三区日韩| 久久精品国产综合精品| 亚洲狼人精品一区二区三区| 亚洲一区二区免费视频| 亚洲第一区在线| 中文在线不卡视频| 亚洲电影在线免费观看| 亚洲视频一区二区在线观看 | 国产精品国产成人国产三级| 久久中文久久字幕| 国产精品家教| 亚洲国产欧美在线人成| 国产亚洲综合性久久久影院| 亚洲欧洲日夜超级视频| 国精产品99永久一区一区| 日韩亚洲欧美一区| 亚洲高清不卡av| 欧美亚洲三区| 亚洲欧美色一区| 欧美激情久久久久| 老鸭窝亚洲一区二区三区| 国产精品爱啪在线线免费观看| 欧美r片在线| 合欧美一区二区三区| 亚洲制服欧美中文字幕中文字幕| 日韩一区二区免费看| 久久婷婷av| 久久天天综合| 国产综合视频| 欧美亚洲午夜视频在线观看| 亚洲综合电影| 欧美少妇一区二区| 亚洲乱码国产乱码精品精可以看| 亚洲国产黄色片| 久久久综合网站| 久久深夜福利免费观看| 国产亚洲欧美另类一区二区三区| 亚洲女人天堂av| 欧美一区二区三区在线观看视频 | 久久精品国产免费观看| 国产精品久久午夜夜伦鲁鲁| 日韩亚洲一区在线播放| 一区二区欧美日韩视频| 欧美激情视频网站| 亚洲免费av片| 亚洲一区二区精品| 欧美午夜精品久久久久免费视| av成人免费在线观看| 亚洲欧美日本国产专区一区| 国产精品ⅴa在线观看h| 亚洲天堂黄色| 久久久精品午夜少妇| 国内成人精品一区| 久久阴道视频| 亚洲高清网站| 欧美久久一级| 亚洲视频欧美在线| 欧美一区网站| 狠狠色狠狠色综合系列| 久久午夜激情| 亚洲精品一区二区在线| 亚洲欧美国产精品桃花| 国产九九精品| 久久一区二区三区四区| 亚洲精品乱码久久久久久日本蜜臀| 亚洲一区日韩在线| 国产综合自拍| 欧美日韩国产综合久久| 欧美亚洲一区二区三区| 亚洲国产裸拍裸体视频在线观看乱了中文| 一区二区三区欧美| 国产三级精品三级| 欧美成人国产一区二区| 中文在线资源观看网站视频免费不卡| 欧美亚洲一级| 亚洲国产精品t66y| 欧美日韩一区成人| 欧美一区二区三区久久精品| 欧美高清影院| 欧美亚洲自偷自偷| 亚洲人成免费| 国产午夜精品福利| 欧美日韩理论| 久久伊人精品天天| 亚洲欧美久久| 亚洲老板91色精品久久| 久久躁日日躁aaaaxxxx| 亚洲欧美文学| 一本大道久久a久久精品综合| 韩国av一区二区三区在线观看| 欧美色图一区二区三区| 蜜桃av一区二区三区| 午夜精品视频在线观看| av72成人在线| 亚洲精品久久久久久久久久久| 久久久之久亚州精品露出| 亚洲天堂免费观看| 亚洲三级免费电影| 一色屋精品视频在线观看网站| 欧美性生交xxxxx久久久| 免费不卡在线观看av| 久久av一区二区| 亚洲一区激情| a4yy欧美一区二区三区| 亚洲国产精品一区在线观看不卡| 久久露脸国产精品| 久久精品道一区二区三区| 亚洲一区二区三区影院| 日韩午夜激情av| 91久久极品少妇xxxxⅹ软件| 国产亚洲福利社区一区|