<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Spring Boot中的WebSocket

          共 8772字,需瀏覽 18分鐘

           ·

          2023-03-08 02:55

          須彌零一

          Spring Boot中的WebSocket

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

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

          簡(jiǎn)介

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

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

          特點(diǎn)

          • ? 較少的控制開(kāi)銷。相對(duì)于HTTP請(qǐng)求每次都要攜帶完整的頭部,開(kāi)銷顯著減少了。

          • ? 更強(qiáng)的實(shí)時(shí)性。由于協(xié)議是全雙工的,所以服務(wù)器可以隨時(shí)主動(dòng)給客戶端下發(fā)數(shù)據(jù)。

          • ? 保持連接狀態(tài)。Websocket需要先創(chuàng)建連接,是一種有狀態(tài)的協(xié)議,之后通信時(shí)可以省略部分狀態(tài)信息。而HTTP請(qǐng)求可能需要在每個(gè)請(qǐng)求都攜帶狀態(tài)信息(如身份認(rèn)證等)。

          • ? 更好的二進(jìn)制支持。Websocket定義了二進(jìn)制幀,相對(duì)HTTP,可以更輕松地處理二進(jìn)制內(nèi)容。

          • ? 可以支持?jǐn)U展。Websocket定義了擴(kuò)展,用戶可以擴(kuò)展協(xié)議、實(shí)現(xiàn)部分自定義的子協(xié)議。如部分瀏覽器支持壓縮等。

          • ? 更好的壓縮效果。相對(duì)于HTTP壓縮,Websocket在適當(dāng)?shù)臄U(kuò)展支持下,可以沿用之前內(nèi)容的上下文,在傳遞類似的數(shù)據(jù)時(shí),可以顯著地提高壓縮率。

          在SpringBoot項(xiàng)目中創(chuàng)建WebSocket Server

          項(xiàng)目依賴(Maven)

          <project xmlns="http://maven.apache.org/POM/4.0.0">
              <modelVersion>4.0.0</modelVersion>
              <groupId>cn.jeremysong</groupId>
              <artifactId>demo</artifactId>
              <version>1.0</version>

              <parent>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-starter-parent</artifactId>
                  <version>3.0.3</version>
              </parent>
              <dependencies>
                  <dependency>
                      <groupId>org.springframework.boot</groupId>
                      <artifactId>spring-boot-starter-websocket</artifactId>
                      <version>3.0.3</version>
                  </dependency>
              </dependencies>
          </project>

          WebSocket服務(wù)

          import org.springframework.context.annotation.Bean;
          import org.springframework.stereotype.Component;
          import org.springframework.web.socket.server.standard.ServerEndpointExporter;

          /**
           * ServerEndpointExporter 作用
           *
           * 這個(gè)Bean會(huì)自動(dòng)注冊(cè)使用@ServerEndpoint注解聲明的websocket endpoint
           *
           */

          @Component
          public class WebSocketConfig {

              @Bean
              public ServerEndPointExporter serverEndPointExporter() {
                  return new ServerEndPointExporter();
              }
          }
          import lombok.extern.slf4j.Slf4j;
          import org.springframework.stereotype.Component;

          import javax.websocket.OnClose;
          import javax.websocket.OnMessage;
          import javax.websocket.OnOpen;
          import javax.websocket.Session;
          import javax.websocket.server.PathParam;
          import javax.websocket.server.ServerEndpoint;
          import java.io.IOException;
          import java.util.concurrent.ConcurrentHashMap;

          @Slf4j
          @Component
          @ServerEndpoint("/websocket/{name}")
          public class WebSocket {

              private Session session;

              private String name;

              private static ConcurrentHashMap<String, WebSocket> webSocketSet = new ConcurrentHashMap<>();

              @OnOpen
              public void onOpen(Session session, @PathParam(value = "name") String name) {
                  this.session = session;
                  this.name = name;
                  webSocketSet.put(name, this);
              }

              @OnClose
              public void onClose() {
                  webSocketSet.remove(this.name);
              }

              @OnMessage
              public void onMessage(String message) {
                  log.info("{} send {}", this.name, message);
              }

              /**
               * 群發(fā)
               * @param message 消息內(nèi)容
               */

              public void groupSending(String message) {
                  for (String name : webSocketSet.keySet()) {
                      try {
                          webSocketSet.get(name).session.getBasicRemote().sendText(message);
                      } catch (IOException e) {
                          e.printStackTrace();
                      }
                  }
              }

              /**
               * 指定發(fā)動(dòng)消息
               * @param name 指定的客戶端名
               * @param message 消息內(nèi)容
               */

              public void appointSending(String name, String message) {
                  try {
                      webSocketSet.get(name).session.getBasicRemote().sendText(message);
                  } catch (IOException e) {
                      e.printStackTrace();
                  }
              }
          }

          使用JavaScript創(chuàng)建WebSocket Client

          WebSocket客戶端

          let websocket = null;

          if ('WebSocket' in window) {
              websocket = new WebSocket('ws://localhost:8888/websocket/cli-1');
              
              websocket.onopen = function () {
                  console.log('連接成功');
              };
              websocket.onclose = function () {
                  console.log('退出連接');
              };
              websocket.onmessage = function (event) {
                  console.log('收到消息:' + event.data);
              };
              websocket.onerror = function () {
                  console.log('連接出錯(cuò)');
              };
              
              // MDN Example
              websocket.addEventListener('open', function (event) {
                  websocket.send('Hello Server!');
              });
              websocket.addEventListener('message', function (event) {
                  console.log('Message from server ', event.data);
              });
              websocket.addEventListener('error', function (event) {
                  console.log('WebScoket error: ', event);
              });
          }

          window.onbeforeunload = function () {
              // 頁(yè)面關(guān)閉時(shí)關(guān)閉WebSocket連接
              websocket.close(1000);
          };

          在Chrome console中測(cè)試

          執(zhí)行如下命令時(shí)可以在Server端添加日志輸出和debug觀察交互現(xiàn)象。

          > ws1 = new WebSocket('ws://localhost:8888/websocket/name1');
          > ws1.send('Send message to server! I am name1');

          > 
          ws2 = new WebSocket('ws://localhost:8888/websocket/name2');
          > ws2.send('Send message to server! I am name2');

          > 
          ws1.close(1000);
          > ws2.close(1000);

          參考

          • WebSocket - MDN:  

            https://developer.mozilla.org/zh-CN/docs/Web/API/WebSocket
          • CloseEvent - MDN:  

            https://developer.mozilla.org/zh-CN/docs/Web/API/CloseEvent#status_codes

          ---- END ----

          歡迎關(guān)注我的公眾號(hào)“須彌零一”,原創(chuàng)技術(shù)文章第一時(shí)間推送。

          瀏覽 83
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  一级黄色H片在线播放 | 日韩成人app | 稀缺小u女呦品呦cB | 天天色色插插综合视频 | 爱搞|