色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

基于Select/Poll實現并發服務器(一)

嵌入式大雜燴 ? 來源:嵌入式大雜燴 ? 作者:嵌入式大雜燴 ? 2022-06-20 00:20 ? 次閱讀

開發環境:

RT-Thread版本:4.0.3

操作系統:Windows10

Keil版本:V5.30

RT-Thread Studio版本:2.0.1

開發板MCUSTM32H750XB

LWIP:2.0.2

并發服務器支持多個客戶端的同時連接,最大可接入的客戶端數取決于內核控制塊的個數。當使用Socket API時,要使服務器能夠同時支持多個客戶端的連接,必須引入多任務機制,為每個連接創建一個單獨的任務來處理連接上的數據,多任務可以是多線程或者多進程,這是最常用的并發服務器設計。但是多線程/多進程消耗資源多,處理起來也比較復雜,本文將基于LWIP協議棧的Select/Poll機制實現并發服務器。

1 IO模型概述

在具體講解基于Select/Poll機制實現并發服務器之前,我們需要了解IO的相關概念,所謂IO就是,就是數據的讀寫,一般分為網絡IO(本質就是socket讀寫)和磁盤IO。

IO模型大致可以分為:同步阻塞、同步非阻塞、異步、信號驅動

poYBAGKvMWeAWCgZAAEohJIEplU624.png

可細分為5種I/O模型:

1)阻塞I/O,進程處于阻塞模式時,讓出CPU,進入休眠狀態;

2)非阻塞I/O,非阻塞模式的使用并不普遍,因為非阻塞模式會浪費大量的CPU資源;

3)I/O復用(select和poll),針對批量IP操作時,使用I/O多路復用,非常有好;

4)異步I/O(POSIX的aio_系列函數)

5)信號驅動I/O(SIGIO)

一個輸入操作通常包括兩個不同的階段:

1)等待數據準備好;

2)從內核向進程復制數據;

對于一個套接字的輸入操作,第一步通常涉及等待數據從網絡中到達。當所等待分組到達時,它被復制到內核中某個緩沖區。第二步就是把數據從內核緩沖區復制到應用進程緩沖區。

1.1阻塞I/O

阻塞 I/O模式是最普遍使用的 I/O模式。一個套接字建立后所處于的模式就是阻塞 I/O模式。(因為Linux系統默認的IO模式是阻塞模式)。對于一個 UDP套接字來說,數據就緒的標志比較簡單:

(1)已經收到了一整個數據報

(2)沒有收到。

而 TCP這個概念就比較復雜,需要附加一些其他的變量。

最流行的I/O模型是阻塞式I/O(blocking I/O) 模型,默認情況下,所有的套接字都是阻塞的。阻塞調用是指調用結果返回之前,當前線程會被掛起(線程進入非可執行狀態,在這個狀態下,CPU不會給線程分配時間片,即線程暫停運行)。函數只有在得到結果之后才會返回。以數據包套接字為例,如圖。

poYBAGKvMZOAOGqKAAEVSw_i33g481.png

進程調用recvfrom,其系統調用直到數據報到達且被拷貝到應用進程的緩沖區或者發生錯誤才返回。最常見的錯誤是系統調用被信號中斷。我們說進程從調用recvfrom開始到它返回的整段時間內是被阻塞的,recvfrom成功返回后,進程開始處理數據報。

1.2非阻塞I/O

進程把一個套接口設置成非阻塞是在通知內核:當所請求的I/O操作非得把本進程投入睡眠才能完成時,不要把本進程投入睡眠,而是返回一個錯誤。

poYBAGKvMbCAFZKRAAFvRl2AOgY598.png

前三次調用recvfrom時沒有數據可返回,因此內核轉而立即返回一個EWOULDBLOCK錯誤。第四次調用 recvfrom時已有一個數據報準備好,它被復制到應用程序緩沖區,于是recvfrom成功返回。我們接著處理數據。

當一個應用程序使用了非阻塞模式的套接字,它需要使用一個循環來不聽的測試是否一個文件描述符有數據可讀(稱做 polling(輪詢))。應用程序不停的 polling內核來檢查是否 I/O操作已經就緒。這將是一個極浪費 CPU資源的操作。這種模式使用中不是很普遍。

非阻塞和阻塞的概念相對應,指在不能立刻得到結果之前,該函數不會阻塞當前線程,而會立刻返回。

1.3 I/O復用

在使用 I/O多路技術的時候,我們調用 select()函數和 poll()函數,在調用它們的時候阻塞,而不是我們來調用 recvfrom(或recv)的時候阻塞。主要可以調用select和poll;對一個IO端口,兩次調用,兩次返回,比阻塞IO并沒有什么優越性;關鍵是能實現同時對多個IO端口進行監聽,可以等待多個描述符就緒。

I/O復用模型會用到select、poll,這幾個函數也會使進程阻塞,但是和阻塞I/O所不同的的,這兩個函數可以同時阻塞多個I/O操作。而且可以同時對多個讀操作,多個寫操作的I/O函數進行檢測,直到有數據可讀或可寫時,才真正調用I/O操作函數。

當我們調用 select函數阻塞的時候,select函數等待數據報套接字進入讀就緒狀態。當select函數返回的時候,也就是套接字可以讀取數據的時候。這時候我們就可以調用 recvfrom函數來將數據拷貝到我們的程序緩沖區中。

對于單個I/O操作,和阻塞模式相比較,select()和poll()并沒有什么高級的地方。而且,在阻塞模式下只需要調用一個函數:讀取或發送函數。在使用了多路復用技術后,我們需要調用兩個函數了:先調用 select()函數或poll()函數,然后才能進行真正的讀寫。

多路復用的高級之處在于:它能同時等待多個文件描述符,而這些文件描述符(套接字描述符)其中的任意一個進入讀就緒狀態,select()函數就可以返回。

pYYBAGKvMdeAYlOlAAFzoeeT2H0033.png

IO多路技術一般在下面這些情況中被使用:

  • 當一個客戶端需要同時處理多個文件描述符的輸入輸出操作的時候(一般來說是標準的輸入輸出和網絡套接字),I/O多路復用技術將會有機會得到使用。
  • 當程序需要同時進行多個套接字的操作的時候。
  • 如果一個 TCP服務器程序同時處理正在偵聽網絡連接的套接字和已經連接好的套接字。
  • 如果一個服務器程序同時使用 TCP和 UDP協議。
  • 如果一個服務器同時使用多種服務并且每種服務可能使用不同的協議(比如 inetd就是這樣的)。

1.4異步I/O模型

異步I/O(asynchronous I/O)有POSIX規范定義。后來演變成當前POSIX規范的各種早期標準定義的實時函數中存在的差異已經取得一致。一般地說,這些函數的工作機制是:告知內核啟動某個操作,并讓內核在整個操作(包括將數據從內核拷貝到我們自己的緩沖區)完成后通知我們。這種模型與前與前面介紹的信號驅動模型的主要區別在于:信號驅動I/O是由內核通知我們何時可以啟動一個I/O操作,而異步I/O模型是由內核通知我們I/O操作何時完成。

poYBAGKvMfOAV7qOAAE5v-Hf4zM819.png

1.5信號驅動I/O模型

我們也可以用信號,讓內核在描述字就緒時發送SIGIO信號通知我們。我們稱這種模型為信號驅動I/O(signal-driven I/O)。

我們首先開啟套接口的信號驅動I/O功能,并通過sigaction系統調用安裝一個信號處理函數。該系統調用立即發回,我們的進程繼續工作,也就是說它沒有被阻塞。當數據報準備好時,內核就為該進程產生一個SIGIO信號。我們隨后既可以在信號處理函數中調用recvfrom讀取數據報,并通知主循環數據已經準備好待處理,也可以立即通知主循環,讓它讀取數據報。

無論如何處理SIGIO信號,這種模型的優勢在于等待數據報到達期間,進程不被阻塞。主循環可以繼續執行,只要不時等待來自信號處理函數的通知:既可以是數據已經準備好被處理,也可以是數據報已準備好被讀取。

poYBAGKvMgyAO8zdAAGHYr595FM613.png

1.6各種模型的比較

各種模型的比較如下圖所示,可以看出,前4種模型的主要區別在于第一階段,因為它們的第二階段是一樣的:在數據從內核復制到調用者的緩沖區起見,進程阻塞與recvfrom調用,相反。異步I/O模型在這兩個階段都需要處理,從而不同于其他四種模型。

poYBAGKvMiWATzBqAAG55wWa2bY569.png
  • 同步I/O與異步I/O對比

POSIX把這兩個術語定義如下:

·同步I/O操作(synchronous I/O operation)導致請求進程阻塞,直到I/O操作完成。

·異步I/O(asynchronous I/O operation)不導致請求進程阻塞。

根據上述定義,我們前4種模型----阻塞I/O模型、非阻塞I/O模型、I/O復用模型和信號去驅動I/O模型都是同步I/O模型,因為其中真正的I/O操作(recvfrom)將阻塞進程。只有異步I/O模型與POSIX定義的異步I/O相匹配。

本文的要將的I/O復用,本質就是select/poll機制。因此,其他IO有興趣可以去了解。

2 RT-thread的網絡架構

RT-Thread的網絡框架結構如下所示:

poYBAGKvMj-AVxm8AABpdb_PAWU941.png

最頂層是網絡應用層,提供一套標準 BSD Socket API,如 socket、connect等函數,用于系統中大部分網絡開發應用, BSD Socket API已經是網絡套接字的事實上的抽象標準。使用BSD Socket API編寫應用,不會依賴具體的操作系統,但是底層的具體實現是依賴操作系統的。

第二部分為 SAL套接字抽象層,通過它 RT-Thread系統能夠適配下層不同的網絡協議棧,并提供給上層統一的網絡編程接口,方便不同協議棧的接入。套接字抽象層為上層應用層提供接口有:accept、connect、send、recv等。

第三部分為 netdev網卡層,主要作用是解決多網卡情況設備網絡連接和網絡管理相關問題,通過 netdev網卡層用戶可以統一管理各個網卡信息和網絡連接狀態,并且可以使用統一的網卡調試命令接口。

第四部分為協議棧層,該層包括幾種常用的 TCP/IP協議棧,例如嵌入式開發中常用的輕型 TCP/IP協議棧 lwIP以及 RT-Thread自主研發的 AT Socket網絡功能實現等。這些協議棧或網絡功能實現直接和硬件接觸,完成數據從網絡層到傳輸層的轉化。

最后一層為硬件層,ETH是唯一的有線網絡接入方式,其余都是無線網絡接入方式,LTE模組,Cat模組,NB-IOT模組這些依賴基站運營商的入網方式,例如 SIM800,EC25,AIR720,L610,N58,M5311等,這些不同廠家,不同工作頻率的模組均可以通過 NET組件入網;WIFI這種無需運營商直接提供的網絡的入網方式,例如 ESP8266,W60x,AP6212,rw007等。

RT-Thread的網絡應用層提供的接口主要以標準 BSD Socket API為主,這樣能確保程序可以在 Windows或者Linux上編寫、調試,然后再移植到 RT-Thread操作系統上。

RT-Thread對于不同的協議棧或網絡功能實現,網絡接口的名稱可能各不相同,以 connect連接函數為例,lwIP協議棧中接口名稱為 lwip_connect,而 AT Socket網絡實現中接口名稱為 at_connect。SAL組件提供對不同協議棧或網絡實現接口的抽象和統一,組件在 socket創建時通過判斷傳入的協議簇(domain)類型來判斷使用的協議棧或網絡功能,完成 RT-Thread系統中多協議的接入與使用。

目前 SAL組件支持的協議棧或網絡實現類型有:lwIP協議棧、AT Socket協議棧、WIZnet硬件 TCP/IP協議棧

int socket(int domain, int type, int protocol);

上述為標準 BSD Socket API中 socket創建函數的定義,domain表示協議域又稱為協議簇(family),用于判斷使用哪種協議棧或網絡實現,AT Socket協議棧使用的簇類型為 AF_AT,lwIP協議棧使用協議簇類型有 AF_INET等,WIZnet協議棧使用的協議簇類型為 AF_WIZ。

對于不同的軟件包,socket傳入的協議簇類型可能是固定的,不會隨著 SAL組件接入方式的不同而改變。為了動態適配不同協議棧或網絡實現的接入,SAL組件中對于每個協議棧或者網絡實現提供兩種協議簇類型匹配方式:主協議簇類型和次協議簇類型。socket創建時先判斷傳入協議簇類型是否存在已經支持的主協議類型,如果是則使用對應協議棧或網絡實現,如果不是判斷次協議簇類型是否支持。目前系統支持協議簇類型如下:

  • lwIP協議棧: family = AF_INET、sec_family = AF_INET
  • AT Socket協議棧: family = AF_AT、sec_family = AF_INET
  • WIZnet硬件 TCP/IP協議棧: family = AF_WIZ、sec_family = AF_INET

SAL組件主要作用是統一抽象底層 BSD Socket API接口,下面以 bind函數調用流程為例說明 SAL組件函數調用方式:

  • bind:SAL組件對外提供的抽象的 BSD Socket API,用于統一 fd管理;
  • sal_bind:SAL組件中 bind實現函數,用于指定端口和網卡(當存在多個網卡的時候)。
  • lwip_bind:底層協議棧提供的層 bind連接函數,在網卡初始化完成時注冊到 SAL組件中,最終調用的操作函數。

/* SAL組件為應用層提供的標準 BSD Socket API */

int bind(int s, const struct sockaddr *name, socklen_t namelen)
{
    /*獲取 SAL套接字描述符 */
int socket = dfs_net_getsocket(s);

    /*通過 SAL套接字描述符執行 sal_bind函數 */
    return sal_bind(socket, name, namelen);
}

/* SAL組件抽象函數接口實現 */

int sal_bind(int socket, const struct sockaddr *name, socklen_t namelen)
{
    struct sal_socket *sock;
    struct sal_proto_family *pf;
    ip_addr_t input_ipaddr;

    RT_ASSERT(name);

    /* get the socket object by socket descriptor */
    SAL_SOCKET_OBJ_GET(sock, socket);

    /* bind network interface by ip address */
    sal_sockaddr_to_ipaddr(name, &input_ipaddr);

    /* check input ipaddr is default netdev ipaddr */
    if (!ip_addr_isany_val(input_ipaddr))
    {
        struct sal_proto_family *input_pf = RT_NULL, *local_pf = RT_NULL;
        struct netdev *new_netdev = RT_NULL;

        new_netdev = netdev_get_by_ipaddr(&input_ipaddr);
        if (new_netdev == RT_NULL)
        {
            return -1;
        }

        /* get input and local ip address proto_family */
       SAL_NETDEV_SOCKETOPS_VALID(sock->netdev, local_pf, bind);
        SAL_NETDEV_SOCKETOPS_VALID(new_netdev, input_pf, bind);

        /* check the network interface protocol family type */
        if (input_pf->family != local_pf->family)
        {
            int new_socket = -1;

            /* protocol family is different, close old socket and create new socket by input ip address */
           local_pf->skt_ops->closesocket(socket);

            new_socket = input_pf->skt_ops->socket(input_pf->family, sock->type, sock->protocol);
            if (new_socket < 0)
            {
                return -1;
            }
            sock->netdev = new_netdev;
            sock->user_data = (void *) new_socket;
        }
    }

    /* check and get protocol families by the network interface device */
    SAL_NETDEV_SOCKETOPS_VALID(sock->netdev, pf, bind);
    return pf->skt_ops->bind((int) sock->user_data, name, namelen);
}

/* lwIP協議棧函數底層 bind函數實現 */

int lwip_bind(int s, const struct sockaddr *name, socklen_t namelen)
{
 struct lwip_sock *sock;
 ip_addr_t local_addr;
 u16_t local_port;
 err_t err;

 sock = get_socket(s);
 if (!sock) {
    return -1;
 }

 if (!SOCK_ADDR_TYPE_MATCH(name, sock)) {
    /* sockaddr does not match socket type (IPv4/IPv6) */
    sock_set_errno(sock, err_to_errno(ERR_VAL));
    return -1;
 }

 /* check size, family and alignment of 'name' */
 LWIP_ERROR("lwip_bind: invalid address", (IS_SOCK_ADDR_LEN_VALID(namelen) &&
             IS_SOCK_ADDR_TYPE_VALID(name) && IS_SOCK_ADDR_ALIGNED(name)),
             sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
 LWIP_UNUSED_ARG(namelen);

 SOCKADDR_TO_IPADDR_PORT(name, &local_addr, local_port);
 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s));
 ip_addr_debug_print_val(SOCKETS_DEBUG, local_addr);
 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", local_port));

#if LWIP_IPV4 && LWIP_IPV6
 /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */
 if (IP_IS_V6_VAL(local_addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&local_addr))) {
   unmap_ipv4_mapped_ipv6(ip_2_ip4(&local_addr), ip_2_ip6(&local_addr));
    IP_SET_TYPE_VAL(local_addr, IPADDR_TYPE_V4);
 }
#endif /* LWIP_IPV4 && LWIP_IPV6 */

 err = netconn_bind(sock->conn, &local_addr, local_port);

 if (err != ERR_OK) {
    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) failed, err=%d\n", s, err));
    sock_set_errno(sock, err_to_errno(err));
    return -1;
 }

 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) succeeded\n", s));
 sock_set_errno(sock, 0);
 return 0;
}

ART-Pi有兩種常用的聯網方式,一個是板載的WiFi模塊AP6212,這個模塊自帶藍牙;另一個是工業擴展板的網口,使用的芯片是LAN8720A。關于多網卡的使用和自動切換在前面的章節有所講解。本文主要講解如何使用Select/Poll機制來實現并發服務器。

RT-Thread網絡組件:

https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/net/net_introduce

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 服務器
    +關注

    關注

    12

    文章

    9123

    瀏覽量

    85324
  • RT-Thread
    +關注

    關注

    31

    文章

    1285

    瀏覽量

    40081
  • select
    +關注

    關注

    0

    文章

    28

    瀏覽量

    3912
  • ART-Pi
    +關注

    關注

    0

    文章

    23

    瀏覽量

    1296
收藏 人收藏

    評論

    相關推薦

    我國首款億級并發服務器系統實現量產

    我國高性能計算領軍企業中科曙光29日在天津宣布,曙光星河云服務器系統正式量產。這是我國首款億級并發服務器系統,也是“十二五”期間國家863計劃信息技術領域“億級并發
    發表于 11-30 15:47 ?838次閱讀

    基于Select/Poll實現并發服務器(二)

    LWIP:2.0.2 3 Select/Poll概述 在LWIP中,如果要實現并發服務器,可以基于Sequentaial API來
    的頭像 發表于 06-20 00:26 ?4951次閱讀
    基于<b class='flag-5'>Select</b>/<b class='flag-5'>Poll</b><b class='flag-5'>實現</b><b class='flag-5'>并發</b><b class='flag-5'>服務器</b>(二)

    在DragonBoard 410c上實現并發處理TCP服務器

    服務,讓傳感和相關的控制設備接入,為此,本期blog將向大家介紹如何使用gevent高性能的并發處理庫在draognbaord 410c上來實現
    發表于 09-25 15:53

    高性能高并發服務器架構分享

    由于自己正在做個高性能大用戶量的論壇程序,對高性能高并發服務器架構比較感興趣,于是在網上收集了不少這方面的資料和大家分享。希望能和大家交流 msn: ——————————————————————————————————————
    發表于 09-16 06:45

    如何利用多線程去構建種TCP并發服務器

    、實驗目的和要求1了解TCP/IP協議2掌握Socket編程,熟悉基于TCP和UDP的傳輸模型3掌握多線程編程4掌握基于TCP的并發服務器設計二、實驗內容和原理實驗內容:編寫C程序,利用多線程構建
    發表于 12-22 08:03

    【沁恒微CH32V307評估板試用體驗】基于LWIP實現并發服務器

    程,這是最常用的并發服務器設計。但是多線程/多進程消耗資源多,處理起來也比較復雜,本文將基于LWIP協議棧的Select/Poll機制實現
    發表于 06-01 23:27

    【飛凌嵌入式OK3568-C開發板試用體驗】第4章 基于 Select Poll的TCP發服務器

    ,本文將基于Select/Poll機制實現并發服務器。 4.1 IO模型概述在具體講解基于Select
    發表于 06-09 22:45

    【原創精選】RT-Thread征文精選技術文章合集

    。RT-Thread自動初始化詳解GD32 RISC-V系列 BSP框架制作與移植GD32407V-START開發板的BSP框架制作與移植基于Select/Poll實現并發
    發表于 07-26 14:56

    【LuckFox Pico Plus開發板免費試用】基于 Select Poll的TCP發服務器

    ,處理起來也比較復雜,本文將基于Select/Poll機制實現并發服務器。 1 IO模型概述 在具體講解基于
    發表于 10-21 13:31

    Linux環境并發服務器設計技術研究

    講述并發服務器設計的主要技術,包括多進程服務器、多線程服務器和I/ O 復用服務器,同時對以上服務器
    發表于 04-24 10:02 ?16次下載

    Linux內核中select, poll和epoll的區別

    先說pollpollselect為大部分Unix/Linux程序員所熟悉,這倆個東西原理類似,性能上也不存在明顯差異,但select對所監控的文件描述符數量有限制,所以這里選用
    發表于 05-14 16:24 ?1709次閱讀

    服務器的高并發能力如何提升?

    服務器的高并發能力如何提升? 服務器并發能力體現著服務器在單位時間內的很強數據處理能力,般來
    的頭像 發表于 03-17 17:07 ?1013次閱讀

    網站服務器并發數的計算方法是什么?

    介紹。 網站服務器并發數主要分為以下幾種:業務并發的用戶數量、最大的并發訪問數量、系統中的用戶數量、同時在線的用戶數量。因為并發數是指網站
    的頭像 發表于 04-12 15:22 ?3229次閱讀

    并發服務器的設計與實現

    并發服務器支持多個客戶端的連接,最大可接入的客戶端數取決于內核控制塊的個數。當使用Socket API時,要使服務器能夠同時支持多個客戶端的連接,必須引入多任務機制,為每個連接創建
    的頭像 發表于 04-25 15:35 ?840次閱讀
    <b class='flag-5'>并發</b><b class='flag-5'>服務器</b>的設計與<b class='flag-5'>實現</b>

    服務器并發的概念

    自己調整系統的相關參數 并發的概念是什么?什么是并發? 對于服務器并發的概念,下面幾點是錯誤的定義 ①服務器處理客戶端請求的數量:沒有時間、
    的頭像 發表于 11-10 10:05 ?5031次閱讀
    <b class='flag-5'>服務器</b><b class='flag-5'>并發</b>的概念
    主站蜘蛛池模板: 亚洲国产三级在线观看| 欧美zozofoot| 好姑娘BD高清在线观看免费| 成人亚洲视频| 背着老婆爆操性感小姨子| adc影院在线| qvod12| xart欧美一区在线播放| 9988电影网| FREE另类老女人| adc我们的永久网址| XXXchinese国产HD| 成年妇女免费播放| 成人在线观看视频免费| 俄罗斯摘花| 国产精品久久久久久搜索| 国产精品久久人妻互换毛片| 国产精品久久久久久免费播放| 国产高清视频免费在线观看| 国产精品1区2区| 国内精品蜜汁乔依琳视频| 果冻传媒9CM在线观看| 娇妻归来在线观看免费完整版电影 | 国产精品成人免费观看| 岛国片免费在线观看| 公交车轮C关老师| 国产老肥熟xxxx| 精品欧美小视频在线观看| 久久精品WWW人人爽人人| 啦啦啦 中文 中国 免费 高清在线| 久久只精品99品免费久| 欧美成人亚洲高清在线观看| 全彩acg无翼乌火影忍者| 十二月综合缴缴情| 亚洲国产日韩欧美视频二区| 正在播放国产精品| porono日本xxx| 国产老肥熟xxxx| 久久夜色噜噜噜亚洲AV0000| 免费观看视频成人国产| 三级黄在线播放|