Java 邂逅 WebSocket:解鎖實時通信的無限可能?

在當今的互聯網時代,實時通信已經成為許多應用不可或缺的功能。從在線聊天工具到實時游戲互動,從股票行情推送再到物聯網數據傳輸,都對實時性有著極高的要求。而在 Java 技術棧中,WebSocket 技術的出現,為開發者打開了一扇通往高效、實時雙向通信的大門。本文將帶您深入探索 Java 與 WebSocket 的完美結合,從基礎概念到實戰案例,全方位解析這一強大技術組合的奧秘。

一、WebSocket 初探:打破 HTTP 的通信壁壘

(一)什么是 WebSocket

WebSocket 是一種在單個 TCP 連接上進行全雙工通信的協議。它于 2011 年被 IETF 標準化為 RFC 6455,并由 W3C 制定了相應的 API 標準。與傳統的 HTTP 協議相比,WebSocket 最大的特點在于允許服務器主動向客戶端推送信息,同時客戶端也可以主動向服務器發送信息,實現了真正意義上的雙向平等對話。

在 WebSocket 出現之前,要實現實時通信功能,開發者通常采用輪詢(Polling)或長輪詢(Long Polling)等方式。輪詢是客戶端每隔一段時間就向服務器發送一次請求,詢問是否有新的數據,服務器則立即返回響應,無論是否有新數據。這種方式會導致大量的無效請求,浪費帶寬和服務器資源。長輪詢則是客戶端向服務器發送請求后,服務器如果沒有新數據,不會立即返回響應,而是將連接保持一段時間,直到有新數據或連接超時才返回。雖然長輪詢比輪詢減少了請求次數,但仍然存在連接建立和關閉的開銷,而且在高并發場景下,服務器的壓力依然很大。

WebSocket 的出現徹底改變了這種狀況。它通過一次握手建立連接后,就可以在客戶端和服務器之間進行持續的雙向通信,不需要頻繁地建立和關閉連接,極大地減少了網絡開銷和服務器負擔,提高了通信效率和實時性。

(二)WebSocket 與 HTTP 的異同

WebSocket 和 HTTP 同屬于應用層協議,并且都基于 TCP 協議進行數據傳輸,這是它們的相同之處。但它們在通信方式、連接狀態等方面存在著顯著的差異:

  • 通信方式:HTTP 是一種單向通信協議,通信只能由客戶端發起,服務器根據客戶端的請求做出響應,無法主動向客戶端發送數據。而 WebSocket 是全雙工通信協議,一旦連接建立,客戶端和服務器可以雙向發送數據,互不干擾。
  • 連接狀態:HTTP 是無狀態協議,每次請求都是獨立的,服務器不會保存客戶端的狀態信息。WebSocket 是有狀態協議,連接建立后會保持狀態,服務器可以識別客戶端的身份和狀態。
  • 連接建立:HTTP 基于請求 - 響應模式,客戶端發送請求,服務器返回響應,連接隨即關閉(除非使用 Keep-Alive)。WebSocket 通過 HTTP 協議進行握手,握手成功后建立持久連接,在這個連接上進行雙向通信。
  • 適用場景:HTTP 適用于客戶端主動獲取數據的場景,如瀏覽網頁、獲取靜態資源等。WebSocket 適用于需要實時雙向通信的場景,如實時聊天、在線游戲、實時數據監控等。

(三)WebSocket 的工作原理

WebSocket 的工作過程主要包括握手階段和數據傳輸階段:

  1. 握手階段:客戶端首先向服務器發送一個 HTTP 請求,這個請求包含一些特殊的頭部信息,表明客戶端想要升級連接到 WebSocket 協議。請求頭部通常包含Upgrade: websocket和Connection: Upgrade,以及一個用于驗證的Sec-WebSocket-Key等信息。服務器收到請求后,如果支持 WebSocket 協議,會返回一個 HTTP 101 Switching Protocols 響應,其中包含Sec-WebSocket-Accept等信息,表明握手成功,連接升級為 WebSocket 連接。
  1. 數據傳輸階段:握手成功后,客戶端和服務器就可以通過這個 TCP 連接進行雙向數據傳輸。WebSocket 的數據幀有一定的格式,包含 opcode(表示數據類型,如文本、二進制等)、掩碼(客戶端發送的數據需要掩碼處理)、數據長度和數據載荷等信息。雙方按照這個格式發送和接收數據,實現實時通信。

二、Java 中的 WebSocket 實現:從基礎到實戰

(一)JSR-356:Java WebSocket API

JSR-356 定義了 Java WebSocket API,為 Java 開發者提供了標準化的 WebSocket 編程接口。它允許開發者在 Java EE 應用中創建 WebSocket 服務器端點和客戶端端點,實現 WebSocket 通信。

  1. 核心注解
    • @ServerEndpoint:用于標注一個類作為 WebSocket 服務器端點,指定端點的 URI 路徑。例如:@ServerEndpoint("/chat")表示該端點的路徑為/chat。
    • @OnOpen:標注一個方法,當客戶端與服務器建立連接時調用該方法。方法參數可以包含Session對象,代表與客戶端的連接會話。
    • @OnMessage:標注一個方法,當服務器收到客戶端發送的消息時調用該方法。方法參數可以包含消息內容、Session對象等。
    • @OnClose:標注一個方法,當客戶端與服務器斷開連接時調用該方法。方法參數可以包含關閉原因代碼、關閉原因描述和Session對象。
    • @OnError:標注一個方法,當連接發生錯誤時調用該方法。方法參數可以包含Throwable對象和Session對象。
  1. 服務器端實現示例

下面是一個簡單的 WebSocket 服務器端點實現,用于處理客戶端的連接和消息:

 

import javax.websocket.*;

import javax.websocket.server.ServerEndpoint;

import java.io.IOException;

import java.util.concurrent.CopyOnWriteArraySet;

@ServerEndpoint("/chat")

public class ChatServer {

// 存儲所有連接的會話

private static CopyOnWriteArraySet<Session> sessions = new CopyOnWriteArraySet<>();

// 當連接建立時調用

@OnOpen

public void onOpen(Session session) {

System.out.println("新的客戶端連接,會話ID:" + session.getId());

sessions.add(session);

try {

session.getBasicRemote().sendText("歡迎連接到聊天服務器!");

} catch (IOException e) {

e.printStackTrace();

}

}

// 當收到客戶端消息時調用

@OnMessage

public void onMessage(String message, Session session) {

System.out.println("收到來自會話" + session.getId() + "的消息:" + message);

// 向所有連接的客戶端廣播消息

for (Session s : sessions) {

if (s.isOpen()) {

try {

s.getBasicRemote().sendText("用戶" + session.getId() + ":" + message);

} catch (IOException e) {

e.printStackTrace();

}

}

}

}

// 當連接關閉時調用

@OnClose

public void onClose(Session session, CloseReason closeReason) {

System.out.println("客戶端斷開連接,會話ID:" + session.getId() + ",原因:" + closeReason.getReasonPhrase());

sessions.remove(session);

}

// 當發生錯誤時調用

@OnError

public void onError(Session session, Throwable throwable) {

System.out.println("會話" + session.getId() + "發生錯誤:" + throwable.getMessage());

throwable.printStackTrace();

}

}

在這個例子中,@ServerEndpoint("/chat")標注了ChatServer類作為 WebSocket 服務器端點,路徑為/chat。onOpen方法在客戶端連接時被調用,將新的會話添加到CopyOnWriteArraySet中(CopyOnWriteArraySet是線程安全的,適合多線程環境),并向客戶端發送歡迎消息。onMessage方法在收到客戶端消息時被調用,將消息廣播給所有連接的客戶端。onClose方法在客戶端斷開連接時被調用,將會話從集合中移除。onError方法處理連接過程中發生的錯誤。

  1. 客戶端實現示例(JavaScript)

客戶端可以使用 JavaScript 的WebSocket對象來連接 WebSocket 服務器并進行通信:

 

<!DOCTYPE html>

<html>

<head>

<title>WebSocket聊天客戶端</title>

</head>

<body>

<h1>WebSocket聊天</h1>

<div id="messages"></div>

<input type="text" id="messageInput" placeholder="請輸入消息">

<button onclick="sendMessage()">發送</button>

<script>

// 連接WebSocket服務器,注意協議是ws(非加密)或wss(加密)

let websocket = new WebSocket("ws://localhost:8080/chat");

// 當連接建立時觸發

websocket.onopen = function(event) {

console.log("連接已建立");

};

// 當收到服務器消息時觸發

websocket.onmessage = function(event) {

let messagesDiv = document.getElementById("messages");

messagesDiv.innerHTML += "<p>" + event.data + "</p>";

};

// 當連接關閉時觸發

websocket.onclose = function(event) {

console.log("連接已關閉,代碼:" + event.code + ",原因:" + event.reason);

};

// 當發生錯誤時觸發

websocket.onerror = function(event) {

console.log("發生錯誤");

};

// 發送消息到服務器

function sendMessage() {

let input = document.getElementById("messageInput");

let message = input.value;

if (message && websocket.readyState === WebSocket.OPEN) {

websocket.send(message);

input.value = "";

}

}

</script>

</body>

</html>

這個客戶端頁面創建了一個 WebSocket 連接到ws://localhost:8080/chat,當連接建立、收到消息、連接關閉或發生錯誤時,會在控制臺輸出相應的信息。頁面上有一個輸入框和一個發送按鈕,點擊發送按鈕會將輸入的消息發送到服務器。

  1. 運行環境與部署

要運行上述示例,需要一個支持 JSR-356 的 Java Web 容器,如 Tomcat 7.0.47 及以上版本、Jetty 9.1 及以上版本等。將服務器端代碼打包成 WAR 文件,部署到 Web 容器中,然后在瀏覽器中打開客戶端 HTML 頁面,就可以進行聊天測試了。

(二)Spring Framework 中的 WebSocket 支持

Spring Framework 對 WebSocket 提供了良好的支持,簡化了 WebSocket 的開發。Spring 的 WebSocket 支持基于 JSR-356,并提供了更高層次的抽象和更多的功能,如消息代理、 STOMP 協議支持等。

  1. Spring WebSocket 配置

要在 Spring 中使用 WebSocket,首先需要進行配置。可以通過 Java 配置類來啟用 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 {

@Override

public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {

// 注冊WebSocket處理器,指定路徑為/chat,允許跨域訪問

registry.addHandler(new ChatHandler(), "/chat").setAllowedOrigins("*");

}

}

在這個配置類中,@EnableWebSocket注解啟用了 Spring 的 WebSocket 支持。WebSocketConfig類實現了WebSocketConfigurer接口,并重寫了registerWebSocketHandlers方法,在該方法中注冊了一個 WebSocket 處理器ChatHandler,并指定了端點路徑為/chat,setAllowedOrigins("*")允許所有域的客戶端訪問。

  1. WebSocket 處理器

ChatHandler是一個實現了WebSocketHandler接口的類,用于處理 WebSocket 連接和消息:

 

import org.springframework.web.socket.CloseStatus;

import org.springframework.web.socket.TextMessage;

import org.springframework.web.socket.WebSocketSession;

import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;

import java.util.concurrent.CopyOnWriteArraySet;

public class ChatHandler extends TextWebSocketHandler {

// 存儲所有連接的會話

private static CopyOnWriteArraySet<WebSocketSession> sessions = new CopyOnWriteArraySet<>();

// 當連接建立時調用

@Override

public void afterConnectionEstablished(WebSocketSession session) throws Exception {

System.out.println("新的客戶端連接,會話ID:" + session.getId());

sessions.add(session);

session.sendMessage(new TextMessage("歡迎連接到Spring WebSocket聊天服務器!"));

}

// 當收到文本消息時調用

@Override

protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {

System.out.println("收到來自會話" + session.getId() + "的消息:" + message.getPayload());

// 向所有連接的客戶端廣播消息

for (WebSocketSession s : sessions) {

if (s.isOpen()) {

s.sendMessage(new TextMessage("用戶" + session.getId() + ":" + message.getPayload()));

}

}

}

// 當連接關閉時調用

@Override

public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {

System.out.println("客戶端斷開連接,會話ID:" + session.getId() + ",狀態:" + status);

sessions.remove(session);

}

}

ChatHandler繼承了TextWebSocketHandler,TextWebSocketHandler是WebSocketHandler的一個子類,專門用于處理文本消息。afterConnectionEstablished方法在連接建立時被調用,handleTextMessage方法在收到文本消息時被調用,afterConnectionClosed方法在連接關閉時被調用,這些方法的功能與前面 JSR-356 示例中的相應方法類似。

  1. 客戶端實現

Spring WebSocket 的客戶端實現與 JSR-356 的客戶端類似,可以使用 JavaScript 的WebSocket對象:

 

<!DOCTYPE html>

<html>

<head>

<title>Spring WebSocket聊天客戶端</title>

</head>

<body>

<h1>Spring WebSocket聊天</h1>

<div id="messages"></div>

<input type="text" id="messageInput" placeholder="請輸入消息">

<button onclick="sendMessage()">發送</button>

<script>

// 連接Spring WebSocket服務器

let websocket = new WebSocket("ws://localhost:8080/chat");

websocket.onopen = function(event) {

console.log("連接已建立");

};

websocket.onmessage = function(event) {

let messagesDiv = document.getElementById("messages");

messagesDiv.innerHTML += "<p>" + event.data + "</p>";

};

websocket.onclose = function(event) {

console.log("連接已關閉,代碼:" + event.code + ",原因:" + event.reason);

};

websocket.onerror = function(event) {

console.log("發生錯誤");

};

function sendMessage() {

let input = document.getElementById("messageInput");

let message = input.value;

if (message && websocket.readyState === WebSocket.OPEN) {

websocket.send(message);

input.value = "";

}

}

</script>

</body>

</html>

這個客戶端與前面 JSR-356 示例中的客戶端基本相同,只是連接的 URL 是 Spring WebSocket 服務器的端點路徑。

  1. STOMP 協議支持

STOMP(Simple Text Oriented Messaging Protocol)是一種簡單的面向文本的消息傳遞協議,它定義了客戶端和服務器之間進行消息傳遞的格式和規則。Spring WebSocket 支持 STOMP 協議,通過 STOMP 可以實現更復雜的消息傳遞模式,如發布 / 訂閱、點對點通信等。

要使用 STOMP 協議,需要配置消息代理。可以使用內置的簡單消息代理,也可以使用外部的消息代理如 RabbitMQ、ActiveMQ 等。以下是使用內置消息代理的配置:

 

import org.springframework.context.annotation.Configuration;

import org.springframework.messaging.simp.config.ChannelRegistration;

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 StompConfig implements WebSocketMessageBrokerConfigurer {

@Override

public void configureMessageBroker(MessageBrokerRegistry config) {

// 啟用簡單消息代理,用于廣播消息到以/topic/開頭的目的地

config.enableSimpleBroker("/topic");

// 配置應用程序的前綴,客戶端發送到服務器的消息需要以/app/開頭

config.setApplicationDestinationPrefixes("/app");

}

@Override

public void registerStompEndpoints(StompEndpointRegistry registry) {

// 注冊STOMP端點,允許跨域訪問,支持SockJS備用傳輸

registry.addEndpoint("/stomp-chat").setAllowedOrigins("*").withSockJS();

}

}

在這個配置類中,@EnableWebSocketMessageBroker注解啟用了 Spring 的 WebSocket 消息代理支持。configureMessageBroker方法配置了消息代理,enableSimpleBroker("/topic")啟用了內置的簡單消息代理,用于處理以/topic開頭的目的地的消息廣播。setApplicationDestinationPrefixes("/app")指定了客戶端發送到服務器的消息需要以/app開頭。registerStompEndpoints方法注冊了一個 STOMP 端點/stomp-chat,并支持 SockJS 備用傳輸,當瀏覽器不支持 WebSocket 時,會自動切換到其他傳輸方式如 HTTP 長輪詢等。

接下來創建一個控制器來處理 STOMP 消息:

 

import org.springframework.messaging.handler.annotation.MessageMapping;

import org.springframework.messaging.handler.annotation.SendTo;

import org.springframework.stereotype.Controller;

@Controller

public class StompController {

// 處理客戶端發送到/app/chat的消息

@MessageMapping("/chat")

// 將消息廣播到/topic/messages目的地

@SendTo("/topic/messages")

public ChatMessage handleChat(ChatMessage message) {

return new ChatMessage("用戶" + message.getSender() + ":" + message.getContent());

}

public static class ChatMessage {

private String sender;

private String content;

// 構造方法、getter和setter

public ChatMessage() {}

public ChatMessage(String content) {

this.content = content;

}

public String getSender() {

return sender;

}

public void setSender(String sender) {

this.sender = sender;

}

public String getContent() {

return content;

}

public void setContent(String content) {

this.content = content;

}

}

}

StompController中的handleChat方法使用@MessageMapping("/chat")注解,用于處理客戶端發送到/app/chat的消息。@SendTo("/topic/messages")注解指定將處理后的消息廣播到/topic/messages目的地。ChatMessage類是一個簡單的消息實體類,包含發送者和消息內容。

客戶端可以使用 SockJS 和 STOMP.js 來連接服務器并進行通信:

 

<!DOCTYPE html>

<html>

<head>

<title>STOMP聊天客戶端</title>

<script src="https://cdn.jsdelivr.net/npm/sockjs-client@1/dist/sockjs.min.js"></script>

<script src="https://cdn.jsdelivr.net/npm/stompjs@5/dist/stomp.min.js"></script>

</head>

<body>

<h1>STOMP聊天</h1>

<div id="messages"></div>

<input type="text" id="sender" placeholder="請輸入用戶名">

<input type="text" id="messageInput" placeholder="請輸入消息">

<button onclick="sendMessage()">發送</button>

<script>

// 連接STOMP端點

let socket = new SockJS('/stomp-chat');

let stompClient = Stomp.over(socket);

// 連接成功后的回調函數

stompClient.connect({}, function(frame) {

console.log('連接成功:' + frame);

// 訂閱/topic/messages目的地,接收廣播消息

stompClient.subscribe('/topic/messages', function(message) {

let chatMessage = JSON.parse(message.body);

let messagesDiv = document.getElementById("messages");

messagesDiv.innerHTML += "<p>" + chatMessage.content + "</p>";

});

});

// 發送消息到服務器

function sendMessage() {

let senderInput = document.getElementById("sender");

let messageInput = document.getElementById("messageInput");

let sender = senderInput.value;

let content = messageInput.value;

if (sender && content && stompClient.connected) {

// 發送消息到/app/chat目的地

stompClient.send("/app/chat", {}, JSON.stringify({sender: sender, content: content}));

messageInput.value = "";

}

}

</script>

</body>

</html>

在這個客戶端中,首先創建了一個SockJS對象連接到/stomp-chat端點,然后通過Stomp.over(socket)創建了一個 STOMP 客戶端。stompClient.connect方法用于連接服務器,連接成功后,通過stompClient.subscribe方法訂閱了/topic/messages目的地,以接收服務器廣播的消息。sendMessage方法用于發送消息到/app/chat目的地,服務器的StompController會處理該消息,并將其廣播到/topic/messages目的地。

三、WebSocket 的應用場景

(一)實時聊天系統

實時聊天是 WebSocket 最典型的應用場景之一。無論是在線客服聊天、社交軟件中的即時通訊,還是團隊協作工具中的群聊,都需要實時地傳遞消息。使用 WebSocket 可以實現客戶端和服務器之間的實時雙向通信,用戶發送的消息能夠立即被其他用戶收到,提供良好的用戶體驗。

在實時聊天系統中,通常采用發布 / 訂閱模式,當一個用戶發送消息時,服務器將消息廣播給所有訂閱了該聊天頻道的用戶。使用 STOMP 協議可以很方便地實現這種模式,通過訂閱不同的主題來區分不同的聊天頻道。

(二)在線游戲

在線游戲對實時性要求很高,玩家的操作需要實時地反饋給服務器,服務器的狀態也需要實時地同步到所有玩家的客戶端。WebSocket 的低延遲和雙向通信特性非常適合在線游戲場景,能夠保證游戲的流暢性和實時性。

在多人在線游戲中,服務器需要實時接收玩家的操作指令,如移動、攻擊等,并進行處理,然后將游戲狀態的變化廣播給所有玩家,確保所有玩家看到的游戲狀態是一致的。

(三)實時數據監控

在工業監控、金融交易、網絡監控等領域,需要實時地獲取和展示數據。例如,股票行情監控系統需要實時推送股票價格的變化;網絡監控系統需要實時顯示網絡設備的運行狀態和流量數據。

使用 WebSocket 可以將實時數據從服務器推送到客戶端,客戶端可以實時更新展示界面,讓用戶及時了解最新的數據信息。相比傳統的輪詢方式,WebSocket 能夠減少網絡流量和服務器負載,提高數據傳輸的效率。

(四)協作編輯工具

協作編輯工具如在線文檔編輯、代碼協作工具等,允許多個用戶同時編輯同一個文檔或代碼文件,用戶的修改需要實時地被其他用戶看到。WebSocket 可以實現用戶之間的實時數據同步,當一個用戶修改內容時,服務器會將修改內容實時推送給其他用戶,確保所有用戶看到的內容是一致的。

四、WebSocket 的注意事項和優化技巧

(一)連接管理

  1. 連接數限制:WebSocket 連接是持久的,會占用服務器的資源,因此需要限制同時連接的客戶端數量,避免服務器資源耗盡。可以通過配置 Web 容器的參數來設置最大連接數,或者在應用程序中進行連接數控制。
  1. 會話管理:需要妥善管理 WebSocket 會話,當客戶端斷開連接時,及時釋放相關資源,如從會話集合中移除會話、關閉相關的流等。可以通過@OnClose注解或afterConnectionClosed方法來處理連接關閉事件。
  1. 心跳機制:由于網絡故障、客戶端崩潰等原因,WebSocket 連接可能會異常斷開,而服務器可能不會立即察覺。為了檢測無效連接,可以使用心跳機制,服務器定期向客戶端發送心跳消息,客戶端收到后返回響應,如果服務器在一定時間內沒有收到客戶端的響應,則認為連接已斷開,主動關閉連接。

(二)消息處理

  1. 消息大小限制:為了防止惡意客戶端發送過大的消息導致服務器內存溢出,需要設置消息大小限制。可以通過配置 Web 容器的參數或在應用程序中進行消息大小檢查來實現。例如,在 Tomcat 中,可以通過maxTextMessageBufferSize和maxBinaryMessageBufferSize參數設置文本消息和二進制消息的最大緩沖區大小。
  1. 消息格式:WebSocket 支持文本消息和二進制消息。對于文本消息,建議使用 JSON 格式,JSON 格式簡潔、易解析,適合傳輸結構化數據。對于二進制消息,如圖片、音頻、視頻等,可以直接傳輸二進制數據,提高傳輸效率。
  1. 消息壓縮:對于較大的消息,可以進行壓縮后再傳輸,減少網絡流量。WebSocket 支持對消息進行壓縮,客戶端和服務器可以協商是否使用壓縮。在 Spring WebSocket 中,可以通過配置WebSocketMessageBrokerConfigurer的configureClientInboundChannel和configureClientOutboundChannel方法來啟用消息壓縮。

(三)安全性

  1. 認證和授權:WebSocket 連接建立前,需要對客戶端進行認證和授權,確保只有合法的用戶才能連接到服務器。可以在握手階段進行認證,例如通過 HTTP 請求的 Cookie、Token 等信息進行身份驗證。在 Spring WebSocket 中,可以通過攔截器來實現認證和授權。
  1. 數據加密:為了防止消息在傳輸過程中被竊取或篡改,需要對 WebSocket 連接進行加密。可以使用 wss 協議(WebSocket Secure),wss 協議基于 SSL/TLS 加密,能夠保證數據傳輸的安全性。
  1. 防止跨站請求偽造(CSRF):WebSocket 連接也可能受到 CSRF 攻擊,因此需要采取措施防止 CSRF 攻擊。可以在握手階段驗證請求的來源,或者使用 CSRF 令牌進行驗證。在 Spring WebSocket 中,可以通過配置 CSRF 保護來防止 CSRF 攻擊。

(四)性能優化

  1. 使用連接池:對于頻繁創建和關閉 WebSocket 連接的場景,可以使用連接池來管理連接,減少連接建立和關閉的開銷。
  1. 異步處理:在處理 WebSocket 消息時,盡量使用異步處理方式,避免阻塞服務器線程。例如,在 Spring WebSocket 中,可以使用@Async注解將消息處理方法標記為異步方法。
  1. 負載均衡:當 WebSocket 服務器面臨高并發訪問時,可以使用負載均衡技術將請求分發到多個服務器節點,提高系統的吞吐量和可用性。需要注意的是,WebSocket 連接是持久的,負載均衡器需要支持會話親和性,確保同一個客戶端的連接始終被路由到同一個服務器節點。

五、總結與展望

WebSocket 作為一種實時雙向通信協議,為 Java 開發者提供了構建高效、實時的 Web 應用程序的能力。通過 JSR-356 和 Spring Framework 等技術,Java 開發者可以方便地實現 WebSocket 功能,滿足各種實時通信場景的需求。

在實際應用中,需要注意連接管理、消息處理、安全性等方面的問題,并采取相應的優化技巧,以提高 WebSocket 應用的性能和可靠性。隨著互聯網技術的不斷發展,實時通信的需求會越來越廣泛,WebSocket 作為一種重要的實時通信技術,將會在更多的領域得到應用。

未來,WebSocket 可能會在性能、安全性、擴展性等方面得到進一步的提升,同時也會與其他技術如物聯網、人工智能等結合,創造出更多新的應用場景。作為 Java 開發者,我們需要不斷學習和掌握 WebSocket 技術,以便更好地應對實時通信領域的挑戰和機遇。

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

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

相關文章

MySQL 核心知識點梳理(5)

目錄 事務 MySQL事務的四大特性 ACID 原子性 持久性 隔離性 事務的隔離級別 讀未提交 讀已提交 可重復讀 串行化 事務的隔離級別如何實現 MVCC 版本鏈 READVIEW 高可用 MySQL數據庫的讀寫分離 主從復制 主從同步延遲怎么處理 分庫策略 水平分庫分表的策略…

借助AI學習開源代碼git0.7之六write-tree

借助AI學習開源代碼git0.7之六write-tree write-tree.c 的作用是根據當前的索引&#xff08;cache&#xff09;內容創建一個樹&#xff08;tree&#xff09;對象&#xff0c;并將其寫入Git的對象數據庫。 樹對象代表了項目在某個時間點的目錄結構。 代碼的主要邏輯&#xff1a;…

開源 python 應用 開發(八)圖片比對

最近有個項目需要做視覺自動化處理的工具&#xff0c;最后選用的軟件為python&#xff0c;剛好這個機會進行系統學習。短時間學習&#xff0c;需要快速開發&#xff0c;所以記錄要點步驟&#xff0c;防止忘記。 鏈接&#xff1a; 開源 python 應用 開發&#xff08;一&#xf…

SeaTunnel 云倉連接器使用指南 | AI 助手解讀系列

最近體驗了一下 Deepwiki 的 AI 文檔生成功能&#xff0c;本文展示其自動生成的《SeaTunnel 云端數據倉庫連接器》文檔內容&#xff0c;歡迎大家一起“挑刺捉蟲”&#xff0c;看看 AI 寫技術文檔到底靠不靠譜&#xff1f; 本文檔介紹了 Apache SeaTunnel 的云數據倉庫連接器&a…

每日算法刷題Day51:7.21:leetcode 棧6道題,用時1h40min

二.進階 1.套路 2.題目描述 1.給你一個字符串 s 。它可能包含任意數量的 * 字符。你的任務是刪除所有的 * 字符。 當字符串還存在至少一個 * 字符時&#xff0c;你可以執行以下操作&#xff1a; 刪除最左邊的 * 字符&#xff0c;同時刪除該星號字符左邊一個字典序 最小的字…

網絡基礎DAY16-MSTP-VRRP

STP/RSTP的局限性1.所有VLAN共享一棵生成樹 2.無法實現不同VLAN在多條Trunk鏈路上的負載分擔 3.次優化二層路徑。MSTP的基本概念及優勢MSTP的定義MST域擁有相同MST配置標識的網橋構成的集合。 具體如何分辨是否是同一個域&#xff0c;就看域名&#xff0c;配置修訂號&#xff0…

freertos關鍵函數理解 uxListRemove

//刪除pxItemToRemove節點 UBaseType_t uxListRemove(ListItem_t *pxItemToRemove) { //The list item knows which list it is in. Obtain the list from the list item.//找到節點所在的鏈表//my_printf( "uxListRemove pxItemToRemove %#p\n", pxI…

C語言---番外篇(柔性數組)

前言&#xff1a; 由于這塊內容所謂綜合性比較高&#xff0c;有數組的知識&#xff0c;有結構體的知識&#xff0c;還有動態內存管理的知識&#xff0c;所以我就單獨寫一篇博客&#xff0c;此謂番外篇。 柔性數組的概念 定義在結構體的最后一個元素的位置且大小未知的數組就叫…

單片機的幾種GPIO輸入輸出模型詳解

模式選擇匯總參考表&#xff1a;模式輸出驅動輸入阻抗默認狀態典型應用場景推挽輸出強驅動禁用可配置LED, SPI, 高速信號開漏輸出弱驅動禁用低/懸空IC, 電平轉換, 線與浮空輸入禁用極高不確定外部強驅動信號上拉輸入禁用中高高電平按鍵(接地型), 數字輸入下拉輸入禁用中高低電平…

深度解析ECharts.js:構建現代化數據可視化的利器

引言&#xff1a;數據可視化的新時代挑戰 在數字化轉型浪潮中&#xff0c;數據可視化已成為企業決策和用戶體驗的關鍵環節。面對海量數據的呈現需求&#xff0c;傳統表格已無法滿足用戶對直觀洞察的渴求。作為百度開源的JavaScript可視化庫&#xff0c;ECharts.js憑借其強大的功…

從零構建實時通信引擎:Freeswitch源碼編譯與深度優化指南

一、構建工具&#xff1a;編譯FreeSWITCH及其依賴庫的基礎 1. CMake2. Autoconf 二、匯編器&#xff1a;提升音視頻處理性能 3. YASM / NASM 三、音視頻編解碼器&#xff1a;支撐實時媒體傳輸 4. Opus5. x264 (可選)6. libvpx / libvpx2 (可選) 四、多媒體框架與工具庫&#xf…

網絡原理 HTTP 和 HTTPS

目錄 一 . HTTP 協議 二 . 抓包 三 . HTTP 請求 / 響應的基本格式 &#xff08;1&#xff09;HTTP請求的基本格式 &#xff08;2&#xff09;HTTP響應的基本格式 四 . HTTP 方法 GET 和 POST 的區別&#xff1a; 五 . 請求報頭和響應報頭 &#xff08;1&#…

基于單片機的自動條幅懸掛機

摘 要 隨著日新月異科技發展&#xff0c;在心率體溫測量方面&#xff0c;我們取得了迅速的發展&#xff0c;就近日而言&#xff0c;脈搏測量儀已經在多個領域大展身手&#xff0c;除了在醫學領域有所建樹&#xff0c;在人們的日常生活方面的應用也不斷拓展&#xff0c;如檢疫…

《C++》面向對象編程--類(中)

文章目錄一、構造函數1.1定義1.2語法1.3特性二、析構函數2.1定義2.2語法2.3特性三、拷貝構造函數3.1定義3.2語法3.3特性3.4淺拷貝3.4.1定義3.4.2淺拷貝的風險3.5深拷貝一、構造函數 1.1定義 在C中&#xff0c;構造函數&#xff08;Constructor&#xff09; 是一種特殊的成員函…

機器學習初學者理論初解

大家好! 為什么手機相冊能自動識別人臉&#xff1f;為什么購物網站總能推薦你喜歡的商品&#xff1f;這些“智能”背后&#xff0c;都藏著一位隱形高手——機器學習&#xff08;Machine Learning&#xff09;。一、什么是機器學習&#xff1f;簡單說&#xff0c;機器學習是教計…

原碼反碼補碼

在Java中&#xff0c;無論是小數還是整數&#xff0c;他們都要帶有符號&#xff08;和C語言不同&#xff0c;C語言有無符號數&#xff09;。首位就作為符號位。原碼反碼&#xff1a;正數的反碼是其原碼本身負數的反碼是在其原碼的基礎上, 符號位不變&#xff0c;其余各個位取反…

使用ubuntu:20.04和ubuntu:jammy構建secretflow環境

一、使用ubuntu:20.04構建隱語編譯環境FROM ubuntu:20.04LABEL maintainer"build SecureProtocolLib on ubuntu:20.04"ARG TARGETPLATFORM# change dash to bash as default shell RUN ln -sf /bin/bash /bin/shRUN apt update \&& apt upgrade -y \&&am…

Hinge Loss(鉸鏈損失函數)詳解:SVM 中的關鍵損失函數

&#x1f4cc; 一、什么是 Hinge Loss&#xff1f;Hinge Loss&#xff08;鉸鏈損失&#xff09;&#xff0c;是 支持向量機&#xff08;SVM, Support Vector Machine&#xff09; 中常用的一種損失函數&#xff0c;用于最大間隔分類。其核心思想是&#xff1a;當預測結果已經正…

days32 :零基礎學嵌入式之網絡2.0

一、wireshark &#xff1a;網絡抓包工具1.功能&#xff1a;抓取通過電腦網卡的網絡數據2.作用&#xff1a;排查故障、抓取數據做數據分析、3.用法&#xff1a;&#xff08;1&#xff09;sudo wireshark&#xff08;2&#xff09;選擇需要抓取的網卡》any&#xff08;3&#xf…

數字護網:一次深刻的企業安全體系靈魂演練

&#x1f9e9; 引言&#xff1a;什么是“護網”&#xff1f;—— 不止是攻防&#xff0c;更是企業安全能力的年度大考 每年&#xff0c;由國家相關部門牽頭的“護網行動”都如期而至&#xff0c;各大企事業單位的安全團隊也隨之進入高度戒備狀態。然而&#xff0c;“護網”遠非…