Java - WebSocket

一、WebSocket

1.1、WebSocket概念

WebSocket是一種協議,用于在Web應用程序和服務器之間建立實時、雙向的通信連接。它通過一個單一的TCP連接提供了持久化連接,這使得Web應用程序可以更加實時地傳遞數據。WebSocket協議最初由W3C開發,并于2011年成為標準。

1.2、WebSocket協議

WebSocket 協議是一種基于TCP的協議,用于在客戶端和服務器之間建立持久連接,并且可以在這個連接上實時地交換數據。WebSocket協議有自己的握手協議,用于建立連接,也有自己的數據傳輸格式。

當客戶端發送一個 WebSocket 請求時,服務器將發送一個協議響應以確認請求。在握手期間,客戶端和服務器將協商使用的協議版本、支持的子協議、支持的擴展選項等。一旦握手完成,連接將保持打開狀態,客戶端和服務器就可以在連接上實時地傳遞數據。

WebSocket 協議使用的是雙向數據傳輸,即客戶端和服務器都可以在任意時間向對方發送數據,而不需要等待對方的請求。它支持二進制數據和文本數據,可以自由地在它們之間進行轉換。

總之,WebSocket協議是一種可靠的、高效的、雙向的、持久的通信協議,它適用于需要實時通信的Web應用程序,如在線游戲、實時聊天等

1.3、WebSocket原理

WebSocket 生命周期描述了 WebSocket 連接從創建到關閉的過程。一個 WebSocket 連接包含以下四個主要階段:

  • 連接建立階段(Connection Establishment):在這個階段,客戶端和服務器之間的 WebSocket 連接被建立。客戶端發送一個 WebSocket 握手請求,服務器響應一個握手響應,然后連接就被建立了。
  • 連接開放階段(Connection Open):在這個階段,WebSocket 連接已經建立并開放,客戶端和服務器可以在連接上互相發送數據。
  • 連接關閉階段(Connection Closing):在這個階段,一個 WebSocket 連接即將被關閉。它可以被客戶端或服務器發起,通過發送一個關閉幀來關閉連接。
  • 連接關閉完成階段(Connection Closed):在這個階段,WebSocket 連接已經完全關閉。客戶端和服務器之間的任何交互都將無效

客戶端依靠發起HTTP握手,告訴服務端進行WebSocket協議通訊,并告知WebSocket協議版本。服務端確認協議版本,升級為WebSocket協議。之后如果有數據需要推送,會主動推送給客戶端

請求頭Request Headers

GET /test HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: sehfiowqweuq1psd==
Sec-WebSocket-Protocol: v10.stomp, v11.stomp, v12.stomp
Origin: http://hello.com
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
Sec-WebSocket-Version: 13

首先客戶端(如瀏覽器)發出帶有特殊消息頭(Upgrade、Connection)的請求到服務器,服務器判斷是否支持升級,支持則返回響應狀態碼101,表示協議升級成功,對于WebSocket就是握手成功。其中關鍵的字段就是Upgrade,Connection,告訴 Apache 、 Nginx 等服務器:注意啦,發起的是Websocket協議,不再 使用原先的HTTP。其中,Sec-WebSocket-Key當成是請求id就好了。

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HaA6EjhHRejpHyuO0yBnY4J4n3A=
Sec-WebSocket-Extensions: permessage-deflate;client_max_window_bits=15
Sec-WebSocket-Protocol: v12.stomp

Sec-WebSocket-Accept的字段值是由握手請求中的Sec-WebSocket-Key的字段值生成的。成功握手確立WebSocket連接之后,通信時不再使用HTTP的數據幀,而采用WebSocket獨立的數據幀

1.4、 應用場景

實時聊天:聊天應用需要實時的消息傳遞,WebSocket 提供了高效的解決方案。

在線游戲:游戲中的實時交互(例如玩家動作和狀態更新)可以通過 WebSocket 高效地處理。

股票市場:股票和金融市場應用需要實時更新數據,WebSocket 能夠提供實時行情和交易信息。

實時通知:例如社交網絡應用中的即時通知和更新。

協作應用:如實時文檔編輯和在線協作工具,可以使用 WebSocket 實現多用戶之間的同步更新。

WebSocket 協議在許多現代網絡應用中扮演了重要角色,特別是在需要高頻率數據交換和低延遲響應的場景中

1.5、WebSocket優劣勢

WebSocket優勢:

  • 實時性:由于WebSocket的持久化連接,它可以實現實時的數據傳輸,避免了Web應用程序需要不斷地發送請求以獲取最新數據的情況。
  • 雙向通信:WebSocket協議支持雙向通信,這意味著服務器可以主動向客戶端發送數據,而不需要客戶端發送請求。
  • 減少網絡負載:由于WebSocket的持久化連接,它可以減少HTTP請求的數量,從而減少了網絡負載。

WebSocket劣勢:

  • 需要瀏覽器和服務器都支持:WebSocket是一種相對新的技術,需要瀏覽器和服務器都支持。一些舊的瀏覽器和服務器可能不支持WebSocket。
  • 需要額外的開銷:WebSocket需要在服務器上維護長時間的連接,這需要額外的開銷,包括內存和CPU。
  • 安全問題:由于WebSocket允許服務器主動向客戶端發送數據,可能會存在安全問題。服務器必須保證只向合法的客戶端發送數據

1.6、http和websocket區別

(1)WebSocket是雙向通信協議,模擬Socket協議,可以雙向發送或接受信息;HTTP是單向的

(2)WebSocket是需要瀏覽器和服務器握手進行建立連接的;而HTTP是瀏覽器發起向服務器的連接,服務器預先并不知道這個連接

二、Java中使用WebSocket

2.1、Java WebSocket API編寫WebSocket

2.1.1、WebSocket服務器的搭建方法

在Java中搭建WebSocket服務器的方法如下:

1、首先,需要引入Java WebSocket API庫。可以從Maven倉庫下載Java WebSocket API依賴,或者直接將相關jar文件添加到項目中。

2、創建一個WebSocket服務器類,實現javax.websocket.Endpoint接口。這個類將作為WebSocket服務器的入口點,并定義了處理WebSocket連接和消息的方法。

3、在服務器類中,重寫以下方法:

@OnOpen:注解用于標記一個方法,當WebSocket與客戶端成功建立連接時,這個方法將被調用。

@OnMessage:注解標記的方法會在收到客戶端發送的消息時被調用。在示例中,收到消息后會打印消息內容,并將響應消息發送回客戶端。

@OnClose:注解標記的方法會在WebSocket關閉時被調用。

@OnError:注解標記的方法會在發生錯誤時被調用。

在類上使用@ServerEndpoint注解,將這個類聲明為一個WebSocket端點。/websocket是WebSocket的URI,客戶端可以通過這個URI來連接到這個WebSocket端點。

4、使用javax.websocket.server.ServerEndpoint注解標記服務器類,指定WebSocket的URL路徑。

5、創建一個WebSocket服務器容器類,用來啟動和管理WebSocket服務器。可以使用javax.websocket.server.ServerEndpointConfig的Builder類創建一個服務器配置對象,將服務器類和URL路徑關聯起來,并配置其他相關信息。

6、使用WebSocket服務器容器類的create方法創建一個WebSocket服務器實例。

7、啟動WebSocket服務器,可以使用Server.start()方法

import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;@ServerEndpoint("/websocket")
public class WebSocketServer {@OnOpenpublic void onOpen(Session session) {// 在連接打開時執行的操作}@OnClosepublic void onClose(Session session) {// 在連接關閉時執行的操作}@OnMessagepublic void onMessage(String message, Session session) {// 處理收到的消息}
}

編寫配置類

// 需要注入Bean的話必須聲明為配置類
@Configuration
public class WebSocketConfig {@Beanpublic ServerEndpointExporter serverEndpointExporter(){return new ServerEndpointExporter();}
}

?調用:

import javax.websocket.server.ServerEndpointConfig;public class WebSocketServerContainer {public static void main(String[] args) {ServerEndpointConfig serverConfig = ServerEndpointConfig.Builder.create(WebSocketServer.class, "/websocket").build();WebSocketContainer container = ContainerProvider.getWebSocketContainer();try {container.connectToServer(serverConfig, new URI("ws://localhost:8080/"));} catch (Exception e) {e.printStackTrace();}}
}

:這里監聽的地址不可以是 "ws" 不然會報錯,可能這是關鍵字吧,畢竟我們的協議就叫 ws?

2.1.2、Vue + JS 實現客戶端

<template><div class="app-container home"><el-row :gutter="20"><el-col :sm="24" :lg="24"><h1>集成websocket測試</h1></el-col></el-row><el-row :gutter="20"><el-col :sm="24" :lg="24"><div><el-input v-model="url" type="text" style="width: 20%" /> &nbsp;&nbsp;<el-button @click="join" type="primary">連接</el-button><el-button @click="exit" type="danger">斷開</el-button><el-button @click="resetForm" type="success">重置</el-button><br /><br /><el-input type="textarea" v-model="message" :rows="9" /><br /><br /><el-button type="success" @click="send">發送消息</el-button><br /><br />返回內容<el-input type="textarea" v-model="text_content" :rows="9" /><br /><br /></div></el-col></el-row></div>
</template><script>
import { getToken } from "@/utils/auth";export default {name: "Index",data() {return {url: "ws://127.0.0.1:8080/websocket/message",message: "",text_content: "",ws: null,headers: {Authorization: "Bearer " + getToken(),},};},methods: {join() {const wsuri = this.url;// this.ws = new WebSocket(wsuri);this.ws = new WebSocket(wsuri, [getToken()]);const self = this;// 連接成功后調用this.ws.onopen = function (event) {self.text_content = self.text_content + "WebSocket連接成功!" + "\n";};this.ws.onerror = function (event) {self.text_content = self.text_content + "WebSocket連接發生錯誤!" + "\n";};// 接收后端消息this.ws.onmessage = function (event) {self.text_content = self.text_content + event.data + "\n";};// 關閉連接時調用this.ws.onclose = function (event) {self.text_content = self.text_content + "已經關閉連接!" + "\n";};},exit() {if (this.ws) {this.ws.close();this.ws = null;}},send() {if (this.ws) {this.ws.send(this.message);} else {alert("未連接到服務器");}},//重置resetForm() {this.message = "";this.text_content = "";},},
};
</script>

2.2、Spring Boot集成WebSocket

2.2.1、添加依賴

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

2.2.2、配置WebSocket

應用程序中,需要配置WebSocket。創建一個新的Java類,并添加注。@ServerEndpoint(“/websocket”)。這將指定WebSocket服務端的端點。

在此類中,需要實現幾個方法:

import javax.websocket.OnClose;import javax.websocket.OnMessage;import javax.websocket.OnOpen;import javax.websocket.Session;import javax.websocket.server.ServerEndpoint;@ServerEndpoint("/websocket")
public class WebSocketServer {@OnOpenpublic void onOpen(Session session) {System.out.println("Connection opened: " + session.getId());sessions.add(session);}@OnMessagepublic void onMessage(Session session, String message) throws IOException {System.out.println("Received message: " + message);session.getBasicRemote().sendText("Server received: " + message);}@OnClosepublic void onClose(Session session) {System.out.println("Connection closed: " + session.getId());sessions.remove(session);}private static final Set<Session> sessions = Collections.synchronizedSet(new HashSet<Session>());
}

2.2.3、處理WebSocket消息

在@OnMessage方法中,可以處理WebSocket客戶端發送的消息,并向客戶端發送響應。下面是一個簡單的示例代碼:

@OnMessage
public void onMessage(Session session, String message) throws IOException {System.out.println("Received message: " + message);session.getBasicRemote().sendText("Server received: " + message);
}

在此代碼中,我們簡單地打印出收到的消息,并向客戶端發送響應。

關閉WebSocket連接

在@OnClose方法中,可以刪除連接并做一些清理工作。下面是一個示例代碼:

@OnClose
public void onClose(Session session) {System.out.println("Connection closed: " + session.getId());sessions.remove(session);
}

在此代碼中,我們從連接池中刪除連接,并打印出連接已關閉的消息。

配置WebSocket支持

最后,需要配置Spring Boot以支持WebSocket。創建一個新的Java類,并添加注釋@Configuration和@EnableWebSocket。然后,需要覆蓋方法registerWebSocketHandlers(),并指定WebSocket處理程序。下面是一個示例代碼:

import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {@Overridepublic void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {registry.addHandler(new WebSocketServer(), "/websocket").setAllowedOrigins("*");}
}

在此代碼中,我們創建了一個新的WebSocketServer對象,并將其添加到WebSocket處理程序中。我們還指定了WebSocket端點(/websocket)和允許的來源(*)。

三、PostMan調用

3.1、Websocket在線模擬請求工具

訪問訪問地址:http://www.jsons.cn/websocket/

具有進行連接、斷開、模擬發送數據等功能。

(請求時注意連接格式為 ws://IP或域名:端口(示例 ws://127.0.0.1:8089/websocket/devices)

3.2、Postman

使用新版的Postman

1、建立 WebSocket 連接

在 File–> New 頁面,選擇 WebSocket Request,即可創建一個 WebSocket 模擬請求。

2、模擬數據交互

在地址欄中輸入相應的 WebSocket 請求地址,點擊地址欄右側的 “Connect” 按鈕,即可建立連接。

連接建立成功后,在 Message 的信息欄中輸入模擬數據,點擊 “Send” 按鈕,即可與服務端進行數據交互。

優勢:

支持多種數據格式

如:Text、JSON、XML、HTML、Binary等;

支持對交互信息進行格式化顯示

如:Text、JSON、XML、HTML等;

支持對交互數據進行模糊搜索、篩選過濾、清空等操作;

交互數據按照時間倒序顯示,更便于查看最新的數據。

3、斷開 WebSocket 連接

如果調試結束,點擊地址欄右側的 “Disconnect” 按鈕,即可斷開與 WebSocket 服務端的連接

可參考

WebSocket詳解及使用教程:打造高效的實時通信(二)_利用websocket進行聊天-CSDN博客


Java中使用WebSocket的幾種方式_java_腳本之家

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/66589.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/66589.shtml
英文地址,請注明出處:http://en.pswp.cn/web/66589.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

stm32 no connect target

解決 STM32 報錯 “no target connected” 的方法 前言 stm32最小系統在下載程序是一直報錯&#xff1a;no target connected&#xff0c;試了很多辦法成功不了&#xff0c;最后將芯片擦除了才成功。 一、問題描述 當時是寫flash的時候寫到ST Link 存儲的地方了。 之后就不…

element的el-form-item的prop作用

這個在elemenui中介紹比較簡單&#xff0c;一般寫的時候照著例子寫&#xff0c;會正常運行。沒太注意porp到底有啥影響點。這次有點時間整理一下。 這個https://worktile.com/kb/p/3534641鏈接講述的要比一般csdn上的文章清晰。 總結&#xff1a; Vue表單驗證中的prop屬性用于指…

Open3D計算點云粗糙度(方法一)【2025最新版】

目錄 一、Roughness二、代碼實現三、結果展示博客長期更新,本文最近更新時間為:2025年1月18日。 一、Roughness 通過菜單欄的Tools > Other > Roughness找到該功能。 這個工具可以估計點云的“粗糙度”。 選擇一個或幾個點云,然后啟動這個工具。 CloudCompare只會詢問…

窺探QCC518x/308x系列與手機之間的藍牙HCI記錄與分析 - 手機篇

今天要介紹給大家的是, 當我們在開發高通耳機時如果遇到與手機之間相容性問題, 通常會用Frontline或Ellisys的Bluetooth Analyzer來截取資料分析, 如果手邊沒有這樣的儀器, 要如何窺探Bluetooth的HCI log.這次介紹的是手機篇. 這次跟QCC518x/QCC308x測試的手機是Samsung S23 U…

【論文投稿】Python 網絡爬蟲:探秘網頁數據抓取的奇妙世界

目錄 前言 一、Python—— 網絡爬蟲的絕佳拍檔 二、網絡爬蟲基礎&#xff1a;揭開神秘面紗 &#xff08;一&#xff09;工作原理&#xff1a;步步為營的數據狩獵 &#xff08;二&#xff09;分類&#xff1a;各顯神通的爬蟲家族 三、Python 網絡爬蟲核心庫深度剖析 &…

前端炫酷動畫--圖片(一)

目錄 一、四角線框的跟隨移動 二、元素倒影(-webkit-box-reflect) 三、模特換裝(maskblend) 四、元素平滑上升 五、無限視差滾動 六、判斷鼠標進入方向(輪播方向) 七、環形旋轉效果 八、黑白小球交替旋轉 九、hover時圓形放大 十、畫一棵隨機樹(canvas) 十一、代碼雨…

STL--list(雙向鏈表)

目錄 一、list 對象創建 1、默認構造函數 2、初始化列表 3、迭代器 4、全0初始化 5、全值初始化 6、拷貝構造函數 二、list 賦值操作 1、賦值 2、assign&#xff08;迭代器1&#xff0c;迭代器2&#xff09; 3、assign&#xff08;初始化列表&#xff09; 4、assig…

【語言處理和機器學習】概述篇(基礎小白入門篇)

前言 自學筆記&#xff0c;分享給語言學/語言教育學方向的&#xff0c;但對語言數據處理感興趣但是尚未入門&#xff0c;卻需要在論文中用到的小伙伴&#xff0c;歡迎大佬們補充或繞道。ps&#xff1a;本文不涉及公式講解&#xff08;文科生小白友好體質&#xff09;&#xff…

小程序獲取微信運動步數

1、用戶點擊按鈕&#xff0c;在小程序中觸發getuserinfo方法&#xff0c;獲取用戶信息 <scroll-view class"scrollarea" scroll-y type"list"><view class"container"><button bind:tap"getLogin">獲取</button&…

leetcode——找到字符串中所有字母異位詞(java)

給定兩個字符串 s 和 p&#xff0c;找到 s 中所有 p 的 異位詞 的子串&#xff0c;返回這些子串的起始索引。不考慮答案輸出的順序。 示例 1: 輸入: s "cbaebabacd", p "abc" 輸出: [0,6] 解釋: 起始索引等于 0 的子串是 "cba", 它是 "…

LDN的藍牙雙模鍵盤幫助文檔

文檔索引 已支持的PCB列表(僅列出少部分)&#xff1a;鍵盤特性硬件軟件鍵盤以及驅動藍牙模式USB模式 驅動功能介紹主界面鍵盤列表頁面鍵盤配置&#xff08;使用雙模鍵盤的請務必細看本說明&#xff09;功能層配置(改鍵)觸發層配置(改FN鍵等觸發功能)功能選擇&#xff08;重要&a…

STM32 FreeRTOS 信號量

信號量的簡介 reeRTOS中的信號量是一種用于任務間同步和資源管理的機制。信號量可以是二進制的&#xff08;只能取0或1&#xff09;也可以是計數型的&#xff08;可以是任意正整數&#xff09;。信號量的基本操作包括“獲取”和“釋放”。 比如動車上的衛生間&#xff0c;一個…

Android SystemUI——系統快捷設置面板(十三)

通過前面的內容我們了解了 SystemUI 的啟動流程以及相關組件的加載流程,同時也詳細介紹了導航欄的創建和加載流程,對于 SystemUI 的組件來說,除了導航欄之外,下拉快捷設置面板也是比較重要的一個組件。 一、快捷設置面板 快捷設置面板(Quick Settings, QS)是 Android 系…

C 語言雛啟:擘畫代碼乾坤,諦觀編程奧宇之初瞰

大家好啊&#xff0c;我是小象?(?ω?)? 我的博客&#xff1a;Xiao Xiangζ????? 很高興見到大家&#xff0c;希望能夠和大家一起交流學習&#xff0c;共同進步。* 這一課主要是讓大家初步了解C語言&#xff0c;了解我們的開發環境&#xff0c;main函數&#xff0c;庫…

VSCode下EIDE插件開發STM32

VSCode下STM32開發環境搭建 本STM32教程使用vscode的EIDE插件的開發環境&#xff0c;完全免費&#xff0c;有管理代碼文件的界面&#xff0c;不需要其它IDE。 視頻教程見本人的 VSCodeEIDE開發STM32 安裝EIDE插件 Embedded IDE 嵌入式IDE 這個插件可以幫我們管理代碼文件&am…

Linux內核編程(二十一)USB驅動開發

一、驅動類型 USB 驅動開發主要分為兩種&#xff1a;主機側的驅動程序和設備側的驅動程序。一般我們編寫的都是主機側的USB驅動程序。 主機側驅動程序用于控制插入到主機中的 USB 設備&#xff0c;而設備側驅動程序則負責控制 USB 設備如何與主機通信。由于設備側驅動程序通常與…

論文筆記-arXiv2025-A survey about Cold Start Recommendation

論文筆記-arXiv2025-Cold-Start Recommendation towards the Era of Large Language Models: A Comprehensive Survey and Roadmap 面向大語言模型&#xff08;LLMs&#xff09;時代的冷啟動推薦&#xff1a;全面調研與路線圖1.引言2.前言3.內容特征3.1數據不完整學習3.1.1魯棒…

C#使用WMI獲取控制面板中安裝的所有程序列表

C#使用WMI獲取控制面板中安裝的所有程序列表 WMI 全稱Windows Management Instrumentation,Windows Management Instrumentation是Windows中用于提供共同的界面和對象模式以便訪問有關操作系統、設備、應用程序和服務的管理信息。如果此服務被終止&#xff0c;多數基于 Windo…

風光并網對電網電能質量影響的matlab/simulink仿真建模

這個課題早在一幾年的時候比較熱門&#xff0c;之前作電科院配電網的一個項目中也有所涉及&#xff0c;我把其中一部分經典仿真模型思路分享給大家&#xff0c;電能質量影響這部分&#xff0c;我在模型中主要體現的就是不同容量的光伏、風電接入&#xff0c;對并網點的電壓影響…

Ubuntu 24.04 LTS linux 文件權限

Ubuntu 24.04 LTS 文件權限 讀權限 &#xff1a;允許查看文件的內容。寫權限 (w)&#xff1a;允許修改文件的內容。執行權限 (x)&#xff1a;允許執行文件&#xff08;對于目錄來說&#xff0c;是進入目錄的權限&#xff09;。 文件權限通常與三類用戶相關聯&#xff1a; 文…