在当今的互联网时代,实时通信已经成为许多应用不可或缺的功能。从在线聊天工具到实时游戏互动,从股票行情推送再到物联网数据传输,都对实时性有着极高的要求。而在 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;“护网”远非…