欧美一级特黄大片做受成人-亚洲成人一区二区电影-激情熟女一区二区三区-日韩专区欧美专区国产专区

Tomcat中的連接器是如何設(shè)計的

本篇文章給大家分享的是有關(guān)Tomcat中的連接器是如何設(shè)計的,小編覺得挺實用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。

創(chuàng)新互聯(lián)建站專業(yè)為企業(yè)提供東平網(wǎng)站建設(shè)、東平做網(wǎng)站、東平網(wǎng)站設(shè)計、東平網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁設(shè)計與制作、東平企業(yè)網(wǎng)站模板建站服務(wù),10多年東平做網(wǎng)站經(jīng)驗,不只是建網(wǎng)站,更提供有價值的思路和整體網(wǎng)絡(luò)服務(wù)。

上期回顧

上一篇文章《Tomcat在SpringBoot中是如何啟動的》從main方法啟動說起,窺探了SpringBoot是如何啟動Tomcat的,在分析Tomcat中我們重點提到了,Tomcat主要包括2個組件,連接器(Connector)和容器(Container)以及他們的內(nèi)部結(jié)構(gòu)圖,那么今天我們來分析下Tomcat中的連接器是怎么設(shè)計的以及它的作用是什么。

說明:本文tomcat版本是9.0.21,不建議零基礎(chǔ)讀者閱讀。

從連接器(Connector)源碼說起

既然是來解析連接器(Connector),那么我們直接從源碼入手,后面所有源碼我會剔除不重要部分,所以會忽略大部分源碼細節(jié),只關(guān)注流程。源碼如下(高能預(yù)警,大量代碼):

public class Connector extends LifecycleMBeanBase  {
    public Connector() {
        this("org.apache.coyote.http11.Http11NioProtocol");
    }


    public Connector(String protocol) {
        boolean aprConnector = AprLifecycleListener.isAprAvailable() &&
                AprLifecycleListener.getUseAprConnector();

        if ("HTTP/1.1".equals(protocol) || protocol == null) {
            if (aprConnector) {
                protocolHandlerClassName = "org.apache.coyote.http11.Http11AprProtocol";
            } else {
                protocolHandlerClassName = "org.apache.coyote.http11.Http11NioProtocol";
            }
        } else if ("AJP/1.3".equals(protocol)) {
            if (aprConnector) {
                protocolHandlerClassName = "org.apache.coyote.ajp.AjpAprProtocol";
            } else {
                protocolHandlerClassName = "org.apache.coyote.ajp.AjpNioProtocol";
            }
        } else {
            protocolHandlerClassName = protocol;
        }

        // Instantiate protocol handler
        ProtocolHandler p = null;
        try {
            Class<?> clazz = Class.forName(protocolHandlerClassName);
            p = (ProtocolHandler) clazz.getConstructor().newInstance();
        } catch (Exception e) {
            log.error(sm.getString(
                    "coyoteConnector.protocolHandlerInstantiationFailed"), e);
        } finally {
            this.protocolHandler = p;
        }

        // Default for Connector depends on this system property
        setThrowOnFailure(Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE"));
    }

我們來看看Connector的構(gòu)造方法,其實只做了一件事情,就是根據(jù)協(xié)議設(shè)置對應(yīng)的ProtocolHandler,根據(jù)名稱我們知道,這是協(xié)議處理類,所以連接器內(nèi)部的一個重要子模塊就是ProtocolHandler。

關(guān)于生命周期

我們看到Connector繼承了LifecycleMBeanBase,我們來看看Connector的最終繼承關(guān)系:

Tomcat中的連接器是如何設(shè)計的

我們看到最終實現(xiàn)的是Lifecycle接口,我們看看這個接口是何方神圣。我把其接口的注釋拿下來解釋下

/**
 * Common interface for component life cycle methods.  Catalina components
 * may implement this interface (as well as the appropriate interface(s) for
 * the functionality they support) in order to provide a consistent mechanism
 * to start and stop the component.
 *            start()
 *  -----------------------------
 *  |                           |
 *  | init()                    |
 * NEW -?-- INITIALIZING        |
 * | |           |              |     ------------------?-----------------------
 * | |           |auto          |     |                                        |
 * | |          \|/    start() \|/   \|/     auto          auto         stop() |
 * | |      INITIALIZED --?-- STARTING_PREP --?- STARTING --?- STARTED --?---  |
 * | |         |                                                            |  |
 * | |destroy()|                                                            |  |
 * | --?-----?--    ------------------------?--------------------------------  ^
 * |     |          |                                                          |
 * |     |         \|/          auto                 auto              start() |
 * |     |     STOPPING_PREP ----?---- STOPPING ------?----- STOPPED -----?-----
 * |    \|/                               ^                     |  ^
 * |     |               stop()           |                     |  |
 * |     |       --------------------------                     |  |
 * |     |       |                                              |  |
 * |     |       |    destroy()                       destroy() |  |
 * |     |    FAILED ----?------ DESTROYING ---?-----------------  |
 * |     |                        ^     |                          |
 * |     |     destroy()          |     |auto                      |
 * |     --------?-----------------    \|/                         |
 * |                                 DESTROYED                     |
 * |                                                               |
 * |                            stop()                             |
 * ----?-----------------------------?------------------------------
 *
 * Any state can transition to FAILED.
 *
 * Calling start() while a component is in states STARTING_PREP, STARTING or
 * STARTED has no effect.
 *
 * Calling start() while a component is in state NEW will cause init() to be
 * called immediately after the start() method is entered.
 *
 * Calling stop() while a component is in states STOPPING_PREP, STOPPING or
 * STOPPED has no effect.
 *
 * Calling stop() while a component is in state NEW transitions the component
 * to STOPPED. This is typically encountered when a component fails to start and
 * does not start all its sub-components. When the component is stopped, it will
 * try to stop all sub-components - even those it didn't start.
 *
 * Attempting any other transition will throw {@link LifecycleException}.
 *
 * </pre>
 * The {@link LifecycleEvent}s fired during state changes are defined in the
 * methods that trigger the changed. No {@link LifecycleEvent}s are fired if the
 * attempted transition is not valid.

這段注釋翻譯就是,這個接口是提供給組件聲明周期管理的,并且提供了聲明周期流轉(zhuǎn)圖。這里我們只需要知道正常流程即可:

New--->Init()---->Start()---->Stop()--->Destory()

從生命周期探索連接器

根據(jù)上面的生命周期說明,我們可以知道連接器(Connector)就是按照如此的聲明周期管理的,所以我們找到了線索,所以連接器肯定會先初始化然后再啟動。我們查看其initInternal()方法可以知道連接器初始化做了什么事情,源碼如下:

    @Override
    protected void initInternal() throws LifecycleException {

        super.initInternal();

        if (protocolHandler == null) {
            throw new LifecycleException(
                    sm.getString("coyoteConnector.protocolHandlerInstantiationFailed"));
        }

        // Initialize adapter
        adapter = new CoyoteAdapter(this);
        protocolHandler.setAdapter(adapter);
        if (service != null) {
            protocolHandler.setUtilityExecutor(service.getServer().getUtilityExecutor());
        }

        // Make sure parseBodyMethodsSet has a default
        if (null == parseBodyMethodsSet) {
            setParseBodyMethods(getParseBodyMethods());
        }

        if (protocolHandler.isAprRequired() && !AprLifecycleListener.isInstanceCreated()) {
            throw new LifecycleException(sm.getString("coyoteConnector.protocolHandlerNoAprListener",
                    getProtocolHandlerClassName()));
        }
        if (protocolHandler.isAprRequired() && !AprLifecycleListener.isAprAvailable()) {
            throw new LifecycleException(sm.getString("coyoteConnector.protocolHandlerNoAprLibrary",
                    getProtocolHandlerClassName()));
        }
        if (AprLifecycleListener.isAprAvailable() && AprLifecycleListener.getUseOpenSSL() &&
                protocolHandler instanceof AbstractHttp11JsseProtocol) {
            AbstractHttp11JsseProtocol<?> jsseProtocolHandler =
                    (AbstractHttp11JsseProtocol<?>) protocolHandler;
            if (jsseProtocolHandler.isSSLEnabled() &&
                    jsseProtocolHandler.getSslImplementationName() == null) {
                // OpenSSL is compatible with the JSSE configuration, so use it if APR is available
                jsseProtocolHandler.setSslImplementationName(OpenSSLImplementation.class.getName());
            }
        }

        try {
            protocolHandler.init();
        } catch (Exception e) {
            throw new LifecycleException(
                    sm.getString("coyoteConnector.protocolHandlerInitializationFailed"), e);
        }
    }
}

根據(jù)上面源碼,我們發(fā)現(xiàn)主要是處理protocolHandler并初始化它,同時我們注意到了protocolHandler 設(shè)置了一個適配器,我們看看這個適配器是做啥的,跟蹤源碼如下:

   /**
     * The adapter, used to call the connector.
     *
     * @param adapter The adapter to associate
     */
    public void setAdapter(Adapter adapter);

這個注釋已經(jīng)說的很直白了,這個適配器就是用來調(diào)用連接器的。我們再繼續(xù)看看protocolHandler的初始化方法

 /**
     * Endpoint that provides low-level network I/O - must be matched to the
     * ProtocolHandler implementation (ProtocolHandler using NIO, requires NIO
     * Endpoint etc.).
     */
private final AbstractEndpoint<S,?> endpoint;

public void init() throws Exception {
        if (getLog().isInfoEnabled()) {
            getLog().info(sm.getString("abstractProtocolHandler.init", getName()));
            logPortOffset();
        }

        if (oname == null) {
            // Component not pre-registered so register it
            oname = createObjectName();
            if (oname != null) {
                Registry.getRegistry(null, null).registerComponent(this, oname, null);
            }
        }

        if (this.domain != null) {
            rgOname = new ObjectName(domain + ":type=GlobalRequestProcessor,name=" + getName());
            Registry.getRegistry(null, null).registerComponent(
                    getHandler().getGlobal(), rgOname, null);
        }

        String endpointName = getName();
        endpoint.setName(endpointName.substring(1, endpointName.length()-1));
        endpoint.setDomain(domain);

        endpoint.init();
    }

這里出現(xiàn)了一個新的對象,endpoint,根據(jù)注釋我們可以知道endpoint是用來處理網(wǎng)絡(luò)IO的,而且必須匹配到指定的子類(比如Nio,就是NioEndPoint處理)。endpoint.init()實際上就是做一些網(wǎng)絡(luò)的配置,然后就是初始化完畢了。根據(jù)我們上面的周期管理,我們知道init()后就是start(),所以我們查看Connectorstart()源碼:

 protected void startInternal() throws LifecycleException {

        // Validate settings before starting
        if (getPortWithOffset() < 0) {
            throw new LifecycleException(sm.getString(
                    "coyoteConnector.invalidPort", Integer.valueOf(getPortWithOffset())));
        }

        setState(LifecycleState.STARTING);

        try {
            protocolHandler.start();
        } catch (Exception e) {
            throw new LifecycleException(
                    sm.getString("coyoteConnector.protocolHandlerStartFailed"), e);
        }
    }

其實就是主要調(diào)用 protocolHandler.start()方法,繼續(xù)跟蹤,為了方便表述,我會把接下來的代碼統(tǒng)一放在一起說明,代碼如下:

//1.類:AbstractProtocol implements ProtocolHandler,
        MBeanRegistration
 public void start() throws Exception {
     // 省略部分代碼
    endpoint.start();
    }

//2. 類:AbstractEndPoint   
public final void start() throws Exception {
       // 省略部分代碼
        startInternal();
    }
 /**3.類:NioEndPoint extends AbstractJsseEndpoint<NioChannel,SocketChannel>
     * Start the NIO endpoint, creating acceptor, poller threads.
     */
    @Override
    public void startInternal() throws Exception {
        //省略部分代碼
       
            // Start poller thread
            poller = new Poller();
            Thread pollerThread = new Thread(poller, getName() + "-ClientPoller");
            pollerThread.setPriority(threadPriority);
            pollerThread.setDaemon(true);
            pollerThread.start();

            startAcceptorThread();
        }
    }

到這里,其實整個啟動代碼就完成了,我們看到最后是在NioEndPoint創(chuàng)建了一個Poller,并且啟動它,這里需要補充說明下,這里只是以NioEndPoint為示列,其實Tomcat 主要提供了三種實現(xiàn),分別是AprEndPoint,NioEndPoint,Nio2EndPoint,這里表示了tomcat支持的I/O模型:

APR:采用 Apache 可移植運行庫實現(xiàn),它根據(jù)不同操作系統(tǒng),分別用c重寫了大部分IO和系統(tǒng)線程操作模塊,據(jù)說性能要比其他模式要好(未實測)。

NIO:非阻塞 I/O

NIO.2:異步 I/O

上述代碼主要是開啟兩個線程,一個是Poller,一個是開啟Acceptor,既然是線程,核心的代碼肯定是run方法,我們來查看源碼,代碼如下:

//4.類:Acceptor<U> implements Runnable
 public void run() {
 //省略了部分代碼
                U socket = null;
                    socket = endpoint.serverSocketAccept();
                // Configure the socket
                if (endpoint.isRunning() && !endpoint.isPaused()) {
                    // setSocketOptions() will hand the socket off to
                    // an appropriate processor if successful
                    //核心邏輯
                    if (!endpoint.setSocketOptions(socket)) {
                        endpoint.closeSocket(socket);
                    }
                } else {
                    endpoint.destroySocket(socket);
                }
            
        state = AcceptorState.ENDED;
}
//5.類:NioEndpoint
protected boolean setSocketOptions(SocketChannel socket) {
        // Process the connection
        //省略部分代碼
        try {
            // Disable blocking, polling will be used
            socket.configureBlocking(false);
            Socket sock = socket.socket();
            socketProperties.setProperties(sock);


            NioSocketWrapper socketWrapper = new NioSocketWrapper(channel, this);
            channel.setSocketWrapper(socketWrapper);
            socketWrapper.setReadTimeout(getConnectionTimeout());
            socketWrapper.setWriteTimeout(getConnectionTimeout());
            socketWrapper.setKeepAliveLeft(NioEndpoint.this.getMaxKeepAliveRequests());
            socketWrapper.setSecure(isSSLEnabled());
            //核心邏輯
            poller.register(channel, socketWrapper);
            return true;
  
    }

這里可以發(fā)現(xiàn)Acceptor主要就是接受socket,然后把它注冊到poller中,我們繼續(xù)看看是如何注冊的。

/**6.類NioEndpoint
         * Registers a newly created socket with the poller.
         *
         * @param socket    The newly created socket
         * @param socketWrapper The socket wrapper
         */
        public void register(final NioChannel socket, final NioSocketWrapper socketWrapper) {
            socketWrapper.interestOps(SelectionKey.OP_READ);//this is what OP_REGISTER turns into.
            PollerEvent r = null;
            if (eventCache != null) {
                r = eventCache.pop();
            }
            if (r == null) {
                r = new PollerEvent(socket, OP_REGISTER);
            } else {
                r.reset(socket, OP_REGISTER);
            }
            addEvent(r);
        }
/** 7.類:PollerEvent implements Runnable
 public void run() {
    //省略部分代碼
    socket.getIOChannel().register(socket.getSocketWrapper().getPoller().getSelector(), SelectionKey.OP_READ, socket.getSocketWrapper());
        }

這里發(fā)現(xiàn)最終就是采用NIO模型把其注冊到通道中。(這里涉及NIO網(wǎng)絡(luò)編程知識,不了解的同學(xué)可以傳送這里)。那么注冊完畢后,我們看看Poller做了什么事情。

*/        
  /**8.類:NioEndPoint內(nèi)部類 Poller implements Runnable
  **/  
  @Override
        public void run() {
            // Loop until destroy() is called
            while (true) {
                //省略部分代碼

                Iterator<SelectionKey> iterator =
                    keyCount > 0 ? selector.selectedKeys().iterator() : null;
                // Walk through the collection of ready keys and dispatch
                // any active event.
                while (iterator != null && iterator.hasNext()) {
                    SelectionKey sk = iterator.next();
                    NioSocketWrapper socketWrapper = (NioSocketWrapper) sk.attachment();
                    // Attachment may be null if another thread has called
                    // cancelledKey()
                    if (socketWrapper == null) {
                        iterator.remove();
                    } else {
                        iterator.remove();
                        //sock處理
                        processKey(sk, socketWrapper);
                    }
                }
        //省略部分代碼
        }

這個就是通過selector把之前注冊的事件取出來,從而完成了調(diào)用。

//9.類: NioEndPoint內(nèi)部類 Poller  implements Runnable     
protected void processKey(SelectionKey sk, NioSocketWrapper socketWrapper) {
         //省略大部分代碼
           processSocket(socketWrapper, SocketEvent.OPEN_WRITE, true)
    
}
       
//10.類:AbstractEndPoint        
public boolean processSocket(SocketWrapperBase<S> socketWrapper,
           SocketEvent event, boolean dispatch) {
       //省略部分代碼
           Executor executor = getExecutor();
           if (dispatch && executor != null) {
               executor.execute(sc);
           } else {
               sc.run();
           }
      
       return true;
   }  
//11.類:SocketProcessorBase  implements Runnable   
public final void run() {
       synchronized (socketWrapper) {
           // It is possible that processing may be triggered for read and
           // write at the same time. The sync above makes sure that processing
           // does not occur in parallel. The test below ensures that if the
           // first event to be processed results in the socket being closed,
           // the subsequent events are not processed.
           if (socketWrapper.isClosed()) {
               return;
           }
           doRun();
       }
   }
   
//類:12.NioEndPoint   extends AbstractJsseEndpoint<NioChannel,SocketChannel> 
protected void doRun() {
       //省略部分代碼
               if (handshake == 0) {
                   SocketState state = SocketState.OPEN;
                   // Process the request from this socket
                   if (event == null) {
                       state = getHandler().process(socketWrapper, SocketEvent.OPEN_READ);
                   } else {
                       state = getHandler().process(socketWrapper, event);
                   }
                   if (state == SocketState.CLOSED) {
                       poller.cancelledKey(key, socketWrapper);
                   }
               }

       }

Poller調(diào)用的run方法或者用Executor線程池去執(zhí)行run(),最終調(diào)用都是各個子EndPoint中的doRun()方法,最終會取一個Handler去處理socketWrapper。繼續(xù)看源碼:

//類:13.AbstractProtocol內(nèi)部類ConnectionHandler implements AbstractEndpoint.Handler<S>
 public SocketState process(SocketWrapperBase<S> wrapper, SocketEvent status) {
            //省略部分代碼
    
            state = processor.process(wrapper, status);
      
            return SocketState.CLOSED;
        }
        
//類:14.AbstractProcessorLight implements Processor 
public SocketState process(SocketWrapperBase<?> socketWrapper, SocketEvent status)
            throws IOException {
            //省略部分代碼
           
            state = service(socketWrapper);
            
        return state;
    }

這部分源碼表明最終調(diào)用的process是通過一個Processor接口的實現(xiàn)類來完成的,這里最終也是會調(diào)用到各個子類中,那么這里的處理器其實就是處理應(yīng)用協(xié)議,我們可以查看AbstractProcessorLight的實現(xiàn)類,分別有AjpProcessor、Http11Processor、StreamProcessor,分別代表tomcat支持三種應(yīng)用層協(xié)議,分別是:

  • AJP協(xié)議

  • HTTP.1協(xié)議

  • HTTP2.0協(xié)議

這里我們以常用的HTTP1.1為例,繼續(xù)看源碼:

//類:15. Http11Processor extends AbstractProcessor
public SocketState service(SocketWrapperBase<?> socketWrapper)
        throws IOException {
        //省略大部分代碼
             getAdapter().service(request, response);
        //省略大部分代碼   
        } 
//類:16   CoyoteAdapter implements Adapter
public void service(org.apache.coyote.Request req, org.apache.coyote.Response res)
            throws Exception {

        Request request = (Request) req.getNote(ADAPTER_NOTES);
        Response response = (Response) res.getNote(ADAPTER_NOTES);
        postParseSuccess = postParseRequest(req, request, res, response);
            if (postParseSuccess) {
                //check valves if we support async
                request.setAsyncSupported(
                        connector.getService().getContainer().getPipeline().isAsyncSupported());
                // Calling the container
                connector.getService().getContainer().getPipeline().getFirst().invoke(
                        request, response);
            }
            
    }

這里我們發(fā)現(xiàn)協(xié)議處理器最終會調(diào)用適配器(CoyoteAdapter),而適配器最終的工作是轉(zhuǎn)換RequestResponse對象為HttpServletRequestHttpServletResponse,從而可以去調(diào)用容器,到這里整個連接器的流程和作用我們就已經(jīng)分析完了。

小結(jié)

那么我們來回憶下整個流程,我畫了一張時序圖來說明:

Tomcat中的連接器是如何設(shè)計的

這張圖包含了兩個流程,一個是組件的初始化,一個是調(diào)用的流程。連接器(Connector)主要初始化了兩個組件,ProtcoHandlerEndPoint,但是我們從代碼結(jié)構(gòu)發(fā)現(xiàn),他們兩個是父子關(guān)系,也就是說ProtcoHandler包含了EndPoint。后面的流程就是各個子組件的調(diào)用鏈關(guān)系,總結(jié)來說就是Acceptor負責(zé)接收請求,然后注冊到Poller,Poller負責(zé)處理請求,然后調(diào)用processor處理器來處理,最后把請求轉(zhuǎn)成符合Servlet規(guī)范的requestresponse去調(diào)用容器(Container)。

我們流程梳理清楚了,接下來我們來結(jié)構(gòu)化的梳理下:

回到連接器(Connector)是源碼,我們發(fā)現(xiàn),上述說的模塊只有ProtocolHandlerAdapter兩個屬于連接器中,也就是說,連接器只包含了這兩大子模塊,那么后續(xù)的EndPoint、AcceptorPoller、Processor都是ProtocolHandler的子模塊。 而AcceptorPoller兩個模塊的核心功能都是在EndPoint 中完成的,所以是其子模塊,而Processor比較獨立,所以它和EndPoint是一個級別的子模塊。

我們用圖來說明下上述的關(guān)系:

Tomcat中的連接器是如何設(shè)計的

根據(jù)上圖我們可以知道,連接器主要負責(zé)處理連接請求,然后通過適配器調(diào)用容器。那么具體流程細化可以如下:

  • Acceptor監(jiān)聽網(wǎng)絡(luò)請求,獲取請求。

  • Poller獲取到監(jiān)聽的請求提交線程池進行處理。

  • Processor根據(jù)具體的應(yīng)用協(xié)議(HTTP/AJP)來生成Tomcat Request對象。

  • Adapter把Request對象轉(zhuǎn)換成Servlet標(biāo)準(zhǔn)的Request對象,調(diào)用容器。

我們從連接器的源碼,一步一步解析,分析了連接器主要包含了兩大模塊,ProtocolHandlerAdapter。ProtocolHandler主要包含了Endpoint模塊和Processor模塊。Endpoint模塊主要的作用是連接的處理,它委托了Acceptor子模塊進行連接的監(jiān)聽和注冊,委托子模塊Poller進行連接的處理;而Processor模塊主要是應(yīng)用協(xié)議的處理,最后提交給Adapter進行對象的轉(zhuǎn)換,以便可以調(diào)用容器(Container)。

以上就是Tomcat中的連接器是如何設(shè)計的,小編相信有部分知識點可能是我們?nèi)粘9ぷ鲿姷交蛴玫降?。希望你能通過這篇文章學(xué)到更多知識。更多詳情敬請關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。

網(wǎng)站題目:Tomcat中的連接器是如何設(shè)計的
標(biāo)題路徑:http://aaarwkj.com/article24/iggsce.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供商城網(wǎng)站、響應(yīng)式網(wǎng)站、軟件開發(fā)網(wǎng)站設(shè)計公司、、App開發(fā)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

商城網(wǎng)站建設(shè)
中文字幕av久久激情| 亚洲欧美天堂一区二区| 亚洲国产精品一区二区三区在线 | 日日插天天干夜夜操| 久久久国产精品视频网站| 色哟哟网站在线精品视频| 国产激情一区二区三区不卡| 18禁止看的视频免费| 日本成人一区二区三区在线| 亚洲天堂免费观看av| 日本午夜节目在线观看| 亚洲经典日韩欧美一区| 搡老女人老91妇女老熟女| 亚洲欧美经典精品专区| 久久久精品人妻免费网站| 91欧美日韩精品在线| 亚洲乱码国产乱码精品| 中文字幕精品一区二区三区精品 | 一区二区三区日韩专区| 伦理在线视频免费观看视频| 一区二区三区艳情播放| 中文岳妇荡欲丰满肥熟| 欧美国产一级二级三级| 成年人免费观看黄色片| 日韩精品精美视频在线观看| 国产极品美女在线观看网站| 亚洲一区二区三区久久精品| 可以免费看黄的网久久| 久久久久久精品国产av| 高潮少妇水多毛多av| 你懂的免费视频中文字幕| av天堂最新资源在线| 天天日天天天干夜夜操| 中文字幕成人资源网站| 日本人妻中文字幕在线一区| 中文字幕制服国产精品| 欧美日韩一区二区午夜福利| 久久免费少妇高潮99精品| av一区二区三区三| 精品成人乱色一区二区| 成人在线观看av毛片|