Java中的WebSocket與實(shí)時(shí)通信詳解
開篇語(yǔ)
今天我要給大家分享一些自己日常學(xué)習(xí)到的一些知識(shí)點(diǎn),并以文字的形式跟大家一起交流,互相學(xué)習(xí),一個(gè)人雖可以走的更快,但一群人可以走的更遠(yuǎn)。
我是一名后端開發(fā)愛(ài)好者,工作日常接觸到最多的就是Java語(yǔ)言啦,所以我都盡量抽業(yè)余時(shí)間把自己所學(xué)到所會(huì)的,通過(guò)文章的形式進(jìn)行輸出,希望以這種方式幫助到更多的初學(xué)者或者想入門的小伙伴們,同時(shí)也能對(duì)自己的技術(shù)進(jìn)行沉淀,加以復(fù)盤,查缺補(bǔ)漏。
前言
在現(xiàn)代Web應(yīng)用中,用戶對(duì)實(shí)時(shí)互動(dòng)的需求越來(lái)越高。無(wú)論是即時(shí)聊天、實(shí)時(shí)通知,還是在線多人游戲,實(shí)時(shí)通信已成為現(xiàn)代應(yīng)用的重要組成部分。傳統(tǒng)的HTTP請(qǐng)求/響應(yīng)模式已經(jīng)不能滿足實(shí)時(shí)數(shù)據(jù)交換的需求,而WebSocket作為一種支持全雙工通信的協(xié)議,為開發(fā)者提供了一個(gè)高效、低延遲的解決方案。Java為實(shí)現(xiàn)WebSocket通信提供了多種工具和框架,其中最常用的是Java API for WebSocket (JSR 356)和Spring WebSocket。
本文將深入探討WebSocket的概念、Java實(shí)現(xiàn)WebSocket的技術(shù)手段,并通過(guò)實(shí)際應(yīng)用場(chǎng)景(如即時(shí)聊天、實(shí)時(shí)通知、在線游戲)進(jìn)行詳細(xì)分析。
一、WebSocket概念:全雙工通信、長(zhǎng)連接
1.1 WebSocket協(xié)議簡(jiǎn)介
WebSocket協(xié)議是HTML5推出的一種網(wǎng)絡(luò)協(xié)議,用于在客戶端和服務(wù)器之間建立一個(gè)持久的、雙向的通信通道。與傳統(tǒng)的HTTP協(xié)議不同,WebSocket提供了全雙工通信方式,這意味著客戶端和服務(wù)器可以隨時(shí)相互發(fā)送消息,而不需要每次建立新的連接。這使得WebSocket特別適用于實(shí)時(shí)應(yīng)用場(chǎng)景。
WebSocket的特點(diǎn):
- 全雙工通信:WebSocket支持客戶端和服務(wù)器之間的雙向數(shù)據(jù)流,可以同時(shí)發(fā)送和接收數(shù)據(jù),不像HTTP那樣只能從客戶端發(fā)起請(qǐng)求。
- 長(zhǎng)連接:WebSocket協(xié)議建立連接后,客戶端與服務(wù)器之間保持長(zhǎng)時(shí)間的連接,直到手動(dòng)關(guān)閉連接。這避免了頻繁建立和關(guān)閉連接的開銷。
- 低延遲:由于WebSocket使用持久連接,數(shù)據(jù)交換不再受到傳統(tǒng)HTTP請(qǐng)求/響應(yīng)模型的限制,具有更低的延遲。
1.2 WebSocket工作原理
- 建立連接:WebSocket連接由客戶端發(fā)起,客戶端通過(guò)HTTP請(qǐng)求與服務(wù)器進(jìn)行握手。服務(wù)器響應(yīng)HTTP請(qǐng)求并升級(jí)協(xié)議為WebSocket,連接建立成功。
- 數(shù)據(jù)交換:一旦WebSocket連接建立,客戶端和服務(wù)器可以通過(guò)該連接進(jìn)行雙向數(shù)據(jù)傳輸。數(shù)據(jù)交換是基于WebSocket協(xié)議的幀結(jié)構(gòu)進(jìn)行的,數(shù)據(jù)幀通過(guò)WebSocket連接不斷發(fā)送。
- 關(guān)閉連接:當(dāng)通信完成時(shí),客戶端或服務(wù)器都可以發(fā)送關(guān)閉幀,關(guān)閉WebSocket連接。
WebSocket連接的三階段:
- 握手階段:客戶端向服務(wù)器發(fā)起連接請(qǐng)求,服務(wù)器響應(yīng)并升級(jí)協(xié)議為WebSocket。
- 數(shù)據(jù)傳輸階段:客戶端和服務(wù)器通過(guò)持久連接進(jìn)行雙向數(shù)據(jù)傳輸。
- 關(guān)閉階段:通信完成后,客戶端或服務(wù)器發(fā)送關(guān)閉幀關(guān)閉連接。
二、Java實(shí)現(xiàn)WebSocket:Java API for WebSocket(JSR 356)、Spring WebSocket
2.1 Java API for WebSocket(JSR 356)
**Java API for WebSocket (JSR 356)**是Java EE7引入的標(biāo)準(zhǔn)API,旨在簡(jiǎn)化WebSocket通信的實(shí)現(xiàn)。通過(guò)JSR 356,開發(fā)者可以輕松地在Java應(yīng)用中實(shí)現(xiàn)WebSocket服務(wù)器端和客戶端。
服務(wù)器端實(shí)現(xiàn)
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
@ServerEndpoint("/chat")
public class ChatEndpoint {
@OnOpen
public void onOpen(Session session) {
System.out.println("New connection: " + session.getId());
}
@OnMessage
public void onMessage(String message, Session session) {
System.out.println("Received message: " + message);
session.getAsyncRemote().sendText("Echo: " + message);
}
@OnClose
public void onClose(Session session) {
System.out.println("Connection closed: " + session.getId());
}
}代碼解析:
- @ServerEndpoint(“/chat”):標(biāo)注WebSocket端點(diǎn),客戶端可以通過(guò)
ws://localhost:8080/chat進(jìn)行連接。 - @OnOpen:當(dāng)WebSocket連接建立時(shí)調(diào)用,
session.getId()可用來(lái)獲取客戶端的連接ID。 - @OnMessage:當(dāng)接收到客戶端發(fā)送的消息時(shí)調(diào)用,
session.getAsyncRemote().sendText()用于向客戶端發(fā)送消息。 - @OnClose:當(dāng)WebSocket連接關(guān)閉時(shí)調(diào)用,釋放資源等。
啟動(dòng)服務(wù)器
import javax.websocket.server.ServerContainer;
import javax.websocket.server.ServerEndpointConfig;
import javax.servlet.ServletContext;
import org.apache.tomcat.websocket.server.WsSci;
public class WebSocketServer {
public static void main(String[] args) {
ServletContext context = new MyServletContext();
ServerContainer container = (ServerContainer) context.getAttribute("javax.websocket.server.ServerContainer");
container.addEndpoint(ChatEndpoint.class);
}
}2.2 Spring WebSocket
Spring WebSocket是Spring框架提供的一種集成WebSocket的解決方案。它結(jié)合了Spring的依賴注入和消息驅(qū)動(dòng)的處理方式,能夠輕松地實(shí)現(xiàn)WebSocket服務(wù)器端和客戶端通信。Spring WebSocket與STOMP協(xié)議結(jié)合使用,使得消息推送和事件通知變得更加簡(jiǎn)單和強(qiáng)大。
配置WebSocket
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/chat").withSockJS(); // 創(chuàng)建WebSocket端點(diǎn),使用SockJS進(jìn)行降級(jí)處理
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/topic"); // 啟用一個(gè)簡(jiǎn)單的內(nèi)存消息代理,處理`/topic`下的消息
registry.setApplicationDestinationPrefixes("/app"); // 設(shè)置消息前綴
}
}代碼解析:
- @EnableWebSocketMessageBroker:?jiǎn)⒂肳ebSocket消息代理,允許使用STOMP協(xié)議進(jìn)行消息推送。
- registerStompEndpoints:注冊(cè)WebSocket端點(diǎn),客戶端通過(guò)
/chat連接。 - configureMessageBroker:配置消息代理和應(yīng)用消息前綴。
/topic用于廣播消息,/app是應(yīng)用消息的前綴。
發(fā)送和接收消息
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Controller;
@Controller
public class ChatController {
@MessageMapping("/sendMessage") // 處理客戶端發(fā)送的消息
@SendTo("/topic/messages") // 向訂閱者發(fā)送消息
public String sendMessage(String message) {
return "Message: " + message;
}
}代碼解析:
- @MessageMapping(“/sendMessage”):接收客戶端發(fā)送到
/sendMessage的消息。 - @SendTo(“/topic/messages”):消息將被轉(zhuǎn)發(fā)到
/topic/messages,然后廣播到所有訂閱者。
客戶端實(shí)現(xiàn)
<!DOCTYPE html>
<html>
<head>
<title>WebSocket Chat</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/stomp.js/2.3.3/stomp.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/sockjs-client/1.5.1/sockjs.min.js"></script>
</head>
<body>
<div id="messages"></div>
<input type="text" id="messageInput">
<button onclick="sendMessage()">Send</button>
<script>
var socket = new SockJS('/chat');
var stompClient = Stomp.over(socket);
stompClient.connect({}, function(frame) {
stompClient.subscribe('/topic/messages', function(message) {
document.getElementById("messages").innerHTML += message.body + "
";
});
});
function sendMessage() {
var message = document.getElementById("messageInput").value;
stompClient.send("/app/sendMessage", {}, message);
}
</script>
</body>
</html>代碼解析:
- SockJS:提供WebSocket連接的降級(jí)支持,在不支持WebSocket的環(huán)境中使用。
- STOMP:消息傳遞協(xié)議,客戶端通過(guò)STOMP協(xié)議發(fā)送消息到
/app/sendMessage,并接收來(lái)自/topic/messages的廣播消息。
三、應(yīng)用場(chǎng)景:即時(shí)聊天、實(shí)時(shí)通知、在線游戲
3.1 即時(shí)聊天
WebSocket在即時(shí)通訊應(yīng)用中的應(yīng)用非常廣泛,利用WebSocket的全雙工通信,可以實(shí)現(xiàn)實(shí)時(shí)的消息推送。每當(dāng)一個(gè)用戶發(fā)送消息,消息便立即傳遞給其他連接的客戶端,提供實(shí)時(shí)互動(dòng)的體驗(yàn)。
3.2 實(shí)時(shí)通知
WebSocket也常用于實(shí)時(shí)通知系統(tǒng)。在很多業(yè)務(wù)場(chǎng)景中,系統(tǒng)需要向用戶推送實(shí)時(shí)信息,如訂單狀態(tài)更新、系統(tǒng)警告、直播通知等。WebSocket提供了一個(gè)持久連接,能夠在有新事件發(fā)生時(shí)立即通知到客戶端。
3.3 在線游戲
在線游戲中的實(shí)時(shí)數(shù)據(jù)交換對(duì)低延遲的要求非常高。WebSocket的低延遲和持久連接特性使其成為在線多人游戲的理想選擇。游戲中的實(shí)時(shí)互動(dòng)、玩家狀態(tài)更新、多人協(xié)作等都可以通過(guò)WebSocket實(shí)現(xiàn)。
四、總結(jié)
Java中的WebSocket和實(shí)時(shí)通信技術(shù)提供了低延遲、高吞吐量的雙向通信解決方案,使得開發(fā)者能夠輕松地構(gòu)建實(shí)時(shí)交互應(yīng)用。Java API for WebSocket(JSR 356)和Spring WebSocket為開發(fā)者提供了簡(jiǎn)潔且功能強(qiáng)大的實(shí)現(xiàn)方式,適用于即時(shí)聊天、實(shí)時(shí)通知、在線游戲等多種應(yīng)用場(chǎng)景。
通過(guò)WebSocket,開發(fā)者能夠?qū)崿F(xiàn)高效的實(shí)時(shí)通信,消除了傳統(tǒng)HTTP協(xié)議的限制,使得應(yīng)用能夠在客戶端和服務(wù)器之間進(jìn)行無(wú)縫的、實(shí)時(shí)的雙向數(shù)據(jù)流。隨著WebSocket的廣泛應(yīng)用,實(shí)時(shí)交互功能在Web開發(fā)中的重要性也將不斷增強(qiáng),推動(dòng)互聯(lián)網(wǎng)應(yīng)用的智能化與實(shí)時(shí)化。
到此這篇關(guān)于Java中的WebSocket與實(shí)時(shí)通信!的文章就介紹到這了,更多相關(guān)Java WebSocket實(shí)時(shí)通信內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Sping?Security前后端分離兩種實(shí)戰(zhàn)方案
這篇文章主要介紹了Sping?Security前后端分離兩種方案,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-03-03
Mybatis多個(gè)字段模糊匹配同一個(gè)值的案例
這篇文章主要介紹了Mybatis多個(gè)字段模糊匹配同一個(gè)值的案例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-09-09
Java中基于Shiro,JWT實(shí)現(xiàn)微信小程序登錄完整例子及實(shí)現(xiàn)過(guò)程
這篇文章主要介紹了Java中基于Shiro,JWT實(shí)現(xiàn)微信小程序登錄完整例子 ,實(shí)現(xiàn)了小程序的自定義登陸,將自定義登陸態(tài)token返回給小程序作為登陸憑證。需要的朋友可以參考下2018-11-11
IntelliJ IDEA優(yōu)化配置的實(shí)現(xiàn)
這篇文章主要介紹了IntelliJ IDEA優(yōu)化配置的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07
java 二進(jìn)制數(shù)據(jù)與16進(jìn)制字符串相互轉(zhuǎn)化方法
今天小編就為大家分享一篇java 二進(jìn)制數(shù)據(jù)與16進(jìn)制字符串相互轉(zhuǎn)化方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-07-07
SpringBoot處理JSON數(shù)據(jù)方法詳解
這篇文章主要介紹了SpringBoot整合Web開發(fā)中Json數(shù)據(jù)處理,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-10-10
Java?Mybatis查詢數(shù)據(jù)庫(kù)舉例詳解
這篇文章主要給大家介紹了關(guān)于Java?Mybatis查詢數(shù)據(jù)庫(kù)的相關(guān)資料,在MyBatis中可以使用遞歸查詢實(shí)現(xiàn)對(duì)數(shù)據(jù)庫(kù)中樹形結(jié)構(gòu)數(shù)據(jù)的查詢,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-10-10
JAVA統(tǒng)計(jì)字符串中某個(gè)字符出現(xiàn)次數(shù)的方法實(shí)現(xiàn)
本文主要介紹了JAVA統(tǒng)計(jì)字符串中某個(gè)字符出現(xiàn)次數(shù)的方法實(shí)現(xiàn),可以循環(huán)使用String的charAt(int index)函數(shù),具有一定的參考價(jià)值,感興趣的可以了解一下2023-11-11

