亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

一文詳解tomcat是如何處理HTTP長連接的

 更新時間:2024年01月02日 11:36:55   作者:super凹凸曼  
HTTP長連接,也稱為持久連接,是一種使用同一個TCP連接來發(fā)送和接收多個HTTP請求/應(yīng)答的方法,那么tomcat作為最常用的WEB容器,是怎么處理HTTP的長連接呢,下面我們就來深入了解下吧

1、HTTP長連接

HTTP長連接,也稱為持久連接,是一種使用同一個TCP連接來發(fā)送和接收多個HTTP請求/應(yīng)答的方法,而不是為每一個新的請求/應(yīng)答打開新的TCP連接。這種方式由于通信連接一直存在,因此可以減少建立和關(guān)閉連接的開銷,提高通信效率。因為HTTP長連接的本質(zhì)就是保持TCP的連接在每次請求響應(yīng)之后不斷開,與其說是HTTP長連接,不如說是TCP的長連接。

那么tomcat作為最常用的WEB容器,是怎么處理HTTP的長連接呢?

2、tomcat處理長連接

在tomcat的Poller線程中,監(jiān)聽已連接套接字以保持連接,并輪詢以檢查數(shù)據(jù)是否可用。具體來說,Poller線程使用NIO架構(gòu),通過內(nèi)部的Selector對象向內(nèi)核查詢Channel的狀態(tài),一旦發(fā)現(xiàn)可讀事件,就會生成任務(wù)類SocketProcessor,并將其交給Executor去處理。

public void run() {
    // Loop until destroy() is called
    while (true) {

        boolean hasEvents = false;

        try {
            if (!close) {
                hasEvents = events();
                if (wakeupCounter.getAndSet(-1) > 0) {
                    // If we are here, means we have other stuff to do
                    // Do a non blocking select
                    keyCount = selector.selectNow();
                } else {
                    keyCount = selector.select(selectorTimeout);
                }
                wakeupCounter.set(0);
            }
            if (close) {
                events();
                timeout(0, false);
                try {
                    selector.close();
                } catch (IOException ioe) {
                    log.error(sm.getString("endpoint.nio.selectorCloseFail"), ioe);
                }
                break;
            }
            // Either we timed out or we woke up, process events first
            if (keyCount == 0) {
                hasEvents = (hasEvents | events());
            }
        } catch (Throwable x) {
            ExceptionUtils.handleThrowable(x);
            log.error(sm.getString("endpoint.nio.selectorLoopError"), x);
            continue;
        }

        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();
            iterator.remove();
            NioSocketWrapper socketWrapper = (NioSocketWrapper) sk.attachment();
            // Attachment may be null if another thread has called
            // cancelledKey()
            if (socketWrapper != null) {
                processKey(sk, socketWrapper);
            }
        }

        // Process timeouts
        timeout(keyCount,hasEvents);
    }

    getStopLatch().countDown();
}

Poller線程的run方法是while(true)死循環(huán),主要監(jiān)聽注冊的socket上是否有已就緒事件,如果有的話就調(diào)用processKey(sk, socketWrapper)方法交由線程池處理,最后調(diào)用了timeout方法。

protected void timeout(int keyCount, boolean hasEvents) {
    long now = System.currentTimeMillis();
    // nextExpiration初始化是0
    if (nextExpiration > 0 && (keyCount > 0 || hasEvents) && (now < nextExpiration) && !close) {
        return;
    }
    int keycount = 0;
    try {
        // 遍歷注冊到selector上所有的socket
        for (SelectionKey key : selector.keys()) {
            keycount++;
            NioSocketWrapper socketWrapper = (NioSocketWrapper) key.attachment();
            try {
                if (socketWrapper == null) {
                    // We don't support any keys without attachments
                    if (key.isValid()) {
                        key.cancel();
                    }
                } else if (close) {
                    key.interestOps(0);
                    // Avoid duplicate stop calls
                    socketWrapper.interestOps(0);
                    socketWrapper.close();
                // 如果注冊的事件是讀寫事件
                } else if (socketWrapper.interestOpsHas(SelectionKey.OP_READ) ||
                          socketWrapper.interestOpsHas(SelectionKey.OP_WRITE)) {
                    boolean readTimeout = false;
                    boolean writeTimeout = false;
                    // 檢查讀超時
                    if (socketWrapper.interestOpsHas(SelectionKey.OP_READ)) {
                        // 用當(dāng)前時間-上次讀時間
                        long delta = now - socketWrapper.getLastRead();
                        long timeout = socketWrapper.getReadTimeout();
                        if (timeout > 0 && delta > timeout) {
                            readTimeout = true;
                        }
                    }
                    // Check for write timeout
                    if (!readTimeout && socketWrapper.interestOpsHas(SelectionKey.OP_WRITE)) {
                        long delta = now - socketWrapper.getLastWrite();
                        long timeout = socketWrapper.getWriteTimeout();
                        if (timeout > 0 && delta > timeout) {
                            writeTimeout = true;
                        }
                    }
                    // 如果已經(jīng)超時
                    if (readTimeout || writeTimeout) {
                        key.interestOps(0);
                        // Avoid duplicate timeout calls
                        socketWrapper.interestOps(0);
                        socketWrapper.setError(new SocketTimeoutException());
                        if (readTimeout && socketWrapper.readOperation != null) {
                            if (!socketWrapper.readOperation.process()) {
                                socketWrapper.close();
                            }
                        } else if (writeTimeout && socketWrapper.writeOperation != null) {
                            if (!socketWrapper.writeOperation.process()) {
                                socketWrapper.close();
                            }
                        // processSocket中對將socket進(jìn)行關(guān)閉
                        } else if (!processSocket(socketWrapper, SocketEvent.ERROR, true)) {
                            socketWrapper.close();
                        }
                    }
                }
            } catch (CancelledKeyException ckx) {
                if (socketWrapper != null) {
                    socketWrapper.close();
                }
            }
        }
    } catch (ConcurrentModificationException cme) {
        // See https://bz.apache.org/bugzilla/show_bug.cgi?id=57943
        log.warn(sm.getString("endpoint.nio.timeoutCme"), cme);
    }
    // For logging purposes only
    long prevExp = nextExpiration;
    // nextExpiration重新賦值 當(dāng)前時間+1s,socketProperties.getTimeoutInterval()默認(rèn)1000
    nextExpiration = System.currentTimeMillis() +
            socketProperties.getTimeoutInterval();
    if (log.isTraceEnabled()) {
        log.trace("timeout completed: keys processed=" + keycount +
                "; now=" + now + "; nextExpiration=" + prevExp +
                "; keyCount=" + keyCount + "; hasEvents=" + hasEvents +
                "; eval=" + ((now < prevExp) && (keyCount>0 || hasEvents) && (!close) ));
    }

}

timeout方法主要做了以下事:

  • 判斷是否要進(jìn)行輪詢所有socket進(jìn)行超時判斷
  • 遍歷所有socket,拿到上次讀寫的事件,與當(dāng)前時間對比,是否已超時
  • 如果已超時,對相關(guān)socket進(jìn)行關(guān)閉處理
  • 重置nextExpiration值,默認(rèn)每秒都會對所有socket進(jìn)行超時輪詢判斷

在進(jìn)行對socket讀取時會把keepAliveTimeout參數(shù)賦值給ReadTimeout(前提,開啟長連接,tomcat已經(jīng)默認(rèn)開啟長連接)

if (keptAlive) {
    // Haven't read any request data yet so use the keep-alive
    // timeout.
    wrapper.setReadTimeout(keepAliveTimeout);
}

每次對socket進(jìn)行讀取后,也會調(diào)用updateLastRead方法更新上次讀取時間

if (to.remaining() >= limit) {
    to.limit(to.position() + limit);
    nRead = fillReadBuffer(block, to);
    if (log.isDebugEnabled()) {
        log.debug("Socket: [" + this + "], Read direct from socket: [" + nRead + "]");
    }
    updateLastRead();
}

3、總結(jié)

tomcat處理Http長連接是在Poller線程中的timeout方法,最長每秒都會對所有的socket進(jìn)行遍歷,上次讀寫數(shù)據(jù)的時間與當(dāng)前時間和參數(shù)配置的keep-alive-timeout時間進(jìn)行判斷是否已經(jīng)超時(前提開啟長連接),如果已經(jīng)超時則對相應(yīng)的socket進(jìn)行關(guān)閉

以上就是一文詳解tomcat是如何處理HTTP長連接的的詳細(xì)內(nèi)容,更多關(guān)于tomcat處理HTTP長連接的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Linux下安裝配置tomcat

    Linux下安裝配置tomcat

    Tomcat是一個輕量級應(yīng)用服務(wù)器,在中小型系統(tǒng)和并發(fā)訪問用戶不是很多的場合下被普遍使用,是開發(fā)和調(diào)試JSP程序的首選。對于一個初學(xué)者來說,可以這樣認(rèn)為,當(dāng)在一臺機器上配置好Apache服務(wù)器,可利用它響應(yīng)對HTML 頁面的訪問請求。
    2017-05-05
  • idea專業(yè)版和idea社區(qū)版整合Tomcat并將war包部署

    idea專業(yè)版和idea社區(qū)版整合Tomcat并將war包部署

    IDEA是一個功能完善的Java開發(fā)工具,除了具備有良好的代碼開發(fā)提示之外,還可以直接在IDEA中集成并啟動Tomcat實現(xiàn)程序的自動部署,本文主要介紹了idea專業(yè)版和idea社區(qū)版整合Tomcat并將war包部署,感興趣的可以了解一下
    2023-11-11
  • 如何修改tomcat默認(rèn)端口號8080的方法

    如何修改tomcat默認(rèn)端口號8080的方法

    本篇文章主要介紹了如何修改tomcat默認(rèn)端口號8080的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-03-03
  • Tomcat6.0與windows 2003 server 的IIS服務(wù)器集成

    Tomcat6.0與windows 2003 server 的IIS服務(wù)器集成

    本例主要講解Tomcat6.0與windows 2003 server 的IIS服務(wù)器集成的問題,用到的工具版 本如下:jdk是6.0、Tomcat 6.0、windows 2003 server 的IIS。
    2009-08-08
  • Tomcat中的Session與Cookie深入講解

    Tomcat中的Session與Cookie深入講解

    這篇文章主要給大家介紹了關(guān)于Tomcat中Session與Cookie的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用Tomcat具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09
  • Tomcat Nginx Redis實現(xiàn)session共享過程圖解

    Tomcat Nginx Redis實現(xiàn)session共享過程圖解

    這篇文章主要介紹了Tomcat Nginx Redis實現(xiàn)session共享過程圖解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-07-07
  • 深入理解tomcat中的BIO、NIO、AIO、ARP

    深入理解tomcat中的BIO、NIO、AIO、ARP

    tomcat作為springboot中默認(rèn)的web容器,了解tomcat的運轉(zhuǎn)可以幫助我們更好的去調(diào)整tomcat的參數(shù)達(dá)到更好的性能,這篇文章主要介紹了理解tomcat中的BIO、NIO、AIO、ARP,需要的朋友可以參考下
    2025-04-04
  • tomcat logs 目錄下各日志文件的解析(小結(jié))

    tomcat logs 目錄下各日志文件的解析(小結(jié))

    這篇文章主要介紹了tomcat logs 目錄下各日志文件的含義,包括catalina.日期.log,commons-daemon.日期.log,host-manager.日期.log,本文給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2021-12-12
  • tomcat單機多實例的實現(xiàn)

    tomcat單機多實例的實現(xiàn)

    這篇文章主要介紹了tomcat單機多實例的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • Tomcat的類加載機制流程及源碼解析

    Tomcat的類加載機制流程及源碼解析

    我們知道,ava默認(rèn)的類加載機制是通過雙親委派模型來實現(xiàn)的,而Tomcat實現(xiàn)的方式又和雙親委派模型有所區(qū)別,下面這篇文章主要給大家介紹了關(guān)于Tomcat類加載機制流程的相關(guān)資料,需要的朋友可以參考下
    2021-11-11

最新評論