亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 操作系統 > 正文

網絡IPC:套接字之數據傳輸

2024-06-28 13:27:50
字體:
來源:轉載
供稿:網友
網絡ipC:套接字之數據傳輸

既然將套接字端點表示為文件描述符,那么只要建立連接,就可以使用read和write來通過套接字通信。通過在connect函數里設置對方地址,數據報套接字也可以“連接”。在套接字描述符上采用read和write是非常有意義的,因為可以傳遞套接字描述符到那些原先設計為處理本地文件的函數。而且可以安排傳遞套接字描述符到執行程序的子進程,該子進程并不了解套接字。

盡管可以通過read和write交換數據,但這就是這兩個函數所能做的一切。如果想指定選項、從多個客戶端接收數據包或者發送帶外數據,需要采用6個傳遞數據的套接字函數中的一個。

三個函數用來發送數據,三個用來接收數據。首先,考察用于發送數據的函數。

最簡單的是send,它和write很像,但是可以指定標志來改變處理傳輸數據的方式。

#include <sys/socket.h>ssize_t send(int sockfd, const void *buf, size_t nbytes, int flags);返回值:若成功則返回發送的字節數,若出錯則返回-1

類似write,使用send時套接字必須已經連接。參數buf和nbytes與write中的含義一致。

然而,與write不同的是,send支持第四個參數flags。其中3個標志是Single UNIX Specification規定的,但是其他標志通常實現也支持。表16-7總結了這些標志。

表16-7 send套接字調用標志

未命名

如果send成功返回,并不必然表示連接另一端的進程接收數據。所保證的僅是當send成功返回時,數據已經無錯誤地發送到網絡上。

對于支持為報文設限的協議,如果單個報文超過協議所支持的最大尺寸,send失敗并將errno設置為EMSGSIZE;對于字節流協議,send會阻塞直到整個數據被傳輸。

函數sendto和send很類似。區別在于sendto允許在無連接的套接字上指定一個目標地址。

#include <sys/socket.h>ssize_t sendto(int sockfd, const void *buf, size_t nbytes, int flags,               const struct sockaddr *destaddr, socklen_t destlen);返回值:若成功則返回發送的字節數,若出錯則返回-1

對于面向連接的套接字,目標地址是忽略的,因為目標地址蘊含在連接中。對于無連接的套接字,不能使用send,除非在調用connect時預先設定了目標地址,或者采用sendto來提供另外一種發送報文方式。

可以使用不止一個的選擇來通過套接字發送數據。可以調用帶有msghdr結構的sendmsg來指定多重緩沖區傳輸數據,這和writev很相像(http://www.CUOXin.com/nufangrensheng/p/3559304.html)。

#include <sys/socket.h>ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);返回值:若成功則返回發送的字節數,出錯則返回-1

POSIX.1定義了msghdr結構,它至少應該有如下成員:

struct msghdr {    void            *msg_name;         /* optional address */    socklen_t        msg_namelen;      /* address size in bytes */    struct iovec    *msg_iov;          /* array of I/O buffers */    int              msg_iovlen;       /* number of elements in array */    void            *msg_control;      /* ancillary data */    socklen_t        msg_controllen;   /* number of ancillary bytes */    int              msg_flags;        /* flags for received message */    ...};

iovec結構可參考http://www.CUOXin.com/nufangrensheng/p/3559304.html。

下面是用于接收數據的函數。

函數recv和read很像,但是允許指定選項來控制如何接收數據。

#include <sys/socket.h>ssize_t recv(int sockfd, void *buf, size_t nbytes, int flags);返回值:以字節計數的消息長度,若無可用消息或對方已經按序結束則返回0,出錯則返回-1

表16-8總結了flags標志。其中只有三個標志是Single UNIX Specification規定的。

表16-8 recv套接字調用標志

未命名

當指定MSG_PEEK標志時,可以查看下一個要讀的數據但不會真正取走。當再次調用read或recv函數時會返回剛才查看的數據。

對于SOCK_STREAM套接字,接收的數據可以比請求少。標志MSG_WAITALL阻止這種行為,除非所需數據全部收到,recv才會返回。對于SOCK_DGRAM和SOCK_SEQPACKET套接字,MSG_WAITALL標志沒有改變什么行為,因為這些基于報文的套接字類型一次讀取就返回整個報文。

如果發送者已經調用shutdown(http://www.CUOXin.com/nufangrensheng/p/3564695.html)來結束傳輸,或者網絡協議支持默認的順序關閉并且發送端已經關閉,那么當所有數據接收完畢后,recv返回0。

如果有興趣定位發送者,可以使用recvfrom來得到數據發送者的源地址。

#include <sys/socket.h>ssize_t recvfrom(int sockfd, void *restrict buf, size_t len, int flags,                 struct sockaddr *restrict addr,                 socklen_t *restrict addrlen);返回值:以字節計數的消息長度,若無可用消息或對方已經按序結束則返回0,若出錯則返回-1

如果addr非空,它將包含數據發送者的套接字端點地址。當調用recvfrom時,需要設置addrlen參數指向一個包含addr所指的套接字緩沖區字節大小的整數。返回時,該整數設為該地址的實際大小。

因為可以獲得發送者的實際地址,recvfrom通常用于無連接套接字。否則recvfrom等同于recv。

為了將接收到的數據送入多個緩沖區(類似于readv(http://www.CUOXin.com/nufangrensheng/p/3559304.html)),或者想接收輔助數據,可以使用recvmsg

#include <sys/socket.h>ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);返回值:以字節計數的消息長度,若無可用消息或對方已經按序結束則返回0,若出錯則返回-1

結構msghdr(在sendmsg中見過)被recvmsg用于指定接收數據的輸入緩沖區??梢栽O置參數flags來改變recvmsg的默認行為。返回時,msghdr結構中的msg_flags字段被設為所接收數據的各種特征(進入recvmsg時msg_flags被忽略)。從recvmsg中返回的各種可能值總結在表16-9中。

表16-9 從recvmsg中返回的msg_flags標志

未命名

實例:面向連接的客戶端

程序清單16-4顯示了一個客戶端命令,該命令用于與服務器通信以獲得系統命令uptime的輸出。該服務成為“remote uptime”(簡稱為“ruptime”)。

程序清單16-4 用于獲取服務器uptime的客戶端命令

#include "apue.h"#include <netdb.h>#include <errno.h>#include <sys/socket.h>#define MAXADDRLEN    256#define    BUFLEN        128    extern int connect_retry(int, const struct sockaddr *, socklen_t);void PRint_uptime(int sockfd){    int    n;    char     buf[BUFLEN];        while(( n = recv(sockfd, buf, BUFLEN, 0)) > 0)        write(STDOUT_FILENO, buf, n);    if(n < 0)        err_sys("recv error");}int main(int argc, char *argv[]){    struct addrinfo *ailist, *aip;    struct addrinfo hint;    int        sockfd, err;    if(argc != 2)        err_quit("usage: ruptime hostname");    hint.ai_flags = 0;    hint.ai_family = 0;    hint.ai_socktype = SOCK_STREAM;    hint.ai_protocol = 0;    hint.ai_addrlen = 0;    hint.ai_canonname = NULL;    hint.ai_addr = NULL;    hint.ai_next = NULL;    if((err = getaddrinfo(argv[1], "ruptime", &hint, &ailist)) != 0)        err_quit("getaddrinfo error: %s", gai_strerror(err));    for(aip = ailist; aip != NULL; aip = aip->ai_next)    {        if((sockfd = socket(aip->ai_family, SOCK_STREAM, 0)) < 0)            err = errno;        if(connect_retry(sockfd, aip->ai_addr, aip->ai_addrlen) < 0)        {            err = errno;        }        else        {            print_uptime(sockfd);            exit(0);        }    }    fprintf(stderr, "can't connect to %s: %s/n", argv[1], strerror(err));    exit(1);}

其中,connect_retry函數見:http://www.CUOXin.com/nufangrensheng/p/3565858.html中的程序清單16-2

這個程序連接服務器,讀取服務器發送過來的字符串并將其打印到標準輸出。既然使用SOCK_STREAM套接字,就不能保證在一次recv調用中會讀取整個字符串,所以需要重復調用直到返回0。

如果服務器支持多重網絡接口或多重網絡協議,函數getaddrinfo會返回不止一個候選地址。輪流嘗試每個地址,當找到一個允許連接到服務的地址時便可停止。

編譯上面的程序成功后,執行時出現錯誤:getaddrinfo error:Servname not supported for ai_socktype,后來經查詢在http://blog.163.com/yjie_life/blog/static/16319833720110311528528/找到了解決辦法。其原因是我們在getaddrinfo第二個參數傳入的服務名“ruptime”還沒有分配端口號,我們可以手動為其添加端口號,只需在/etc/services文件中添加一行:ruptime 8888/tcp 其中8888是分配的端口號,需要大于1024且不與其他服務的端口號重復就行,后面的tcp是協議。

實例:面向連接的服務器

程序清單16-5顯示服務器程序,用來提供uptime命令到程序清單16-4的客戶端程序的輸出

程序清單16-5 提供系統uptime的服務器程序

#include "apue.h"#include <netdb.h>#include <errno.h>#include <syslog.h>#include <sys/socket.h>#define BUFLEN    128#define QLEN    10#ifndef HOST_NAME_MAX#define HOST_NAME_MAX    256#endifextern int initserver(int, struct sockaddr *, socklen_t, int);voidserve(int sockfd){    int      clfd;    FILE    *fp;    char     buf[BUFLEN];    for(;;)    {        clfd = accept(sockfd, NULL, NULL);        if(clfd < 0)        {            syslog(LOG_ERR, "ruptimed: accept error: %s", strerror(errno));            exit(1);        }        if((fp = popen("/usr/bin/uptime", "r")) == NULL)        {            sprintf(buf, "error: %s/n", strerror(errno));            send(clfd, buf, strlen(buf), 0);        }        else        {            while(fgets(buf, BUFLEN, fp) != NULL)                send(clfd, buf, strlen(buf), 0);            pclose(fp);        }        close(clfd);    }}intmain(int argc, char *argv[]){    struct addrinfo *ailist, *aip;    struct addrinfo hint;    int        sockfd, err, n;    char        *host;            if(argc != 1)        err_quit("usage: ruptimed");#ifdef _SC_HOST_NAME_MAX    n = sysconf(_SC_HOST_NAME_MAX);    if(n < 0)    /* best guess */#endif        n = HOST_NAME_MAX;    host = malloc(n);    if(host == NULL)        err_sys("malloc error");    if(gethostname(host, n) < 0)        err_sys("gethostname error");    daemonize("ruptimed");    hint.ai_flags = AI_CANONNAME;    hint.ai_family = 0;    hint.ai_socktype = SOCK_STREAM;    hint.ai_protocol = 0;    hint.ai_addrlen = 0;    hint.ai_canonname = NULL;    hint.ai_addr = NULL;    hint.ai_next = NULL;    if((err = getaddrinfo(host, "ruptime", &hint, &ailist)) != 0)    {        syslog(LOG_ERR, "ruptimed: getaddrinfo error: %s", gai_strerror(err));        exit(1);    }    for(aip = ailist; aip != NULL; aip = aip->ai_next)    {        if((sockfd = initserver(SOCK_STREAM, aip->ai_addr, aip->ai_addrlen, QLEN)) >= 0)        {            serve(sockfd);            exit(0);        }    }    exit(1);}

其中,

initserver函數見:http://www.CUOXin.com/nufangrensheng/p/3565858.html中的程序清單16-3

daemonize函數見:http://www.CUOXin.com/nufangrensheng/p/3544104.html中的程序清單13-1

為了找到地址,服務器程序需要獲得其運行時的主機名字。一些系統不定義_SC_HOST_NAME_MAX常量,因此這種情況下使用HOST_NAME_MAX。如果系統不定義HOST_NAME_MAX就自己定義。POSXI.1規定該值的最小值為255字節,不包括終結符,因此定義HOST_NAME_MAX為256以包括終結符。

通過調用gethostname,服務器程序獲得主機名字。并查看遠程uptime服務(ruptime)地址??赡軙卸鄠€地址返回,但簡單地選擇第一個來建立被動套接字端點,在這個端點等待到來的連接請求。

實例:另一個面向連接的服務器

前面說過采用文件描述符來訪問套接字是非常有意義的,因為允許程序對聯網環境的網絡訪問一無所知。程序清單16-6中顯示的服務器程序版本顯示了這一點。為了代替從uptime命令中讀取輸出并發送到客戶端,服務器安排uptime命令的標準輸出和標準出錯替換為連接到客戶端的套接字端點。

程序清單16-6 用于顯示命令直接寫到套接字的服務器程序

#include "apue.h"#include <netdb.h>#include <errno.h>#include <syslog.h>#include <fcntl.h>#include <sys/socket.h>#include <sys/wait.h>#define QLEN    10#ifndef HOST_NAME_MAX#define HOST_NAME_MAX 256#endifextern int initserver(int, struct sockaddr *, socklen_t, int);voidserve(int sockfd){    int      clfd, status;    pid_t    pid;        for(;;)    {        clfd = accept(sockfd, NULL, NULL);        if(clfd < 0)        {            syslog(LOG_ERR, "ruptimed: accept error: %s",                strerror(errno));            exit(1);        }        if((pid = fork()) < 0)        {            syslog(LOG_ERR, "ruptimed: fork error: %s",                 strerror(errno));            exit(1);        }        else if(pid == 0)    /* child */        {            /*            * The parent called daemonize, so             * STDIN_FILENO, STDOUT_FILENO, and STDERR_FILENO            * are already open to /dev/null. Thus, the call to            * close doesn't need to be protected by checks that            * clfd isn't already equal to one of these values.            */            if(dup2(clfd, STDOUT_FILENO) != STDOUT_FILENO ||                dup2(clfd, STDERR_FILENO) != STDERR_FILENO)            {                syslog(LOG_ERR, "ruptimed: unexpected error");                exit(1);            }            close(clfd);            execl("/usr/bin/uptime", "uptime", (char *)0);            syslog(LOG_ERR, "ruptimed: unexpected return from exec:                 %s", strerror(errno));        }        else    /* parent */        {            close(clfd);            waitpid(pid, &status, 0);        }        }}intmain(int argc, char *argv[]){    struct addrinfo *ailist, *aip;    struct addrinfo  hint;    int              sockfd, err, n;    char            *host;    if(argc != 1)        err_quit("usage: ruptimed");#ifdef _SC_HOST_NAME_MAX    n = sysconf(_SC_HOST_NAME_MAX);    if(n < 0)    /* best guess */#endif        n = HOST_NAME_MAX;    host = malloc(n);    if(host == NULL)        err_sys("malloc error");    if(gethostname(host, n) < 0)        err_sys("gethostname error");    daemonize("ruptimed");    hint.ai_flags = AI_CANONNAME;    hint.ai_family = 0;    hint.ai_socktype = SOCK_STREAM;    hint.ai_protocol = 0;    hint.ai_addrlen = 0;    hint.ai_canonname = NULL;    hint.ai_addr = NULL;    hint.ai_next = NULL;    if((err = getaddrinfo(host, "ruptime", &hint, &ailist)) != 0)    {        syslog(LOG_ERR, "ruptimed: getaddrinfo error: %s",             gai_strerror(err));        exit(1);    }    for(aip = ailist; aip != NULL; aip = aip->ai_next)    {        if((sockfd = initserver(SOCK_STREAM, aip->ai_addr,             aip->ai_addrlen, QLEN)) >= 0)        {            serve(sockfd);            exit(0);        }    }    exit(1);}

以前的方式是采用popen來運行uptime命令,并從連接到命令標準輸出的管道讀取輸出,現在采用fork來創建一個子進程,并使用dup2使子進程的STDIN_FILENO的副本打開到/dev/null、STDOUT_FILENO和STDERR_FILENO打開到套接字端點。當執行uptime時,命令將結果寫到標準輸出,該標準輸出連到套接字,所以數據被送到ruptime客戶端命令。

父進程可以安全地關閉連接到客戶端的文件描述符,因為子進程仍舊打開著。父進程等待子進程處理完畢,所以子進程不會變成僵死進程。既然運行uptime花費時間不會太長,父進程在接受下一個連接請求之前,可以等待子進程退出。不過,這種策略不適合子進程運行時間比較長的情況。

前面的例子采用面向連接的套接字。但如何選擇合適的套接字類型?何時采用面向連接的套接字,何時采用無連接的套接字呢?答案取決于要做的工作以及對錯誤的容忍程度。

對于無連接的套接字,數據包的到來可能已經沒有次序,因此當所有的數據不能放在一個包里時,在應用程序里必須關心包的次序。包的最大尺寸是通信協議的特性。并且對于無連接套接字,包可能丟失。如果應用程序不能容忍這種丟失,必須使用面向連接的套接字。

容忍包丟失意味著兩個選擇。如果想和對方可靠通信,必須對數據報編號,如果發現包丟失,則要求對方重新傳輸。既然包可能因延遲而疑似丟失,我們要求重傳,但該包卻又出現,與重傳過來的包重復。因此必須識別重復包,如果出現重復包,則將其丟棄。

另外一個選擇是通過讓用戶再次嘗試命令來處理錯誤。對于簡單的應用程序,這就足夠;但對于復雜的應用程序,這種處理方式通常不是可行的選擇,一般在這種情況下使用面向連接的套接字更為可取。

面向連接的套接字的缺陷在于需要更多的時間和工作來建立一個連接,并且每個連接需要從操作系統中消耗更多的資源。

實例:無連接的客戶端

程序清單16-7中的程序是采用數據報套接字接口的uptime客戶端命令版本。

程序清單16-7 采用數據報服務的客戶端命令

#include "apue.h"#include <netdb.h>#include <errno.h>#include <sys/socket.h>#define BUFLEN    128#define TIMEOUT    20void sigalrm(int signo){}void print_uptime(int sockfd, struct addrinfo *aip){    int    n;    char    buf[BUFLEN];        buf[0] = 0;    if(sendto(sockfd, buf, 1, 0, aip->ai_addr, aip->ai_addrlen) < 0)        err_sys("sendto error");    alarm(TIMEOUT);    if((n = recvfrom(sockfd, buf, BUFLEN, 0, NULL, NULL)) < 0)    {        if(errno != EINTR)            alarm(0);        err_sys("recv error");    }    alarm(0);    write(STDOUT_FILENO, buf, 0);}int main(int argc, char *argv[]){    struct addrinfo        *ailist, *aip;    struct addrinfo         hint;    int                     sockfd, err;    struct sigaction        sa;        if(argc != 2)        err_quit("usage: ruptime hostname");    sa.sa_handler = sigalrm;    sa.sa_flags = 0;    sigemptyset(&sa.sa_mask);    if(sigaction(SIGALRM, &sa, NULL) < 0)        err_sys("sigaction error");    hint.ai_flags = 0;    hint.ai_family = 0;    hint.ai_socktype = SOCK_DGRAM;    hint.ai_protocol = 0;    hint.ai_addrlen = 0;    hint.ai_canonname = NULL;    hint.ai_addr = NULL;    hint.ai_next = NULL;    if((err = getaddrinfo(argv[1], "ruptime", &hint, &ailist)) != 0)        err_quit("getaddrinfo error: %s", gai_strerror(err));    for(aip = ailist; aip != NULL; aip = aip->ai_next)    {        if((sockfd = socket(aip->ai_family, SOCK_DGRAM, 0)) < 0)        {            err = errno;        }        else        {            print_uptime(sockfd, aip);            exit(0);        }    }    fprintf(stderr, "can't contact %s: %s/n", argv[1], strerror(err));    exit(1);}

除了為SIGALRM增加了一個信號處理程序以外,基于數據報的客戶端main函數和面向連接的客戶端中的類似。使用alarm函數來避免調用recvfrom時無限期阻塞。

對于面向連接的協議,需要在交換數據前連接服務器。對于服務器來說,到來的連接請求已經足夠判斷出所需提供給客戶端的服務。但是對于基于數據報的協議,需要有一種方法來通知服務器需要它提供服務。本例中,只是簡單地給服務器發送1字節的消息。服務器接收后從包中得到地址,并使用這個地址來發送響應消息。如果服務器提供多個服務,可以使用這個請求消息來指示所需要的服務,但既然服務器只做一件事情,1字節消息的內容是無關緊要的。

如果服務器不在運行狀態,客戶端調用recvfrom便會無限期阻塞。對于面向連接的例子,如果服務器不運行,connect調用會失敗。為了避免無限期阻塞,調用recvfrom之前設置警告時鐘。

實例:無連接服務器

程序清單16-8中的程序是數據報版本的uptime服務器程序。

程序清單16-8 基于數據報提供系統uptime的服務器程序

#include "apue.h"#include <netdb.h>#include <errno.h>#include <syslog.h>#include <sys/socket.h>#define BUFLEN        128#define    MAXADDRLEN    256#ifndef    HOST_NAME_MAX#define HOST_NAME_MAX    256#endifextern int initserver(int, struct sockaddr *, socklen_t, int);voidserve(int sockfd){    int          n;    socklen_t    alen;    FILE        *fp;        char         buf[BUFLEN];    char         abuf[MAXADDRLEN];    for(;;)    {        alen = MAXADDRLEN;        if((n = recvfrom(sockfd, buf, BUFLEN, 0,            (struct sockaddr *)abuf, &alen)) < 0)        {            syslog(LOG_ERR, "ruptimed: recvfrom error: %s",                 strerror(errno));            exit(1);        }        if((fp = popen("/usr/bin/uptime", "r")) == NULL)        {            sprintf(buf, "error: %s/n", strerror(errno));            sendto(sockfd, buf, strlen(buf), 0,                (struct sockaddr *)abuf, alen);        }        else        {            if(fgets(buf, BUFLEN, fp) != NULL)                sendto(sockfd, buf, strlen(buf), 0,                    (struct sockaddr *)abuf, alen);            pclose(fp);        }    }    }intmain(int argc, char *argv[]){    struct addrinfo *ailist, *aip;    struct addrinfo  hint;    int              sockfd, err, n;    char            *host;        if(argc != 1)    {        err_quit("usage: ruptimed");            }#ifdef _SC_HOST_NAME_MAX    n = sysconf(_SC_HOST_NAME_MAX);    if(n < 0)    /* best guess */#endif        n = HOST_NAME_MAX;    host = malloc(n);    if(host == NULL)        err_sys("malloc error");    if(gethostname(host, n) < 0)        err_sys("gethostname error");    daemonize("ruptimed");    hint.ai_flags = AI_CANONNAME;    hint.ai_family = 0;    hint.ai_socktype = SOCK_DGRAM;    hint.ai_protocol = 0;    hint.ai_addrlen = 0;    hint.ai_canonname = NULL;    hint.ai_addr = NULL;    hint.ai_next = NULL;    if((err = getaddrinfo(host, "ruptime", &hint, &ailist)) != 0)    {        syslog(LOG_ERR, "ruptimed: getaddrinfo error: %s",            gai_strerror(err));        exit(1);    }    for(aip = ailist; aip != NULL; aip = aip->ai_next)    {        if((sockfd = initserver(SOCK_DGRAM, aip->ai_addr,             aip->ai_addrlen, 0)) >= 0)        {            serve(sockfd);            exit(0);        }    }    exit(1);}

服務器在recvfrom中阻塞等待服務請求。當一個請求到達時,保存請求者地址并使用popen來運行uptime命令。采用sendto函數將輸出發送到客戶端,其目標地址就設為剛才的請求者地址。

本篇博文內容摘自《UNIX環境高級編程》(第2版),僅作個人學習記錄所用。關于本書可參考:http://www.apuebook.com/


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美精品九九久久| 久久久久久久久久久网站| 国产脚交av在线一区二区| 亚洲精品自拍偷拍| 精品国产成人av| 国产精品久久久久不卡| 国产精品视频久久| 欧美香蕉大胸在线视频观看| 欧美激情视频在线免费观看 欧美视频免费一| 精品视频www| 久久综合电影一区| 久久精品一区中文字幕| 欧美另类精品xxxx孕妇| 国产精品久久不能| 国产丝袜精品第一页| 另类少妇人与禽zozz0性伦| 欧美激情视频免费观看| 日韩av影视在线| 热久久免费国产视频| 久久久影视精品| 国产色婷婷国产综合在线理论片a| 国产一区二区三区在线观看网站| 精品国产欧美一区二区三区成人| 亚洲国产精品系列| 色天天综合狠狠色| 欧美成人午夜激情| 欧美激情喷水视频| 国产精品高清在线观看| 日本不卡高字幕在线2019| 91成人国产在线观看| 国产精品一区二区三区成人| 欧美激情啊啊啊| 国产精品久久国产精品99gif| 成人在线小视频| 国产亚洲视频在线观看| 国产精品美腿一区在线看| 久久精品国产综合| 日韩成人av网| 国产视频精品免费播放| 日韩国产欧美精品在线| 国产精品国产三级国产专播精品人| 久久久免费在线观看| 国产成人亚洲综合91| 青青青国产精品一区二区| 色樱桃影院亚洲精品影院| 91精品国产99久久久久久| 欧美理论电影在线播放| 精品国产区一区二区三区在线观看| 久久这里有精品视频| 日韩暖暖在线视频| 不卡av日日日| 欧美日本啪啪无遮挡网站| 国产免费亚洲高清| 国模精品系列视频| 国产欧美精品在线| 亚洲在线视频福利| xxxxxxxxx欧美| 国产日韩欧美视频在线| 日本中文字幕久久看| 91av免费观看91av精品在线| 国产黑人绿帽在线第一区| 亚洲国产高清福利视频| 日韩av综合网| 亚洲级视频在线观看免费1级| 国产综合香蕉五月婷在线| 亚洲成色www8888| 国产日韩欧美在线观看| 日本一区二区不卡| 最近2019中文免费高清视频观看www99| 国产午夜精品一区理论片飘花| 国产精品成人在线| 国产午夜精品久久久| 欧美日韩国产va另类| 国产成人在线一区二区| 久久久国产精品免费| 色综合五月天导航| 亚洲视频在线免费看| 久久91超碰青草是什么| 51精品国产黑色丝袜高跟鞋| 一区二区成人av| 欧美日韩aaaa| 久久亚洲成人精品| 欧美日韩国产综合新一区| 亚洲天堂第一页| 日韩一区二区精品视频| 亚洲自拍小视频| 国产成人小视频在线观看| 日韩亚洲在线观看| 7777免费精品视频| 欧美性猛交xxxx免费看久久久| 亚洲国产精品电影| 国产中文字幕91| 九九九热精品免费视频观看网站| 一本色道久久综合狠狠躁篇的优点| 欧美亚洲日本黄色| 国产啪精品视频| 国产欧美精品xxxx另类| 国产精品高潮呻吟久久av黑人| 欧美日韩午夜视频在线观看| 国产精品视频区1| 亚洲3p在线观看| 色樱桃影院亚洲精品影院| 欧美孕妇与黑人孕交| 黑人巨大精品欧美一区免费视频| 欧美日韩xxx| 日韩av在线免费观看一区| 亚洲大胆人体视频| 国产精品极品美女在线观看免费| 91精品国产777在线观看| 日韩亚洲精品视频| 国产一区二区香蕉| 91超碰caoporn97人人| 国产精品亚洲аv天堂网| 亚洲xxxx妇黄裸体| 欧美最猛性xxxxx(亚洲精品)| 久久精品视频网站| 亚洲男人天堂网站| 国产精品久久久久秋霞鲁丝| 91国产高清在线| 日本欧美黄网站| 久久人91精品久久久久久不卡| 中日韩午夜理伦电影免费| 色七七影院综合| 久久久国产在线视频| 亚洲国产成人精品久久久国产成人一区| 92国产精品久久久久首页| 国产精品高潮呻吟久久av无限| 国内精品久久久久久| 国产乱人伦真实精品视频| 亚洲女人天堂网| 亚洲区中文字幕| 美女久久久久久久久久久| 国产一区二区三区日韩欧美| 午夜精品一区二区三区在线视频| 欧美国产日韩在线| 亚洲自拍偷拍第一页| 国产精品久久久久久久久久久久| 亚洲第一av网站| 国模极品一区二区三区| 成人免费网站在线| 国产精品亚洲综合天堂夜夜| 91视频国产高清| 欧美电影免费观看大全| 欧美国产日韩精品| 国产精品美女主播在线观看纯欲| 国产97在线|亚洲| 久久综合五月天| 亚洲毛茸茸少妇高潮呻吟| 亚洲最大福利视频| 伊人一区二区三区久久精品| 91av在线视频观看| 国产午夜一区二区| 最近2019年日本中文免费字幕| 亚洲网站在线播放| www.久久久久| 日韩午夜在线视频| 一区二区三区国产视频| 91久久久久久久久| 欧美日韩一区二区三区在线免费观看| 亚洲精品97久久| 综合激情国产一区| 一区二区在线免费视频| 91久久在线播放| 亚洲有声小说3d|