中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

WebSocket原理及Tomcat的實現是怎樣的

發布時間:2021-11-15 16:08:33 來源:億速云 閱讀:325 作者:柒染 欄目:大數據

WebSocket原理及Tomcat的實現是怎樣的 ,很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細講解,有這方面需求的人可以來學習下,希望你能有所收獲。

現如今,許多場景下需要實現從服務端到客戶端的主動推送消息。而對于傳統的HTTP,我們都了解,其必須是要通過主動的請求,每個Request對應一個Response,此時要實現服務端推,必須要有一個主動的請求。

為此,人們想出了ajax長輪詢,長連接等一系列方式,但對比長輪詢的不斷無效的請求,都不如使用我們今天提到的更方便且不消耗資源實現。

對比HTTP請求,比較明顯的你會感覺到,無論是異步還是同步請求,對于HTTP,在開發者工具中你都能觀察到應用是新發了一個請求到服務器,之后根據返回的信息進行處理展示的。

而WebSocket,則在第一次握手建立連接之后,后續的收發消息,都不再重新建立連接,也就是你觀察不到它后續的請求了。

這也是HTTP與WebSocket的區別。

而在Tomcat內部,我們來看Websocket是如何生效及工作的。

首先,來看WebSocket是如何初始化的。

無論哪種類型的請求,都會在ApplicationFilterChain中進行處理,根據是否配置Filter來決定整個處理的流向。(前面曾介紹過Filter的工作原理及請求流程:責任鏈模式及Filter的工作原理)。而無論哪個應用,其實Tomcat內部都會為其默認添加這樣一個Filter:

WsFilter

這個Filter就是用來處理WebSocket的,但又不全是,因為它的filter-mapping是

/*

FilterRegistration.Dynamic fr = servletContext.addFilter(

                "Tomcat WebSocket (JSR356) Filter", new WsFilter());

        fr.setAsyncSupported(true);

        EnumSet<DispatcherType> types = EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD);

        fr.addMappingForUrlPatterns(types, true, "/*");

上面的代碼即是使用Servlet3.0新增加的動態聲明Filter的實現方式,把WsFilter這個動態增加到應用的filter鏈中。

而這個Filter中,也是在入口處判斷,只有WebSocket的請求才處理,其它的就跳過了


// This filter only needs to handle WebSocket upgrade requests

        if (!sc.areEndpointsRegistered() ||

                !UpgradeUtil.isWebSocketUpgradeRequest(request, response)) {

            chain.doFilter(request, response);

            return;

        }

添加Filter這一行為,是在應用啟動的時候執行的,調用棧如下:

 at org.apache.catalina.core.StandardContext.addFilterMap(StandardContext.java:2836)

 at org.apache.catalina.core.ApplicationFilterRegistration.addMappingForUrlPatterns(ApplicationFilterRegistration.java:104)

 at org.apache.tomcat.websocket.server.WsServerContainer.<init>(WsServerContainer.java:141)

 at org.apache.tomcat.websocket.server.WsSci.init(WsSci.java:131)

 at org.apache.tomcat.websocket.server.WsSci.onStartup(WsSci.java:47)

 at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5151)

請求連接建立

在數據發送之前,需要先建立連接。而WebSocket本質上仍然是TCP連接,雖然看起來是通過HTTP,只是因為其初次的握手是需要通過HTTP來建立。

我們以Tomcat自帶的websocket樣例中的echo例子來說明WebSocket的使用方式以及其在Tomcat內部的實現形式。

echo例子位于:

TOMCAT_HOME\webapps\examples\websocket

java代碼位于:

TOMCAT_HOME\webapps\examples\WEB-INF\classes\websocket\echo

代碼中,對于connect和echo message的實現如下:

 function connect() {

            var target = document.getElementById('target').value;

            if (target == '') {

                alert('Please select server side connection implementation.');

                return;

            }

            if ('WebSocket' in window) {

                ws = new WebSocket(target);

            } else if ('MozWebSocket' in window) {

                ws = new MozWebSocket(target);

            } else {

                alert('WebSocket is not supported by this browser.');

                return;

            }

            ws.onopen = function () {

                setConnected(true);

                log('Info: WebSocket connection opened.');

            };

            ws.onmessage = function (event) {

                log('Received: ' + event.data);

            };

            ws.onclose = function (event) {

                setConnected(false);

                log('Info: WebSocket connection closed, Code: ' + event.code + (event.reason == "" ? "" : ", Reason: " + event.reason));

            };

        }

我們看到,整個websocket對象會處理三個事件:

  • connect

  • message

  • close

而信息的發送,是直接使用websocket的send方法。

在初次連接握手時,通過開發者工具,我們可以觀察到:

WebSocket原理及Tomcat的實現是怎樣的

是通過Upgrade來進行協議的切換,同時連接到WebSocket 的Server上去的。

而此時的Upgrade就是通過我們前面提到的Filter來進行的。

在Filter中,通過UgradeUtil的doUpgrade方法進行后續關于WebSocket規范的調用實現。

而對于WebSocket Server 的支持,我們通過Echo的例子可以看到,可以直接使用Endpoint的類來進行,也可以通過注解的等式進行。

例如下面的代碼就是通過注解的形式,聲明了一個Websocket的Endpoint

@ServerEndpoint("/websocket/echoAnnotation")
 
public class EchoAnnotation {
   @OnMessage
   public void echoTextMessage(Session session, String msg, boolean last) {
       try {
           if (session.isOpen()) {
               session.getBasicRemote().sendText(msg, last);
           }
       } catch (IOException e) {
       }
   }

根據注解,Tomcat內部會生成一個PojoServer,并使用反射調用當前標注有@OnMessage的方法。

而請求的分發,我們在前面介紹Connector的時候,曾簡單說過是經過

Endpoint  -> Handler -> Protocol

(Tomcat的Connector組件)

對于不同的請求,Protocol中進行不同的轉發,

} else if (processor.isAsync() ||
       state == SocketState.ASYNC_END) {
   state = processor.asyncDispatch(status);
} else if (processor.isComet()) {
   state = processor.event(status);
} else if (processor.isUpgrade()) {
   state = processor.upgradeDispatch(status);
} else if (status == SocketStatus.OPEN_WRITE) {
   // Extra write event likely after async, ignore
   state = SocketState.LONG;
}

在建立連接之后,后續再進行的數據發送,通過開發者工具已經觀察不到任何的請求了,這也是WebSocket之所以可以實現服務器推送的主要原因。其本質上在建立連接后,已經不再是一個HTTP請求了,而是一個TCP連接。

而且因于WebSocket在HTML5中的規范實現,各個主流瀏覽器的支持,現在多數的應用服務器也都已經根據規范進行了支持。許多要實現服務器推的場景也可以考慮使用WebSocket來實現。

打開Tomcat的webSocket樣例,來體驗一下吧!

看完上述內容是否對您有幫助呢?如果還想對相關知識有進一步的了解或閱讀更多相關文章,請關注億速云行業資訊頻道,感謝您對億速云的支持。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

靖远县| 南宁市| 江陵县| 珲春市| 锡林郭勒盟| 巴彦县| 峨边| 固安县| 延川县| 攀枝花市| 宜州市| 绍兴县| 静宁县| 江安县| 武平县| 满城县| 信阳市| 法库县| 蒲城县| 高平市| 大悟县| 嘉黎县| 怀来县| 高要市| 福海县| 平度市| 湖北省| 易门县| 咸阳市| 江口县| 祁连县| 韶关市| 新绛县| 呼玛县| 涿鹿县| 伽师县| 石家庄市| 阿拉尔市| 湟中县| 社旗县| 藁城市|