HTML5 WebSocket

WebSocket protocol 是HTML5一種新的協(xié)議。它實(shí)現(xiàn)了瀏覽器與服務(wù)器全雙工通信(full-duplex)。一開始的握手需要借助HTTP請求完成。

——百度百科

什么是WebSocket

WebSocket 是 HTML5 開始提供的一種在單個(gè) TCP 連接上進(jìn)行全雙工通訊的協(xié)議。

原理

WebSocket 使得客戶端和服務(wù)器之間的數(shù)據(jù)交換變得更加簡單,允許服務(wù)端主動向客戶端推送數(shù)據(jù)。在 WebSocket API 中,瀏覽器和服務(wù)器只需要完成一次握手,兩者之間就直接可以創(chuàng)建持久性的連接,并進(jìn)行雙向數(shù)據(jù)傳輸。

在 WebSocket API 中,瀏覽器和服務(wù)器只需要做一個(gè)握手的動作,然后,瀏覽器和服務(wù)器之間就形成了一條快速通道。兩者之間就直接可以數(shù)據(jù)互相傳送。

連接過程
  1. 瀏覽器、服務(wù)器建立TCP連接,三次握手。這是通信的基礎(chǔ),傳輸控制層,若失敗后續(xù)都不執(zhí)行。
  2. TCP連接成功后,瀏覽器通過HTTP協(xié)議向服務(wù)器傳送WebSocket支持的版本號等信息。(開始前的HTTP握手)
  3. 服務(wù)器收到客戶端的握手請求后,同樣采用HTTP協(xié)議回饋數(shù)據(jù)。
  4. 當(dāng)收到了連接成功的消息后,通過TCP通道進(jìn)行傳輸通信。

目的

現(xiàn)在,很多網(wǎng)站為了實(shí)現(xiàn)推送技術(shù),所用的技術(shù)都是 Ajax 輪詢。輪詢是在特定的的時(shí)間間隔(如每1秒),由瀏覽器對服務(wù)器發(fā)出HTTP請求,然后由服務(wù)器返回最新的數(shù)據(jù)給客戶端的瀏覽器。這種傳統(tǒng)的模式帶來很明顯的缺點(diǎn),即瀏覽器需要不斷的向服務(wù)器發(fā)出請求,然而HTTP請求可能包含較長的頭部,其中真正有效的數(shù)據(jù)可能只是很小的一部分,顯然這樣會浪費(fèi)很多的帶寬等資源。

HTML5 定義的 WebSocket 協(xié)議,能更好的節(jié)省服務(wù)器資源和帶寬,并且能夠更實(shí)時(shí)地進(jìn)行通訊。

image.png

瀏覽器通過 JavaScript 向服務(wù)器發(fā)出建立 WebSocket 連接的請求,連接建立以后,客戶端和服務(wù)器端就可以通過 TCP 連接直接交換數(shù)據(jù)。

當(dāng)你獲取 Web Socket 連接后,你可以通過 send() 方法來向服務(wù)器發(fā)送數(shù)據(jù),并通過 onmessage 事件來接收服務(wù)器返回的數(shù)據(jù)。

以下 API 用于創(chuàng)建 WebSocket 對象。

var Socket = new WebSocket(url, [protocol] );

以上代碼中的第一個(gè)參數(shù) url, 指定連接的 URL。第二個(gè)參數(shù) protocol 是可選的,指定了可接受的子協(xié)議。

WebSocket與HTTP的關(guān)系

相同點(diǎn)
  • 1. 都是一樣基于TCP的,都是可靠性傳輸協(xié)議。
  • 2. 都是應(yīng)用層協(xié)議。
不同點(diǎn)
  • 1. WebSocket是雙向通信協(xié)議,模擬Socket協(xié)議,可以雙向發(fā)送或接受信息。HTTP是單向的。
  • 2. WebSocket是需要握手進(jìn)行建立連接的。
聯(lián)系

WebSocket在建立握手時(shí),數(shù)據(jù)是通過HTTP傳輸?shù)?。但是建立之后,在真正傳輸時(shí)候是不需要HTTP協(xié)議的。


WebSocket 屬性

以下是 WebSocket 對象的屬性。假定我們使用了以上代碼創(chuàng)建了 Socket 對象:

屬性 描述
Socket.readyState 只讀屬性 readyState 表示連接狀態(tài),可以是以下值: 0 - 表示連接尚未建立。1. 表示連接已建立,可以進(jìn)行通信。2. 表示連接正在進(jìn)行關(guān)閉。 3. 表示連接已經(jīng)關(guān)閉或者連接不能打開。
Socket.bufferedAmount 只讀屬性 bufferedAmount 已被 send() 放入正在隊(duì)列中等待傳輸,但是還沒有發(fā)出的 UTF-8 文本字節(jié)數(shù)。

WebSocket 事件

以下是 WebSocket 對象的相關(guān)事件。假定我們使用了以上代碼創(chuàng)建了 Socket 對象:

事件 事件處理程序 描述
open Socket.onopen 連接建立觸發(fā)
message Socket.onmessage 客戶端接收服務(wù)端數(shù)據(jù)時(shí)觸發(fā)
error Socket.onerror 通信發(fā)生錯(cuò)誤時(shí)觸發(fā)
close Socket.onclose 連接關(guān)閉時(shí)觸發(fā)

WebSocket 方法

以下是 WebSocket 對象的相關(guān)方法。假定我們使用了以上代碼創(chuàng)建了 Socket 對象:

方法 描述
Socket.send() 使用連接發(fā)送數(shù)據(jù)
Socket.close() 關(guān)閉連接

WebSocket實(shí)例

WebSocket 協(xié)議本質(zhì)上是一個(gè)基于 TCP 的協(xié)議。

為了建立一個(gè) WebSocket 連接,客戶端瀏覽器首先要向服務(wù)器發(fā)起一個(gè) HTTP 請求,這個(gè)請求和通常的 HTTP 請求不同,包含了一些附加頭信息,其中附加頭信息"Upgrade: WebSocket"表明這是一個(gè)申請協(xié)議升級的 HTTP 請求,服務(wù)器端解析這些附加的頭信息然后產(chǎn)生應(yīng)答信息返回給客戶端,客戶端和服務(wù)器端的 WebSocket 連接就建立起來了,雙方就可以通過這個(gè)連接通道自由的傳遞信息,并且這個(gè)連接會持續(xù)存在直到客戶端或者服務(wù)器端的某一方主動的關(guān)閉連接。

客戶端的 HTML 和 JavaScript

注意:websocket地址:ws://{ip}:{端口}/{工程名}/{ServerEndpoint路徑}}
地址使用localhost會出現(xiàn)如下錯(cuò)誤:
WebSocket connection to 'ws://localhost:8080/aidTibet/websocket' failed: Error during WebSocket handshake: Unexpected response code: 302

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>測試WebSocket</title>
        <script type="text/javascript">
            function WebSocketTest()
            {
                if ("WebSocket" in window)
                {
                    alert("您的瀏覽器支持WebScoket!")
                    
                    // 打開一個(gè)web socket
                    var ws = new WebSocket("ws://172.20.241.171:8080/websocket")
                    
                    ws.onopen = function(){
                        // web socket已連接上,使用 send() 發(fā)送數(shù)據(jù)
                        ws.send("發(fā)送數(shù)據(jù)")
                        alert("數(shù)據(jù)發(fā)送中...")
                    }
                    
                    ws.onmessage = function(evt){
                        var received_msg = evt.data
                        alert("數(shù)據(jù)已接收..." + received_msg)
                    }
                    
                    ws.onclose = function() {
                        // 關(guān)閉WebSocket
                        alert("連接已關(guān)閉...")
                    }
                } else {
                    // 瀏覽器不支持 WebSocket
                    alert("您的瀏覽器不支持 WebSocket!")
                }
            }
        </script>
        
    </head>
    <body>
        <div>
            <a href="javascript:WebSocketTest()">運(yùn)行 WebSocket</a>
        </div>
    </body>
</html>

服務(wù)端

服務(wù)端使用SpringBoot結(jié)合WebSocket的方式實(shí)現(xiàn)。

  1. 導(dǎo)入依賴
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
  1. 新建WebSocket配置類
@Configuration
public class WebsocketConfiguration {
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}
  1. 新建WebSocket服務(wù)端
@ServerEndpoint("/websocket")
@Component
@Slf4j
public class MyWebsocketServer {
    /**
     * 存放所有在線的客戶端
     */
    private static Map<String, Session> clients = new ConcurrentHashMap<>();

    @OnOpen
    public void onOpen(Session session) {
        log.info("有新的客戶端連接了: {}", session.getId());
        //將新用戶存入在線的組
        clients.put(session.getId(), session);
    }

    /**
     * 客戶端關(guān)閉
     * @param session session
     */
    @OnClose
    public void onClose(Session session) {
        log.info("有用戶斷開了, id為:{}", session.getId());
        //將掉線的用戶移除在線的組里
        clients.remove(session.getId());
    }

    /**
     * 發(fā)生錯(cuò)誤
     * @param throwable e
     */
    @OnError
    public void onError(Throwable throwable) {
        throwable.printStackTrace();
    }

    /**
     * 收到客戶端發(fā)來消息
     * @param message  消息對象
     */
    @OnMessage
    public void onMessage(String message) {
        log.info("服務(wù)端收到客戶端發(fā)來的消息: {}", message);
        this.sendAll(message);
    }

    /**
     * 群發(fā)消息
     * @param message 消息內(nèi)容
     */
    private void sendAll(String message) {
        for (Map.Entry<String, Session> sessionEntry : clients.entrySet()) {
            sessionEntry.getValue().getAsyncRemote().sendText(message);
        }
    }
}

啟動后,使用客戶端發(fā)送數(shù)據(jù):


image.png

參考:http://www.itdecent.cn/p/8c4983a3ca2e(包含創(chuàng)建連接時(shí)傳遞userId已區(qū)分不同客戶端)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • HTML5 WebSocket WebSocket 是 HTML5 開始提供的一種在單個(gè) TCP 連接上進(jìn)行全雙工...
    洛的俠閱讀 433評論 0 0
  • HTML5 WebSocket 作為新一代的web標(biāo)準(zhǔn),HTML5為我們提供了很多有用的東西,比如canvas,本...
    Srtian閱讀 7,606評論 0 9
  • 1、HTML5 WebSocket WebSocket 是 HTML5 開始提供的一種在單個(gè) TCP 連接上進(jìn)行全...
    maskerII閱讀 286評論 0 0
  • WebSocket是HTML5開始提供的一種在單個(gè)TCP連接上進(jìn)行全雙通訊的協(xié)議在WebSocket API中,瀏...
    龍飝閱讀 317評論 0 3
  • 參考阮一峰 WebSocket 教程WebSocket 是什么原理WebSocket 淺析 《WebSocket詳...
    合肥黑閱讀 757評論 0 2

友情鏈接更多精彩內(nèi)容