小結: 客戶端和瀏覽器"實時通信"


olddoor:  通過本文可了解客戶端和瀏覽器"實時通信"的解決方案
1 定時輪詢(拉取)
    1.1 定時輪詢, 整個頁面刷新(過時)
    1.2 基於js, 定時輪詢(普通輪詢)
    1.3 基於js, 長輪詢等Comet類風格的請求.(客戶端請求后服務器端有結果反饋, 沒結果hold請求, 等有結果或超時再響應. 得到響應后客戶端重新發起輪詢請求.  此方式對比普通輪詢,減少js請求服務器端的次數(減少創建連接的開銷))
服務器端的早期實現方式可在servet中for循環等待有結果再response.
servet3.0開始 相關開發規范支持異步處理的特性.  對應服務器端可基於sevlet3的規范(服務器一側接收請求的線程和處理請求的線程分開, 接收請求后容器線程處理其他請求, 原請求的連接不關閉, 待處理線程處理完畢后, 通過監聽器等方式通過原未關閉的連接給與客戶端響應.)

2 相互通信(推送, 如websocket為代表)


1 請求-響應的局限性

網絡上的客戶端-服務器通信在過去曾是一種請求-響應模型,要求客戶端(比如 Web 瀏覽器)向服務器請求資源。服務器通過發送所請求的資源來響應客戶端請求。如果資源不可用,或者客戶端沒有權限訪問它,那么服務器會發送一條錯誤消息。在請求-響應架構中,未經請求, 服務器絕不能主動向客戶端發送未經請求的消息

2 瀏覽器和服務器實時通信的解決方案

瀏覽器需要和服務器保持實時通信效果實現的一些想法, 思路其實無非就是兩種
1 客戶端定時到服務器查詢信息, 實現一種看起來是"服務器推送"的效果.
2 服務器和客戶端實時通信, 雙方能互相推送信息.

對應的技術實現上可能的方案有:
1 基於客戶端Socket的技術(過時的解決方案, 代表方案Flash XMLSocket,Java Applet套接口,Activex包裝的socket ) 
  • 優點:原生socket的支持,和PC端和移動端的實現方式相似;
  • 缺點:瀏覽器端需要裝相應的插件;
2 傳統的輪詢方式: 利用js定時輪詢服務器. 客戶端每隔一段時間都會向服務器請求新數據. 要想取得數據,必須首先發送請求. 性能差.不推薦
3 Comet技術 (可以理解為一種技術分類. 服務器在沒有新數據的時候不再返回空響應,而是hold住連接. 
而且把連接保持到有服務器方有更新的時候或超時(設置)才返回響應信息並關閉連接,客戶端處理完響應信息后再向服務器發送新的請求的這類實現技術. 稱為Comet技術 )
本質是基於HTTP長連接定時"拉數據" 達到一個瀏覽器和服務器實時通信, 貌似"服務器推"的效果.
Comet是一種技術思路, 代表的實現方案有 長輪詢和 基於 Iframe 及流(streaming)方式.

4 HTML5 標准的WebSocket 和Server-sent-events(SSE)
5 自建或者使用第三方雲推送(本質和上述3種已發生改變, 我方已變成推送接收方)

本文不涉及App或者小程序之類的推送. 


3 輪詢

不管服務端數據有無更新,客戶端每隔定長時間請求拉取一次數據,可能有更新數據返回,也可能什么都沒有。
這顯然這不會是"實時通信"/"服務器推"效果可能的選擇方案.
實現一般用AJAX 定時(可以使用JS的 setTimeout 函數)去服務器查詢是否有新消息 。這讓用戶感覺應用是實時的。實際上這會造成延時和性能問題,因為服務器每秒都要處理大量的連接請求,每次請求都會有 TCP 三次握手並附帶 HTTP 的頭信息。盡管現在很多應用仍在使用輪詢,但這並不是理想的解決方案。
  • 優點:服務端邏輯簡單;
  • 缺點:大多數請求是無效請求,在輪詢很頻繁的情況下對服務器的壓力很大;
可能的實現代碼, 利用XHR,通過setInterval定時發送請求,但會造成數據同步不及時及無效的請求,增加后端處理壓力。
function ajax(data){
    var xhr = new XMLHttpRequest();
    xhr.open('get', '/cgi-bin/xxx', true);
    xhr.onreadystatechange = function(){
        if (xhr.readyState == 4) {
            if (xhr.status == 200) {
                ......
            }
        }
    }
    xhr.send(data);
}
setTimeout(function(){ajax({"data":"hehe"});}, 2000);//每隔2秒請求一次

4 comet 技術模型

Comet是技術實現的一個分類而已. 也可理解為客戶端所需要的響應信息不再需要主動地去索取,而是在服務器端以事件(Event)的形式推至客戶端的技術類別.
具體實現方式為長輪詢和iframe流.

4.1 長輪詢

長輪詢是在Ajax傳統輪詢基礎上做的一些改進,服務器在沒有新數據的時候不再返回空響應,而是hold住連接. 
而且把連接保持到有服務器方有更新的時候或超時(設置)才返回響應信息並關閉連接,客戶端處理完響應信息后再次向服務器發送新的請求。 (這種實現思路,這類方案被成為Comet技術)
長輪詢的效果是讓 HTTP的連接保持,服務器端會阻塞請求,直到服務器端有一個事件觸發或者到達超時。客戶端在收到響應后再次發出請求,重新建立連接。
----------延伸--------------
前面提到長輪詢如果當時服務端沒有需要的相關數據,此時請求會hold住,直到服務端把相關數據准備好,或者等待一定時間直到此次請求超時,這里大家是否有疑問,為什么不是一直等待到服務端數據准備好再返回,這樣也不需要再次發起下一次的 長輪詢 ,節省資源?
主要原因是網絡傳輸層主要走的是tcp協議,tcp協議是可靠面向連接的協議,通過三次握手建立連接。但是所建立的連接是虛擬的,可能存在某段時間網絡不通,或者服務端程序非正常關閉,亦或服務端機器非正常關機,面對這些情況客戶端根本不知道服務端此時已經不能互通,還在傻傻的等服務端發數據過來,而這一等一般都是很長時間。當然tcp協議棧在實現上有保活計時器來保證的,但是等到保活計時器發現連接已經斷開需要很長時間,如果沒有專門配置過相關的tcp參數,一般需要2個小時,而且這些參數是機器操作系統層面,所以,以此方式來保活不太靠譜,故 長輪詢 的實現上一般是需要設置超時時間的。
-----------------------------

如圖4-1, 從瀏覽器的角度來看,長輪詢的辦法保持了有效的請求,又避免了大量無效請求,並且即時性更好,這是一種可行的方案。

  • 優點:任意瀏覽器都可用;實時性好,無消息的情況下不會進行頻繁的請求;
  • 缺點:連接創建銷毀操作還是比較頻繁,服務器維持着連接比較消耗資源;

在長輪詢方式下,客戶端是在 XMLHttpRequest 的 readystate 為 4(即數據傳輸結束)時調用回調函數,進行信息處理。當 readystate 為 4 時,數據傳輸結束,連接已經關閉。

4.1.1 短輪詢和長輪詢的區別

短輪詢中服務器對請求立即響應,而長輪詢中服務器等待新的數據到來才響應,因此實現了服務器向頁面推送實時,並減少了頁面的請求次數。
普通Ajax輪詢與基於Ajax的長輪詢原理對比: 圖4-2




4.1.2 長輪詢的編碼實現

可能的實現代碼:

JS客戶端

function longPoll(data, cbk){
    var xhr = new XMLHttpRequest();
    var url = '/cgi-bin/xxx';
    xhr.onreadystatechange = function(){
        if (xhr.readyState == 4) {//XMLHttpRequest 的狀態中4: 請求已完成,且響應已就緒
            if (xhr.status == 200) { //請求完畢后重新發起新的一次連接
                cbk(xhr.responseText);
                xhr.open('get', url, true);
                xhr.send(otherData);
            }
        }
    }
    xhr.open('get', url, true);
    xhr.send(data);
}
注意:
無論是輪詢還是Comet技術, 思路都是客戶端頻繁間隔的對服務器端發送請求數據達到"服務器推"的效果, 會在服務端和客戶端都需要維持一個比較長時間的連接狀態,這一點在客戶端不算什么太大的負擔,但是服務端是要同時對多個客戶端服務的,按照經典 Request-Response 交互模型,每一個請求都占用一個 Web 線程不釋放的話,Web 容器的線程則會很快消耗殆盡,而這些線程大部分時間處於空閑等待的狀態。
Comet對比輪詢只不過是在請求服務器的頻率上會大幅降低而已. 
而服務器一方 線程大部分時間處於空閑等待, 嚴重影響服務器性能(請求始終占用連接) , 所以能夠有異步處理的原因,希望 Web 線程不需要同步的、一對一的處理客戶端請求,能做到一個 Web 線程處理多個客戶端請求。
服務器端能夠異步處理請求的規范以及標准就是 Servlet3.0規范 引入的異步支持.

---------------延伸開始----------------------------
Servlet 3.0 作為 Java EE 6 規范體系中一員,隨着 Java EE 6 規范一起發布。(Tomcat7提供了對Java EE6規范的支持。)
新特性部分列列舉如下:
1 異步處理支持:有了該特性,Servlet 線程不再需要一直阻塞,直到業務處理完畢才能再輸出響應,最后才結束該 Servlet 線程。在接收到請求之后,Servlet 線程可以將耗時的操作委派給另一個線程來完成,自己在不生成響應的情況下返回至容器。針對業務處理較耗時的情況,這將大大減少服務器資源的占用,並且提高並發處理速度。
2 新增的注解支持:該版本新增了若干注解,用於簡化 Servlet、過濾器(Filter)和監聽器(Listener)的聲明,這使得 web.xml 部署描述文件從該版本開始不再是必選的了。
使用異步處理 Servlet 線程不再是一直處於阻塞狀態以等待業務邏輯的處理,而是啟動異步線程之后可以立即返回.
異步處理特性可以應用於 Servlet 和過濾器兩種組件. 
1)對於使用傳統的部署描述文件 (web.xml) 配置 Servlet 和過濾器的情況Servlet 3.0 為 和 標簽增加了 子標簽,該標簽的默認取值為 false,要啟用異步處理支持,則將其設為 true 即可。以 Servlet 為例
<servlet> 
    <servlet-name>DemoServlet</servlet-name> 
    <servlet-class>footmark.servlet.Demo Servlet</servlet-class> 
    <async-supported>true</async-supported> 
</servlet>
2) 使用注解方式: Servlet 3.0 提供的 @WebServlet 和 @WebFilter 進行 Servlet 或過濾器配置的情況,這兩個注解都提供了 asyncSupported 屬性,默認該屬性的取值為 false,要啟用異步處理支持,只需將該屬性設置為 true 即可
@WebFilter 為例,其配置方式如下所示:
@WebFilter(urlPatterns = “/demo”,asyncSupported = true)
2、 Servlet 3.0 還為異步處理提供了一個監聽器 ,使用  AsyncListener  接口表示.
異步的攔截器:
            1)、原生API的AsyncListener (使用異步servlet的時候需要注冊 AsyncListener )
            2)、SpringMVC:實現AsyncHandlerInterceptor
---------------延伸結束------------------- ---------


服務器端

(1)服務端基於servlet(同步/異步)的實現
詳見   Long Polling長輪詢及例子詳解  (名詞解釋, 例子服務端主要是 基於servlet的實現 )或者見( https://www.jianshu.com/p/d3f66b1eb748  和

服務器端異步實現
需要做的是
保證 web.xml 中application的配置的版本是3.0
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            http://java.sun.com/xml/ns/javaee
            http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    version="3.0">
可以通過web.xml中的子元素<async-supported>true</async-supported>使得DispatcherServlet支持異步.此外的任何Filter參與異步語法處理必須配置為支持ASYNC分派器類型。這樣可以確保Spring Framework提供的所有filter都能夠異步分發.自從它們繼承了OncePerRequestFilter之后.並且在runtime的時候會check filter是否需要被異步調用分發.
下面是web.xml的配置示例:
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
            http://java.sun.com/xml/ns/javaee
            http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    version="3.0">

    <filter>
        <filter-name>Spring OpenEntityManagerInViewFilter</filter-name>
        <filter-class>org.springframework.~.OpenEntityManagerInViewFilter</filter-class>
        <async-supported>true</async-supported>
    </filter>

    <filter-mapping>
        <filter-name>Spring OpenEntityManagerInViewFilter</filter-name>
        <url-pattern>/*</url-pattern>
        <dispatcher>REQUEST</dispatcher>
        <dispatcher>ASYNC</dispatcher>
    </filter-mapping>

</web-app>
如果使用Sevlet3,Java配置可以通過 WebApplicationInitializer ,你同樣需要像在 web.xml 中一樣,設置”asyncSupported”標簽為ASYNC.為了簡化這個配置,考慮繼承 AbstractDispatcherServletInitializer 或者 AbstractAnnotationConfigDispatcherServletInitializer 。它們會自動設置這些選項,使它很容易注冊過濾器實例。

在代碼層面:
接受處理請求的servlet需要使用Servlet 3.0為異步處理提供了一個監聽器,使用AsyncListener接口表示。此接口負責管理異步事件.
Long Polling長輪詢及例子詳解例子中使用異步servlet處理請求, 就用到了 AsyncListener

見代碼片段
 asyncContext.addListener(new AsyncListener() { //這里為異步處理提供了一個監聽器,使用AsyncListener接口表示。此接口負責管理異步事件
            @Override
            public void onComplete(AsyncEvent event) throws IOException {

            }

            //超時處理,注意asyncContext.complete();,表示請求處理完成
            @Override
            public void onTimeout(AsyncEvent event) throws IOException {
                AsyncContext asyncContext = event.getAsyncContext();
                asyncContext.complete();
            }

            @Override
            public void onError(AsyncEvent event) throws IOException {

            }

            @Override
            public void onStartAsync(AsyncEvent event) throws IOException {

            }
        });

(2)服務器端基於SpringMVC實現(DeferredResult 或 Callable)
官方文檔中說DeferredResult和Callable( java.util.concurrent.Callable  涉及java多線程知識) )都是為了異步生成返回值提供基本的支持。簡單來說就是一個請求進來,如果你使用了DeferredResult或者Callable,在沒有得到返回數據之前DispatcherServlet和所有Filter就會退出Servlet容器線程但響應保持打開狀態,一旦返回數據有了,這個DispatcherServlet就會被再次調用並且處理,以異步產生的方式,向請求端返回值。 
這么做的好處就是請求不會長時間占用服務連接池,提高服務器的吞吐量。
這其實也就是SpringMVC對於外部請求的異步處理( 基本實現 Servlet 3.0的異步處理規范).核心是為了提高減少http請求的連接的占用, 接受請求后快速釋放, 將業務邏輯交給其他線程處理. 業務邏輯處理完畢后重新拿到http請求連接, 由http連接返回給客戶端. 達到異步的效果.  

C ontroller中構造 Callable並將其作為返回值. 
使用Callable大致流程說明
客戶端請求服務后;
  • SpringMVC調用Controller,Controller返回一個Callback對象
  • SpringMVC調用ruquest.startAsync並且將Callback提交到TaskExecutor使用一個隔離的線程去進行執行
  • DispatcherServlet以及Filters等從應用服務器線程中結束,但Response仍舊是打開狀態,也就是說暫時還不返回給客戶端
  • TaskExecutor調用Callback返回一個結果,SpringMVC將請求發送給應用服務器繼續處理
  • DispatcherServlet再次被調用並且繼續處理Callback返回的對象,根據Callable返回的結果。SpringMVC繼續進行視圖渲染流程等, 最終將其返回給客戶端

簡易流程參考如圖4-1-2

這里寫圖片描述

DeferredResult
DeferredResult的處理過程與Callback類似,不一樣的地方在於它的結果不是DeferredResult直接返回的,而是由其它線程通過同步的方式設置到該對象中。
它的執行過程如下所示:

DeferredResult的處理順序與Callable十分相似,由應用程序多線程產生異步結果:

  1. Controller返回一個DeferredResult對象,並且把它保存在內在隊列當中或者可以訪問它的列表中。
  2. Spring MVC開始異步處理.
  3. DispatcherServlet與所有的Filter的Servlet容器線程退出,但Response仍然開放。
  4. application通過多線程返回DeferredResult中sets值.並且Spring MVC分發request給Servlet容器.
  5. DispatcherServlet再次被調用並且繼續異步的處理產生的結果.

為進一步在異步請求處理動機的背景,並且when或者why使用它請看 this blog post series .
異步請求的異常處理 HTTP Streaming等略. 詳見https://blog.csdn.net/u012410733/article/details/52124333 (推薦)

SpringMVC的配置

Spring MVC提供Java Config與MVC namespace作為選擇用來配置處理異步request.WebMvcConfigurer可以通過configureAsyncSupport來進行配置,而xml可以通過子元素來進行配置.

如果你不想依賴Servlet容器(e.g. Tomcat是10)配置的值,允許你配置異步請求默認的timeout值。你可以配置AsyncTaskExecutor用來包含Callable實例作為controller方法的返回值.強烈建議配置這個屬性,因為在默認情況下Spring MVC使用SimpleAsyncTaskExecutor。Spring MVC中Java配置與namespace允許你注冊CallableProcessingInterceptorDeferredResultProcessingInterceptor實例.

如果你想覆蓋DeferredResult的默認過期時間,你可以選擇使用合適的構造器.同樣的,對於Callable,你可以通過WebAsyncTask來包裝它並且使用相應的構造器來定制化過期時間.WebAsyncTask的構造器同樣允許你提供一個AsyncTaskExecutor.

原文地址:spring-framework-reference-4.2.6.RELEASE




4.2 iframe流(永久幀)

iframe方式是在頁面中插入一個隱藏的iframe,利用其src屬性在服務器和客戶端之間創建一條長連接,服務器向iframe傳輸數據(通常是HTML,內有負責插入信息的javascript),來實時更新頁面.
 function foreverFrame(url,callback){
      var iframe = body.appendChild(document.createElement("iframe"));
      iframe.style.display="none";
      iframe.src=url+"?callback=parent.foreverFrame.callback";
      this.callback = callback;
    }
只不過這里涉及父子iframe之間的通信,要注意跨域問題。關於iframe跨域問題,隔壁團隊有個不錯的實現方案。 見http://www.alloyteam.com/2013/11/the-second-version-universal-solution-iframe-cross-domain-communication/ 
然后服務器就發送一堆消息到iframe中
<script>
parent.foreverFrame.callback('hello world!');
</script>
<script>
parent.foreverFrame.callback('hello Mars!');
</script>

4.3 流(xhr流)

具體解決方案有XHR 流(xhr-multipart)、htmlfile
xhr流(XMLHttpRequest Streaming)也是通過標准的XMLHttpRequest對象獲得的,但是需要在readyState為3的時候去訪問數據,這樣就不必等待連接關閉之后再操作數據。
參考代碼
function xhrStreaming(url, callback) {
    var xhr = new XMLHttpRequest();
    xhr.open('post', url, true);
    //保存上次返回的文檔位置
    var lastSize;
    xhr.onreadystatechange = function() {
        var newResponseText = "";
        if (xhr.readyState > 2) { 
            newResponseText = xhr.responseText.slice(lastSize);
            lastSize = xhr.responseText.length;
            callback(newResponseText);
        }
        if (xhr.readyState == 4) {
            xhrStreaming(url, callback);
        }
    }
    xhr.send(null);
}
其實跟永久幀的方法也類似,只不過是把iframe獲取內容的方式改成了ajax,然后在xhr內部處理增量邏輯、回調和重發。
這里需要注意的是鏈接時間需要有超時限制,否則內存性能會受到影響,另外單個請求返回數據需要限定長度,不能無限增大。

注意:
不管是長輪詢還是流,請求都需要在服務器上存在一段較長時間,因此Comet被稱為"基於HTTP長連接的服務器推技術"。這打破了每個請求一個線程的模型。這個模型顯然對Comet不適用。所以服務端這邊Java對此提出了非阻塞IO(non-blocking IO)解決方案, Java 通過它的NIO庫提供非阻塞IO處理Comet。
Tomcat配置server.xml, 即啟用異步版本的IO連接器
protocol="org.apache.coyote.http11.Http11NioProtocol"
后台請求處理以servlet為例, 通過 servlet 實現 CometProcessor 接口。這個接口要求實現 event() 方法,在配置的 Http11NioProtocol 調用 event() 方法來處理請求,而不是 doGet 或 doPost。
服務器端代碼實現略.

WebSocket 



Ajax
WebSocket是html5規范新引入的功能 是基於 TCP 的雙向的、全雙工的 socket 連接。(是獨立的、創建在 TCP 上的協議。).
WebSocket 用於解決瀏覽器與后台服務器雙向通訊的問題,使用WebSocket技術,后台可以隨時向前端推送消息,以保證前后台狀態統一,在傳統的無狀態HTTP協議中,這是“無法做到”的。在WebSocke推出以前,服務端向客戶端推送消息的方式都以曲線救國的輪詢方式(  Comet 或輪詢 )為主。


WebSocket不屬於http無狀態協議,協議名為”ws”,這意味着一個websocket連接地址會是這樣的寫法:ws://twaver.com:8080/webSocketServer。ws不是http,所以傳統的web服務器不一定支持,需要服務器與瀏覽器同時支持, WebSocket才能正常運行,目前的支持還不普遍,需要特別的web服務器和現代的瀏覽器。

現在我們來看一下都有哪些瀏覽器支持 WebSocket:
Chrome >= 4
Safari >= 5
iOS >= 4.2
Firefox >= 4*
Opera >= 11*
檢測瀏覽器是否支持 WebSocket 也非常簡單、直接:
var supported = ("WebSocket" in window);
if (supported) alert("WebSockets are supported");
Websocket 通過 HTTP/1.1 協議的101狀態碼進行握手。為了創建Websocket連接,需要通過瀏覽器發出請求,之后服務器進行回應,這個過程通常稱為“握手”(handshaking)。

利用HTTP完成握手有幾個好處。首先,讓WebSockets與現有HTTP基礎設施兼容:WebSocket服務器可以運行在80和443 端口上,這通常是對客戶端唯一開放的端口。其次,讓我們可以重用並擴展HTTP的Upgrade流,為其添加自定義的WebSocket首部,以完成協商。

5.1 WebSocket API

瀏覽器提供的WebSocket API很簡單,使用時無需關心連接管理和消息處理等底層細節,只需要發起連接,綁定相應的事件回調即可。

var connection = new WebSocket('ws://localhost:8080');
// When the connection is open, send some data to the server connection.onopen = function () { connection.send('Ping'); // Send the message 'Ping' to the server }; // Log errors connection.onerror = function (error) { console.log('WebSocket Error ' + error); }; // Log messages from the server connection.onmessage = function (e) { console.log('Server: ' + e.data); };
WebSocket資源URL采用了自定議模式,沒有使用http是為了在非http協議場景下也能使用,wss表示使用加密信道通信(TCP + TLS),支持接收和發送文本和二進制數據。
請求頭信息
Connection:Upgrade Sec-WebSocket-Key:eDCPPyPQZq7PiwRcx8SPog== Sec-WebSocket-Version:13 Upgrade:websocket
響應頭信息
HTTP/1.1 101 Switching Protocols
Upgrade:websocket
Connection:upgrade
Sec-WebSocket-Accept:QJsTRym36zHnArQ7FCmSdPhuK78=

// Connection:upgrade 升級被服務器同意
// Upgrade:websocket 指示客戶端升級到websocket
// Sec-WebSocket-Accept:參考上面請求的Sec-WebSocket-Key的注釋
最后,前述握手完成后,如果握手成功,該連接就可以用作雙向通信信道交換WebSocket消息。到此,客戶端與服務器之間不會再發生HTTP通信,一切由WebSocket 協議接管。

使用場景
適合於對數據的實時性要求比較強的場景,如通信、股票、Feed、直播、共享桌面,特別適合於客戶端與服務頻繁交互的情況下,如實時共享、多人協作等平台。

優點
  • 真正的全雙工通信
  • 支持跨域設置(Access-Control-Allow-Origin)
缺點
  • 采用新的協議,后端需要單獨實現
  • 客戶端並不是所有瀏覽器都支持
  • 代理服務器會有不支持websocket的情況
  • 無超時處理
  • 更耗電及占用資源

TIP 代理、很多現有的HTTP中間設備可能不理解新的WebSocket協議,而這可能導致各種問題,使用時需要注意,可以使借助TLS,通過建立一條端到端的加密信道,可以讓WebSocket通信繞過所有中間代理。

5.2 WebSocket在Java中

JavaEE 7的JSR-356:Java API for WebSocket,已經對WebSocket做了支持。不少Web容器,如Tomcat、Jetty等都支持WebSocket。Tomcat從7.0.27開始支持WebSocket,從7.0.47開始支持JSR-356。

待續




SSE

待續

參考


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM