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

溫馨提示×

溫馨提示×

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

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

WebSocket如何實現服務器消息推送客戶端

發布時間:2021-11-20 15:38:41 來源:億速云 閱讀:428 作者:小新 欄目:編程語言

這篇文章主要為大家展示了“WebSocket如何實現服務器消息推送客戶端”,內容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領大家一起研究并學習一下“WebSocket如何實現服務器消息推送客戶端”這篇文章吧。

  一、背景

  項目需要做一個消息能夠實時獲取的功能,系統日活躍量達到10000,產生的消息是活躍量的數倍,如果采用 Http 的方式輪詢后端服務,會使得后端服務壓力過大而奔潰,因此需要一種新的技術方式來改變 “拉” 的方式。

  二、解決方案

  經過各種 Google、百度 后發現可以使用 html5 的新技術 WebSocket ,將現有 “拉”消息的方式改變成 “推” 的模式,大大的減少服務器壓力。

  三、具體實現

  實例采用 Spring Boot 框架,

  引入 pom 依賴

  org.springframework.boot

  spring-boot-starter-websocket

  org.springframework.boot

  spring-boot-starter-undertow

  org.springframework.boot

  spring-boot-starter-web

  org.springframework.boot

  spring-boot-starter-tomcat

  WebSocket 服務可采用 websocket-api 或 spring-websocket 開發,我們采用 websocket-api 的注解開發方式:

  package com.gridsum.techpub.systemhistory.api.server;

  import org.slf4j.Logger;

  import org.slf4j.LoggerFactory;

  import org.springframework.stereotype.Service;

  import javax.websocket.*;

  import javax.websocket.server.PathParam;

  import javax.websocket.server.ServerEndpoint;

  import java.io.IOException;

  import java.util.Objects;

  import java.util.Set;

  import java.util.concurrent.CopyOnWriteArraySet;

  /**

  * @author ouyangrongtao

  * @version 1.0

  * @description WebSocketServer

  * @date 2019/12/23 10:16

  **/

  @ServerEndpoint("/websocket/{sid}")

  @Service

  public class WebSocketServer {

  private static final Logger logger = LoggerFactory.getLogger(WebSocketServer.class);

  private ClientInfo clientInfo;

  /**

  * 存放每個客戶端對應的 ClientInfo 對象。

  */

  private static final Set WEB_SOCKET_SET = new CopyOnWriteArraySet<>();

  /**

  * 連接建立成功調用的方法

  *

  * @param session 會話

  * @param sid 客戶端

  */

  @OnOpen

  public void onOpen(Session session, @PathParam("sid") String sid) {

  //加入set中

  this.clientInfo = new ClientInfo(sid, session);

  WEB_SOCKET_SET.add(clientInfo);

  logger.info("有新窗口開始監聽:[{}],當前在線人數為[{}]", sid, WEB_SOCKET_SET.size());

  try {

  this.sendMessage(session, "連接成功");

  } catch (IOException e) {

  logger.error("websocket IO異常");

  }

  }

  /**

  * 連接關閉調用的方法

  */

  @OnClose

  public void onClose() {

  //從set中刪除

  WEB_SOCKET_SET.remove(this.clientInfo);

  logger.info("有一連接關閉!當前在線人數為:[{}]", WEB_SOCKET_SET.size());

  }

  /**

  * 

  * @param message 客戶端發送過來的消息

  */

  @OnMessage

  public void onMessage(String message) {

  logger.info("收到來自窗口[{}]的信息:[{}]", this.clientInfo.getSid(), message);

  //發消息

  for (ClientInfo item : WEB_SOCKET_SET) {

  try {

  this.sendMessage(item.getSession(), message);

  } catch (IOException ignored) {

  }

  }

  }

  /**

  * 錯誤時調用

  * @param session 會話

  * @param error 錯誤信息

  */

  @OnError

  public void onError(Session session, Throwable error) {

  logger.error("發生錯誤", error);

  }

  /**

  * 給 sid 發送消息

  * @param message 消息

  * @param sid sid

  */

  public void sendMessage(String message, String sid) {

  logger.info("推送消息到窗口[{}],推送內容:[{}]", sid, message);

  ClientInfo client = WEB_SOCKET_SET.parallelStream()

  .filter(item -> item.getSid().equals(sid)).findFirst().orElse(null);

  if (client != null) {

  try {

  this.sendMessage(client.getSession(), message);

  } catch (IOException ignored) {

  }

  }

  }

  /**

  * 實現服務器主動推送

  * @param session session

  * @param message message

  * @throws IOException IOException

  */鄭州哪個婦科醫院好 http://www.sptdfk.com/

  private void sendMessage(Session session, String message) throws IOException {

  session.getBasicRemote().sendText(message);

  }

  class ClientInfo {

  /**

  * 接收sid

  */

  private String sid = "";

  /**

  * 客戶端

  */

  private Session session;

  public ClientInfo() { }

  private ClientInfo(String sid, Session session) {

  this.sid = sid;

  this.session = session;

  }

  private String getSid() {

  return sid;

  }

  private Session getSession() {

  return session;

  }

  @Override

  public boolean equals(Object o) {

  if (this == o) {

  return true;

  }

  if (o == null || getClass() != o.getClass()) {

  return false;

  }

  ClientInfo that = (ClientInfo) o;

  return Objects.equals(sid, that.sid);

  }

  @Override

  public int hashCode() {

  return Objects.hash(sid);

  }

  }

  }

  前端代碼

  運行 WebSocketClient1000001

  來一個發消息的接口

  /**

  * 發送消息給客戶端

  * @author ouyangrongtao

  */

  @RestController

  public class WebSocketController {

  private WebSocketServer webSocketServer;

  @Autowired

  public WebSocketController(WebSocketServer webSocketServer) {

  this.webSocketServer = webSocketServer;

  }

  @PostMapping("/socket/push")

  public boolean pushToWeb(@RequestBody Map content) {

  webSocketServer.sendMessage(content.get("message"), content.get("cid"));

  return true;

  }

  }

  到此已經基本寫完。使用 Postman 調用發消息的接口,發現客戶端可以收到發送的消息。

  四、問題記錄

  在做的時候,因為項目用的 Tomcat 容器,導致 Tomcat 相關包與 WebSocket 依賴有沖突,最終項目不能啟動,解決方式只需要將 Tomcat 容器改為 Undertow 。

  org.springframework.boot

  spring-boot-starter-undertow

  org.springframework.boot

  spring-boot-starter-web

  org.springframework.boot

  spring-boot-starter-tomcat

  異常信息:

  Caused by: java.lang.IllegalStateException: javax.websocket.server.ServerContainer not available

  at org.springframework.util.Assert.state(Assert.java:73)

  at org.springframework.web.socket.server.standard.ServerEndpointExporter.afterPropertiesSet(ServerEndpointExporter.java:106)

  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1753)

  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1690)

  ... 16 common frames omitted

以上是“WebSocket如何實現服務器消息推送客戶端”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!

向AI問一下細節

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

AI

伊金霍洛旗| 太保市| 磐安县| 嘉荫县| 鄂托克前旗| 论坛| 禹城市| 民和| 历史| 江阴市| 浪卡子县| 普兰店市| 北碚区| 隆子县| 虹口区| 博罗县| 丹棱县| 揭阳市| 左贡县| 冕宁县| 双流县| 图木舒克市| 育儿| 松潘县| 陆河县| 阜新市| 石楼县| 武功县| 虹口区| 礼泉县| 阿鲁科尔沁旗| 西青区| 嘉禾县| 陇南市| 句容市| 雷波县| 阿克| 开鲁县| 镶黄旗| 马关县| 梁河县|