WebSocket實(shí)踐

WebSocket

1 WebSocket概述

1)WebSocket是一種網(wǎng)絡(luò)通信協(xié)議,是HTML5開始提供的一種在單個(gè)TCP連接上進(jìn)行全雙工通信的協(xié)議;是為了兼容現(xiàn)有瀏覽器的握手規(guī)范;

2)是一種瀏覽器與服務(wù)器進(jìn)行全雙工通信的網(wǎng)絡(luò)技術(shù),屬于應(yīng)用層協(xié)議,基于TCP傳輸協(xié)議,并復(fù)用HTTP的握手通道;

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

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

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

2 WebSocket與HTTP協(xié)議

1)HTTP協(xié)議只能由客戶端發(fā)起通信,這種單向請求的特點(diǎn),帶來的問題是如果服務(wù)器有連續(xù)的狀態(tài)變化,客戶端獲知非常麻煩,只能用輪詢的方式,每隔一段時(shí)間,發(fā)出一個(gè)詢問,了解服務(wù)器有沒有新的信息,這種效率比較低,浪費(fèi)資源;

2)websocket是一個(gè)持久化的協(xié)議;而HTTP是非持久化協(xié)議;

3)HTTP1.0生命周期是通過Request界定,一個(gè)Request一個(gè)Response,則請求就結(jié)束了;HTTP1.1中有一個(gè)keep-alive,在一個(gè)HTTP連接中,可以發(fā)送多個(gè)Request,接收多個(gè)Response,Response和Request對應(yīng)的,且Response是被動(dòng)的,不能主動(dòng)發(fā)起;

4)http是一個(gè)無狀態(tài)協(xié)議;

引用圖1

3 WebSocket特點(diǎn)

3.1 優(yōu)點(diǎn)

1)服務(wù)器可以主動(dòng)向客戶端推送信息,客戶端也可以主動(dòng)向服務(wù)器發(fā)送信息,是真正的雙向平等對話,屬于服務(wù)器推送技術(shù)的一種;

2)支持雙向通信,實(shí)時(shí)性更強(qiáng);

3)更好的二進(jìn)制支持;

4)較少的控制開銷。連接創(chuàng)建后,ws客戶端、服務(wù)端進(jìn)行數(shù)據(jù)交換時(shí),協(xié)議控制的數(shù)據(jù)包頭部較小。在不包含頭部的情況下,服務(wù)端到客戶端的包頭只有2~10字節(jié)(取決于數(shù)據(jù)長度),客戶端到服務(wù)端的話,需要加上額外的4字節(jié)的掩碼。而HTTP協(xié)議每次通信都需要攜帶完整的頭部。

5)支持?jǐn)U展。ws協(xié)議定義了擴(kuò)展,用戶可以擴(kuò)展協(xié)議,或者事項(xiàng)自定義的子協(xié)議。(比如支持自定義壓縮算法等)

3.2 舉例

客戶端發(fā)起:

引用圖2

服務(wù)端回復(fù):服務(wù)端返回內(nèi)容如下,狀態(tài)代碼101表示協(xié)議切換。到此完成協(xié)議升級,后續(xù)的數(shù)據(jù)交互都按照新的協(xié)議來

引用圖3

? Connection: Upgrade:表示要升級協(xié)議

? Upgrade: websocket:表示要升級到websocket協(xié)議。

? Sec-WebSocket-Version: 13:表示websocket的版本。如果服務(wù)端不支持該版本,需要返回一個(gè)Sec-WebSocket-Versionheader,里面包含服務(wù)端支持的版本號。

? Sec-WebSocket-Key:與后面服務(wù)端響應(yīng)首部的Sec-WebSocket-Accept是配套的,提供基本的防護(hù),比如惡意的連接,或者無意的連接。

4 WebSocket原理

4.1 其他方式的被動(dòng)性

1)ajax輪詢:讓瀏覽器每隔幾秒就發(fā)送一次請求,詢問服務(wù)器是否有信息;


引用敘述1

2)long poll:類似于ajax輪詢,采取阻塞模型(一直打電話,沒收到對方回應(yīng)就不掛電話),客戶端發(fā)起連接后,如果沒信息,就一直不返回Response給客戶端,直到有消息才返回,然后客戶端再次建立連接;

引用敘述2

3)websocket:只需要經(jīng)過一次HTTP請求,就可以不斷的互通消息;


引用敘述3

4.2 websocket的產(chǎn)生

1)ajax輪詢需要服務(wù)器有很快的處理速度和資源;long poll需要有很高的并發(fā),及同時(shí)接待客戶的能力;

2)websocket在服務(wù)器完成協(xié)議升級后(HTTP->websocket),服務(wù)端就可以主動(dòng)推送消息給客戶端;

3)只需要經(jīng)過一次HTTP請求,就可以不斷的互通消息;解決了服務(wù)器消耗資源以及同步延遲問題;

5 常用屬性

5.1 @WebSocketEndpoint

注解是一個(gè)類層次的注解,它的功能主要是將目前的類定義成一個(gè)websocket服務(wù)器端。注解的值將被用于監(jiān)聽用戶連接的終端訪問URL地址。

5.2 @onOpen

打開一個(gè)新連接,即有新連接時(shí),會調(diào)用被此注解的方法。

5.3 @onClose

關(guān)閉連接時(shí)調(diào)用。

5.4 @onMessage

當(dāng)服務(wù)器接收到客戶端發(fā)送的消息時(shí)所調(diào)用的方法。

5.5 @PathParam

接收 uri參數(shù)的,與@PathVariable功能差不多,可通過url獲取對應(yīng)值

6 WebSocket 后端JAVA實(shí)現(xiàn)

6.1 pom文件依賴

 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>
依賴

6.2 運(yùn)行類

1)添加注解:

@EnableWebSocket

2)添加Bean:

@Bean
 public ServerEndpointExporter serverEndpointExporter() {
 return new ServerEndpointExporter();
 }
@Bean

6.3 WebSocket controller類

1)注解:

@ServerEndpoint(value = "/heartbeatMonitor/{userId}")
@Component

2)其他類注入方式:


注入

3)方法使用:

@ServerEndpoint(value = "/websocket/{usernick}")為例

1.  @OnOpen
2.  public void onOpen(@PathParam(value = "usernick") String userNick,Session session) {
3.  String message = "有新游客[" + userNick + "]加入聊天室!";
4.  log.info(message);
5.  WebSocketUtil.addSession(userNick, session);    
6.  //此時(shí)可向所有的在線通知 某某某登錄了聊天室 
7.  WebSocketUtil.sendMessageForAll(message);
8.  }

10.  @OnClose
11.  public void onClose(@PathParam(value = "usernick") String userNick,Session session) {
12.  String message = "游客[" + userNick + "]退出聊天室!";
13.  log.info(message);
14.  WebSocketUtil.remoteSession(userNick);  
15.  //此時(shí)可向所有的在線通知 某某某登錄了聊天室 
16.  WebSocketUtil.sendMessageForAll(message);
17.  }
19.  @OnMessage
20.  public void OnMessage(@PathParam(value = "usernick") String userNick, String message) {
21.  //類似群發(fā)
22.  String info = "游客[" + userNick + "]:" + message;
23.  log.info(info);
24.  WebSocketUtil.sendMessageForAll(message);
25.  }
27.  @OnError
28.  public void onError(Session session, Throwable throwable) {
29.  log.error("異常:", throwable);
30.  try {
31.  session.close();
32.  } catch (IOException e) {
33.  e.printStackTrace();
34.  }
35.  throwable.printStackTrace();
36.  }
websocket方法

6.4 測試

http://coolaf.com/tool/chattest

1)連接


websocket open

2)發(fā)送消息


websocket onMessage
?著作權(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)容

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