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

C++ Coder

HCP高性能計算架構,實現,編譯器指令優化,算法優化, LLVM CLANG OpenCL CUDA OpenACC C++AMP OpenMP MPI

C++博客 首頁 新隨筆 聯系 聚合 管理
  98 Posts :: 0 Stories :: 0 Comments :: 0 Trackbacks

http://www.pcdog.com/edu/linux/13/11/y237288.html

管道技術是Linux的一種基本的進程間通信技術。在本文中,我們將為讀者介紹管道技術的模型,匿名管道和命名管道技術的定義和區別,以及這兩種管道的創建方法。同時,闡述如何在應用程序和命令行中通過管道進行通信的詳細方法。

    一、管道技術模型 

    管道技術是Linux操作系統中歷來已久的一種進程間通信機制。所有的管道技術,無論是半雙工的匿名管道,還是命名管道,它們都是利用FIFO排隊模型來指揮進程間的通信。對于管道,我們可以形象地把它們當作是連接兩個實體的一個單向連接器。例如,請看下面的命令:
  

ls -1 | wc -l


    該命令首先創建兩個進程,一個對應于ls –1,另一個對應于wc –l。然后,把第一個進程的標準輸出設為第二個進程的標準輸入(如圖1所示)。它的作用是計算當前目錄下的文件數量。

Linux下的管道編程技術(圖一)

點擊查看大圖

 

圖1:管道示意圖 



    如上圖所示,前面的例子實際上就是在兩個命令之間建立了一根管道(有時我們也將之稱為命令的流水線操作)。第一個命令ls執行后產生的輸出作為了第二個命令wc的輸入。這是一個半雙工通信,因為通信是單向的。兩個命令之間的連接的具體工作,是由內核來完成的。下面我們將會看到,除了命令之外,應用程序也可以使用管道進行連接。

二、信號和消息的區別

    我們知道,進程間的信號通信機制在傳遞信息時是以信號為載體的,但管道通信機制的信息載體是消息。那么信號和消息之間的區別在哪里呢? 

    首先,在數據內容方面,信號只是一些預定義的代碼,用于表示系統發生的某一狀況;消息則為一組連續語句或符號,不過量也不會太大。在作用方面,信號擔任進程間少量信息的傳送,一般為內核程序用來通知用戶進程一些異常情況的發生;消息則用于進程間交換彼此的數據。 

    在發送時機方面,信號可以在任何時候發送;信息則不可以在任何時刻發送。在發送者方面,信號不能確定發送者是誰;信息則知道發送者是誰。在發送對象方面,信號是發給某個進程;消息則是發給消息隊列。在處理方式上,信號可以不予理會;消息則是必須處理的。在數據傳輸效率方面,信號不適合進大量的信息傳輸,因為它的效率不高;消息雖然不適合大量的數據傳送,但它的效率比信號強,因此適于中等數量的數據傳送。 

    三、管道和命名管道的區別 

    我們知道,命名管道和管道都可以在進程間傳送消息,但它們也是有區別的。 

    管道技術只能用于連接具有共同祖先的進程,例如父子進程間的通信,它無法實現不同用戶的進程間的信息共享。再者,管道不能常設,當訪問管道的進程終止時,管道也就撤銷。這些限制給它的使用帶來不少限制,但是命名管道卻克服了這些限制。 

    命名管道也稱為FIFO,是一種永久性的機構。FIFO文件也具有文件名、文件長度、訪問許可權等屬性,它也能像其它Linux文件那樣被打開、關閉和刪除,所以任何進程都能找到它。換句話說,即使是不同祖先的進程,也可以利用命名管道進行通信。 

    如果想要全雙工通信,那最好使用Sockets API。下面我們分別介紹這兩種管道,然后詳細說明用來進行管道編程的編程接口和系統級命令。

四、管道編程技術 

    在程序中利用管道進行通信時,根據通信主體大體可以分為兩種情況:一種是具有共同祖先的進程間的通信,比較簡單;另一種是任意進程間通信,相對較為復雜。下面我們先從較為簡單的進程內通信開始介紹。 

    1. 具有共同祖先的進程間通信管道編程 

    為了了解管道編程技術,我們先舉一個例子。在這個例中,我們將在進程中新建一個管道,然后向它寫入一個消息,管道讀取消息后將其發出。代碼如下所示: 

    示例代碼1:管道程序示例 

1: #include <unistd.h> 2: #include <stdio.h> 3: #include <string.h> 4: 5: #define MAX_LINE 80 6: #define PIPE_STDIN 0 7: #define PIPE_STDOUT 1 8: 9: int main() 10: ...{ 11: const char *string=...{"A sample message."}; 12: int ret, myPipe[2]; 13: char buffer[MAX_LINE+1]; 14: 15: /**//* 建立管道 */ 16: ret = pipe( myPipe ); 17: 18: if (ret == 0) ...{ 19: 20: /**//* 將消息寫入管道 */ 21: write( myPipe[PIPE_STDOUT], string, strlen(string) ); 22: 23: /**//* 從管道讀取消息 */ 24: ret = read( myPipe[PIPE_STDIN], buffer, MAX_LINE ); 25: 26: /**//* 利用Null結束字符串 */ 27: buffer[ ret ] = 0; 28: 29: printf("%s\n", buffer); 30: 31: } 32: 33: return 0; 34: }

   
    上面的示例代碼中,我們利用pipe調用新建了一個管道,參見第16行代碼。 我們還建立了一個由兩個元素組成的數組,用來描述我們的管道。我們的管道被定義為兩個單獨的文件描述符,一個用來輸入,一個用來輸出。我們能從管道的一端輸入,然后從另一端讀出。如果調用成功,pipe函數返回值為0。返回后,數組myPipe中存放的是兩個新的文件描述符,其中元素myPipe[1]包含的文件描述符用于管道的輸入,元素myPipe[0] 包含的文件描述符用于管道的輸出。

    在第21行代碼,我們利用write函數把消息寫入管道。站在應用程序的角度,它是在向stdout輸出。現在,該管道存有我們的消息,我們可以利用第24行的read函數來讀它。對于應用程序來說,我們是利用stdin描述符從管道讀取消息的。read函數把從管道讀取的數據存放到buffer變量中。然后在buffer變量的末尾添加一個NULL,這樣就能利用printf函數正確的輸出它了。在本例中的管道可以利用下圖解釋:

Linux下的管道編程技術(圖二)

點擊查看大圖

 

圖2:示例代碼1中半雙工管道的示意圖

    這個例子中,通信是在具有共同祖先的進程間發生的,即父進程和子進程通信。這樣做局限性太大,但我們只是用它來給讀者一個感性的認識。接下來,我們將介紹更為高級的進程間的管道通信。

 2.進程間通信管道編程 

    在利用管道技術進行編程時,處理要用到上面介紹的pipe函數外,還用到另外三個函數,如下所示。

? pipe函數:該函數用于創建一個新的匿名管道。

? dup函數:該函數用于拷貝文件描述符。

? mkfifo函數:該函數用于創建一個命名管道(fifo)。 

    當然,在管道通信過程中還用到其它函數,到時我們會加以介紹。需要注意的是,說到底,管道無非就是一對文件描述符,因此任何能夠操作文件操作符的函數都可以使用管道。這包括但不限于這些函數:select、read、write、 fcntl、freopen,等等。 

    2.1函數pipe 

    函數pipe用來建立一個新的管道,該管道用兩個文件描述符進行描述。函數pipe的原型如下所示:

#include <unistd.h> int pipe( int fds[2] );

    當調用成功時,函數pipe返回值為0,否則返回值為-1。成功返回時,數組fds被填入兩個有效的文件描述符。數組的第一個元素中的文件描述符供應用程序讀取之用,數組的第二個元素中的文件描述符可以用來供應用程序寫入。 

    下面我們考察在一個包含多個進程的應用程序中的管道示例。在該程序中(見示例代碼2),第14行用于創建一個管道,然后進程在第16行分叉,變成一個父進程和一個子進程。在子進程中,我們嘗試從(在第18行建立的)管道的輸入描述符讀取,這時該進程將被掛起,直到管道中有可以讀取的內容為止。 

    讀完后,我們用NULL作為讀取的內容的結束符,這樣的話,讀的這些內容就能使用printf函數正確打印輸出了。父進程先是利用存放在thePipe[1]中的“寫文件標識符”向管道寫入測試字符串,然后就使用wait函數來等待子進程退出。 

    在我們的這個程序中需要加以注意的是,我們的子進程是如何繼承父進程利用pipe函數建立的文件描述符的,以及如何利用該文件描述符進行通信的。函數fork一旦執行,子進程會繼承父進程的功能和管道的文件描述符,但對于內核來說,父進程和子進程是平等的,它們是獨立運行的。也就是說,兩個進程分別具有單獨的內存空間,它們正是通過pipe函數來互通有無的。

示例代碼2:演示兩個進程間的管道模型的代碼 1: #include <stdio.h> 2: #include <unistd.h> 3: #include <string.h> 4: #include <wait.h> 5: 6: #define MAX_LINE 80 7: 8: int main() 9: ...{ 10: int thePipe[2], ret; 11: char buf[MAX_LINE+1]; 12: const char *testbuf=...{"a test string."}; 13: 14: if ( pipe( thePipe ) == 0 ) ...{ 15: 16: if (fork() == 0) ...{ 17: 18: ret = read( thePipe[0], buf, MAX_LINE ); 19: buf[ret] = 0; 20: printf( "Child read %s\n", buf ); 21: 22: } else ...{ 23: 24: ret = write( thePipe[1], testbuf, strlen(testbuf) ); 25: ret = wait( NULL ); 26: 27: } 28: 29: } 30: 31: return 0; 32: }



    需要注意的是,在這個示例程序中我們沒有說明如何關閉管道,因為一旦進程結束,與管道有關的資源將被自動釋放。盡管如此,為了養成一種良好的編程習慣,最好利用close調用來關閉管道的描述符,如下所示: 

ret = pipe( myPipe ); ... close( myPipe[0] ); close( myPipe[1] );


    如果管道的寫入端關閉,但是還有進程嘗試從管道讀取的話,將被返回0,用來指出管道已不可用,并且應當關閉它。如果管道的讀出端關閉,但是還有進程嘗試向管道寫入的話,試圖寫入的進程將收到一個SIGPIPE信號,至于信號的具體處理則要視其信號處理程序而定了。

2.2 dup函數和dup2函數

    dup和dup2也是兩個非常有用的調用,它們的作用都是用來復制一個文件的描述符。它們經常用來重定向進程的stdin、stdout和stderr。這兩個函數的原型如下所示:

#include <unistd.h> int dup( int oldfd ); int dup2( int oldfd, int targetfd )

    利用函數dup,我們可以復制一個描述符。傳給該函數一個既有的描述符,它就會返回一個新的描述符,這個新的描述符是傳給它的描述符的拷貝。這意味著,這兩個描述符共享同一個數據結構。例如,如果我們對一個文件描述符執行lseek操作,得到的第一個文件的位置和第二個是一樣的。下面是用來說明dup函數使用方法的代碼片段:

int fd1, fd2; ... fd2 = dup( fd1 );

    需要注意的是,我們可以在調用fork之前建立一個描述符,這與調用dup建立描述符的效果是一樣的,子進程也同樣會收到一個復制出來的描述符。

    dup2函數跟dup函數相似,但dup2函數允許調用者規定一個有效描述符和目標描述符的id。dup2函數成功返回時,目標描述符(dup2函數的第二個參數)將變成源描述符(dup2函數的第一個參數)的復制品,換句話說,兩個文件描述符現在都指向同一個文件,并且是函數第一個參數指向的文件。下面我們用一段代碼加以說明:

int oldfd; oldfd = open("app_log", (O_RDWR | O_CREATE), 0644 ); dup2( oldfd, 1 ); close( oldfd );

    本例中,我們打開了一個新文件,稱為“app_log”,并收到一個文件描述符,該描述符叫做fd1。我們調用dup2函數,參數為oldfd和1,這會導致用我們新打開的文件描述符替換掉由1代表的文件描述符(即stdout,因為標準輸出文件的id為1)。任何寫到stdout的東西,現在都將改為寫入名為“app_log”的文件中。需要注意的是,dup2函數在復制了oldfd之后,會立即將其關閉,但不會關掉新近打開的文件描述符,因為文件描述符1現在也指向它。 

    下面我們介紹一個更加深入的示例代碼。回憶一下本文前面講的命令行管道,在那里,我們將ls –1命令的標準輸出作為標準輸入連接到wc –l命令。接下來,我們就用一個C程序來加以說明這個過程的實現。代碼如下面的示例代碼3所示。 

    在示例代碼3中,首先在第9行代碼中建立一個管道,然后將應用程序分成兩個進程:一個子進程(第13–16行)和一個父進程(第20–23行)。接下來,在子進程中首先關閉stdout描述符(第13行),然后提供了ls –1命令功能,不過它不是寫到stdout(第13行),而是寫到我們建立的管道的輸入端,這是通過dup函數來完成重定向的。在第14行,使用dup2函數把stdout重定向到管道(pfds[1])。之后,馬上關掉管道的輸入端。然后,使用execlp函數把子進程的映像替換為命令ls –1的進程映像,一旦該命令執行,它的任何輸出都將發給管道的輸入端。 

    現在來研究一下管道的接收端。從代碼中可以看出,管道的接收端是由父進程來擔當的。首先關閉stdin描述符(第20行),因為我們不會從機器的鍵盤等標準設備文件來接收數據的輸入,而是從其它程序的輸出中接收數據。然后,再一次用到dup2函數(第21行),讓stdin變成管道的輸出端,這是通過讓文件描述符0(即常規的stdin)等于pfds[0]來實現的。關閉管道的stdout端(pfds[1]),因為在這里用不到它。最后,使用execlp函數把父進程的映像替換為命令wc -1的進程映像,命令wc -1把管道的內容作為它的輸入(第23行)。

示例代碼3:利用C實現命令的流水線操作的代碼 1: #include <stdio.h> 2: #include <stdlib.h> 3: #include <unistd.h> 4: 5: int main() 6: ...{ 7: int pfds[2]; 8: 9: if ( pipe(pfds) == 0 ) ...{ 10: 11: if ( fork() == 0 ) ...{ 12: 13: close(1); 14: dup2( pfds[1], 1 ); 15: close( pfds[0] ); 16: execlp( "ls", "ls", "-1", NULL ); 17: 18: } else ...{ 19: 20: close(0); 21: dup2( pfds[0], 0 ); 22: close( pfds[1] ); 23: execlp( "wc", "wc", "-l", NULL ); 24: 25: } 26: 27: } 28: 29: return 0; 30: }


     在該程序中,需要格外關注的是,我們的子進程把它的輸出重定向的管道的輸入,然后,父進程將它的輸入重定向到管道的輸出。這在實際的應用程序開發中是非常有用的一種技術。

  2.3 mkfifo函數

    mkfifo函數的作用是在文件系統中創建一個文件,該文件用于提供FIFO功能,即命名管道。前邊講的那些管道都沒有名字,因此它們被稱為匿名管道,或簡稱管道。對文件系統來說,匿名管道是不可見的,它的作用僅限于在父進程和子進程兩個進程間進行通信。而命名管道是一個可見的文件,因此,它可以用于任何兩個進程之間的通信,不管這兩個進程是不是父子進程,也不管這兩個進程之間有沒有關系。Mkfifo函數的原型如下所示:

#include <sys/types.h> #include <sys/stat.h> int mkfifo( const char *pathname, mode_t mode );

     mkfifo函數需要兩個參數,第一個參數(pathname)是將要在文件系統中創建的一個專用文件。第二個參數(mode)用來規定FIFO的讀寫權限。Mkfifo函數如果調用成功的話,返回值為0;如果調用失敗返回值為-1。下面我們以一個實例來說明如何使用mkfifo函數建一個fifo,具體代碼如下所示:

int ret; ... ret = mkfifo( "/tmp/cmd_pipe", S_IFIFO | 0666 ); if (ret == 0) ...{ // 成功建立命名管道 } else ...{ // 創建命名管道失敗 }

    在這個例子中,利用/tmp目錄中的cmd_pipe文件建立了一個命名管道(即fifo)。之后,就可以打開這個文件進行讀寫操作,并以此進行通信了。命名管道一旦打開,就可以利用典型的輸入輸出函數從中讀取內容。舉例來說,下面的代碼段向我們展示了如何通過fgets函數來從管道中讀取內容:

pfp = fopen( "/tmp/cmd_pipe", "r" ); ... ret = fgets( buffer, MAX_LINE, pfp );

    我們還能向管道中寫入內容,下面的代碼段向我們展示了利用fprintf函數向管道寫入的具體方法:

pfp = fopen( "/tmp/cmd_pipe", "w+ ); ... ret = fprintf( pfp, "Here’s a test string!\n" );


    對命名管道來說,除非寫入方主動打開管道的讀取端,否則讀取方是無法打開命名管道的。Open調用執行后,讀取方將被鎖住,直到寫入方出現為止。盡管命名管道有這樣的局限性,但它仍不失為一種有效的進程間通信工具。

    上面介紹的是與管道有關的一些系統調用,下面介紹管道命令相關的系統命令。
五、與管道相關的系統命令

    現在開始,我們來研究與進程間通信密切相關的一些系統命令。首先介紹的是mkfifo命令,它的功能與mkfifo系統調用相似,只不過它是用來在命令行中建立一個命名管道。

    在命令行下建立fifo的專用文件,即命名管道的常用方法有兩個,mkfifo命令便是其中之一。mkfifo命令的一般用法如下所示:

mkfifo [options] name

 

    這里的options一般為-m,即模式,用以指出讀寫權限;name是要創建的管道的名稱,必要時可以加上路徑。如果我們沒有規定權限,該命令會采取默認值0644。這里以一個具體實例來說明如何在/tmp目錄下面建立一個稱為cmd_pipe的命名管道:

 

$ mkfifo /tmp/cmd_pipe

 

    下面用例子說明如何給命名管道指定讀寫權限。這里我們先將前面建立的管道刪掉,然后重新建立管道,并指定管道的權限為0644,當然您也可以指定其他權限:

 

$ rm cmd_pipe $ mkfifo -m 0644 /tmp/cmd_pipe

 

    上面的權限一經建立,就能夠在命令行行下通過此管道進行通信了。比如,可以在一個終端上,利用cat命令來讀取管道:

 

$ cat cmd_pipe

 

    當輸入該命令后,我們的進程就會被掛起,等待寫入程序打開此管道。現在,在另一個終端上利用echo命令向這個命名管道寫入:

 

$ echo Hi > cmd_pipe

 

    這個命令結束后,要讀取該管道的程序(即cat)將被喚醒,然后結束。為醒目起見,這里列出完整的讀取方(也就是讀取管道的程序)輸入的命令和得到的結果:

 

$ cat cmd_pipe Hi $

 

    由此看來,命名管道不僅在C程序中非常有用,而且在腳本中作用也很大。當然,如果組合使用,效果也是很好的。

    除了mkfifo命令外,mknod命令也可以用來創建命名管道,其用法如下所示:

 

$ mknod cmd_pipe p

 


    該命令執行后,將在當前目錄下創建一個命名管道cmd_pipe,p用于指出建立的是命名管道。

    六、小結

    在這篇文章中,我們介紹了管道和命名管道的概念,詳細的說明了應用程序和命令行創建管道的方法,以及通過它們進行通信的I/O機制。然后,討論了如何利用dup和 dup2命令來進行輸入輸出重定向。我們希望本文能夠幫您更好的了解Linux下的管道技術。

 


posted on 2013-01-07 10:05 jackdong 閱讀(2990) 評論(0)  編輯 收藏 引用 所屬分類: Linux_Unix編程
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            欧美视频一区在线| 裸体素人女欧美日韩| 日韩一级黄色大片| 久久在线免费观看视频| 国产精品视频yy9099| 亚洲美女视频在线免费观看| 久久高清福利视频| 宅男精品导航| 欧美理论电影网| 91久久久久| 久久亚洲精选| 久久久久久999| 在线播放中文字幕一区| 久久精品国产77777蜜臀| 亚洲视频综合在线| 国产精品美女久久久久久2018| 99亚洲一区二区| 亚洲国产精品久久久久久女王| 久久国产天堂福利天堂| 国产亚洲综合在线| 久久久精品日韩欧美| 亚洲自拍啪啪| 国产日韩欧美成人| 久久久噜噜噜久久狠狠50岁| 久久久久久9| 亚洲激情女人| 亚洲精品小视频在线观看| 欧美日韩精品久久| 午夜精品影院在线观看| 午夜精品久久久久久久99樱桃| 国产精品香蕉在线观看| 久久狠狠亚洲综合| 久久国产日韩欧美| 亚洲日本va在线观看| 亚洲精品久久在线| 欧美图区在线视频| 亚洲欧洲av一区二区三区久久| 亚洲欧美中文字幕| 樱花yy私人影院亚洲| 欧美激情bt| 国产精品成人一区二区| 欧美在线视频网站| 欧美成人国产| 亚洲欧美乱综合| 久久成人这里只有精品| 亚洲激情中文1区| 宅男66日本亚洲欧美视频| 国产主播在线一区| 91久久久亚洲精品| 国产日韩精品久久| 欧美激情偷拍| 国产精品推荐精品| 欧美国产一区二区三区激情无套| 欧美色欧美亚洲另类七区| 在线免费观看日本一区| 这里只有精品丝袜| 免费一区视频| 亚洲激情av在线| 亚洲日本一区二区三区| 欧美日韩免费区域视频在线观看| 亚洲一区二区三区在线| 久久精品一二三| 在线一区二区三区四区五区| 久久精品一级爱片| 一区二区三区高清视频在线观看| 亚洲欧美bt| 亚洲高清激情| 亚洲欧美在线另类| 亚洲开发第一视频在线播放| 亚洲欧美色婷婷| 999在线观看精品免费不卡网站| 午夜免费久久久久| 中文国产成人精品久久一| 欧美在线网站| 亚洲欧美国产高清| 欧美激情综合五月色丁香小说| 久久精品夜色噜噜亚洲aⅴ| 欧美日韩国产一中文字不卡| 美女尤物久久精品| 国产精自产拍久久久久久| 亚洲欧洲综合另类| 激情亚洲网站| 亚洲免费在线观看视频| 亚洲午夜av电影| 欧美成人午夜免费视在线看片| 久久久久国产精品一区| 国产精品yjizz| 亚洲精品午夜精品| 日韩亚洲国产精品| 欧美高清在线精品一区| 欧美18av| 激情成人综合网| 欧美一区永久视频免费观看| 性亚洲最疯狂xxxx高清| 国产精品久久久久久久久久久久 | 久久精品观看| 国产精品久久久久久久一区探花| 亚洲啪啪91| 亚洲午夜精品国产| 国产精品福利久久久| 亚洲午夜成aⅴ人片| 亚洲午夜精品国产| 国产精品国产自产拍高清av| 亚洲小说欧美另类社区| 午夜久久久久| 国产亚洲欧美aaaa| 亚洲欧美日韩在线高清直播| 久久久精品日韩| 亚洲高清视频中文字幕| 老司机67194精品线观看| 欧美黄色片免费观看| 99国产精品视频免费观看| 欧美色网一区二区| 亚洲一区二区三区成人在线视频精品 | 亚洲国产婷婷香蕉久久久久久99 | 午夜精品福利一区二区蜜股av| 欧美一区二区三区四区视频| 国产一区二区三区最好精华液| 久久另类ts人妖一区二区| 亚洲国产天堂久久综合| 亚洲一卡二卡三卡四卡五卡| 国产欧美日韩91| 久久精品亚洲一区二区| 亚洲第一精品夜夜躁人人躁| 亚洲午夜精品久久久久久浪潮 | 欧美一级淫片aaaaaaa视频| 激情成人av在线| 欧美日韩成人综合在线一区二区| 中文一区在线| 欧美jizz19性欧美| 亚洲一本大道在线| 黄色成人免费观看| 欧美日韩播放| 亚洲免费在线视频| 欧美成人精品在线观看| 亚洲天堂黄色| 极品少妇一区二区三区| 欧美日韩在线视频首页| 久久精品一区中文字幕| 99re66热这里只有精品3直播| 久久精品国产免费| 亚洲人成网站在线播| 国产欧美日韩一级| 欧美大片一区二区| 校园激情久久| 99天天综合性| 欧美aⅴ一区二区三区视频| 国产精品99久久久久久有的能看 | 亚洲在线观看视频| 亚洲国产精品久久久久秋霞不卡 | 这里是久久伊人| 狠狠色综合色区| 国产精品h在线观看| 久久婷婷国产综合国色天香| 亚洲免费视频网站| 日韩视频中文| 亚洲国产精品悠悠久久琪琪 | 亚洲午夜在线观看| 亚洲二区在线观看| 卡一卡二国产精品| 午夜精彩视频在线观看不卡 | 最近中文字幕mv在线一区二区三区四区 | 夜夜嗨av一区二区三区四季av| 一区在线视频| 国产自产精品| 国产欧美精品日韩区二区麻豆天美| 亚洲尤物视频在线| 亚洲国产日韩欧美在线动漫| 久久一区中文字幕| 久久精品视频免费观看| 午夜精品福利视频| 国产精品99久久久久久久久| 日韩亚洲国产欧美| 在线视频一区二区| 99热免费精品在线观看| 日韩视频专区| 一区二区三区日韩精品| 一区二区日韩伦理片| 亚洲日本理论电影| 亚洲激情影视| 亚洲精品之草原avav久久| 亚洲日本理论电影| 亚洲麻豆一区| 一区二区三区视频在线看| 日韩一区二区精品视频| 夜夜嗨av一区二区三区| 亚洲视频福利| 性欧美18~19sex高清播放| 亚洲永久精品大片| 欧美在线999| 久久资源在线| 亚洲国产精品va在线看黑人| 亚洲精品免费观看| 亚洲午夜电影| 久久久综合激的五月天| 欧美成人黑人xx视频免费观看| 欧美成人亚洲成人| 欧美日韩中文字幕精品| 国产精品一区二区男女羞羞无遮挡| 欧美精品乱码久久久久久按摩|