网络编程之WebSocket(1)
什么是WebSocket?它的作用是什么?
核心定义:
WebSocket是一种网络通信协议,它在单个TCP连接上提供全双工(Full-Duplex) 的通信通道。简单来说,就是允许服务器和客户端(通常是浏览器)在建立一次连接后,随时主动向对方发送数据。
它要解决的核心问题(作用):
解决传统HTTP协议的请求-响应(Request-Response)模型的局限性。在HTTP协议下,通信总是由客户端发起,服务器被动响应。如果服务器有新的数据(如新消息、实时股价、游戏状态更新)需要推送给客户端,它无法主动推送,只能等待客户端来请求。
为了模拟“实时”效果,在WebSocket出现之前,通常采用以下技术,但它们都有明显缺点:
- 轮询(Polling):客户端定期向服务器发送HTTP请求询问是否有新数据。缺点:效率低下,很多请求是无用的,实时性差。
- 长轮询(Long-Polling):客户端发送请求,服务器hold住连接,直到有数据或超时才返回。客户端收到响应后立即发出下一个请求。缺点:实现复杂,连接管理困难。
WebSocket的作用就是为浏览器和服务器之间建立一个真正的、高效的、低延迟的双向实时通信渠道。
WebSocket可以用来干什么?
WebSocket非常适合需要高实时性的应用场景,例如:
- 在线聊天/客服系统:消息能够即时送达和显示。
- 实时协作工具:如在线文档(Google Docs)、多人在线绘图板,一方的操作可以实时同步给其他参与者。
- 实时数据展示:如股票行情看板、体育赛事直播比分、监控系统实时数据。
- 多人在线游戏:游戏状态的实时同步。
- 社交Feed流:新内容的实时推送。
WebSocket和网络编程有什么关系?
网络编程是涵盖所有在网络中进行数据交换的编程技术的总称。WebSocket是网络编程中应用于应用层的一种具体协议。
- 基础:WebSocket建立在网络编程的基础之上。它依赖于TCP协议(传输层)来提供可靠、有序的数据流。可以说,WebSocket是TCP协议之上的一种高级封装。
- 与HTTP的关系:WebSocket的设计与HTTP协议密切相关。它的连接建立过程(称为“握手”)是通过HTTP协议完成的,如您提供的文章中所示:
服务器同意升级协议后,通信就不再遵循HTTP协议,而是切换到WebSocket协议。这使得WebSocket可以轻松绕过防火墙和代理,因为它们通常允许HTTP流量通过。GET /chat HTTP/1.1 Host: www.example.com Upgrade: websocket Connection: Upgrade - 演进:WebSocket代表了网络编程从简单的请求-响应模式向复杂的、持续的双向通信模式的演进。它是为了满足现代Web应用对实时性日益增长的需求而诞生的关键技术。
怎么使用WebSocket?
1. 核心概念
- WebSocketHandler:处理WebSocket通信的核心接口,相当于HTTP中的
Controller。文章中的ChatHandler继承了TextWebSocketHandler,专门用于处理文本消息。 - WebSocketSession:代表一个WebSocket连接。通过它可以发送消息、获取连接属性、关闭连接等。
- HandshakeInterceptor:拦截器,用于在WebSocket握手建立前后执行逻辑,如文章中的
ChatHandshakeInterceptor用于将HTTP Session中的属性(如用户信息)复制到WebSocketSession中。
2. 服务器端开发步骤(基于Spring)
a. 添加依赖
在pom.xml中添加Spring WebSocket和嵌入式Tomcat对WebSocket的支持。
<dependency><groupId>org.apache.tomcat.embed</groupId><artifactId>tomcat-embed-websocket</artifactId><version>10.1.1</version>
</dependency>
<dependency><groupId>org.springframework</groupId><artifactId>spring-websocket</artifactId><version>6.0.0</version>
</dependency>
b. 启用WebSocket支持
在配置类(如AppConfig)上使用@EnableWebSocket注解。
c. 配置WebSocket端点
通过实现WebSocketConfigurer接口,注册WebSocketHandler并指定其映射的URL路径。
@Configuration
@EnableWebSocket
public class AppConfig implements WebSocketConfigurer {@Autowiredprivate ChatHandler chatHandler;@Autowiredprivate ChatHandshakeInterceptor chatInterceptor;@Overridepublic void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {// 将 ChatHandler 映射到 "/chat" 路径registry.addHandler(chatHandler, "/chat").addInterceptors(chatInterceptor);}
}
d. 实现业务处理器(ChatHandler)
这是最核心的部分,需要处理连接建立、接收消息、连接关闭等事件。
@Component
public class ChatHandler extends TextWebSocketHandler {// 使用线程安全的Map来管理所有在线用户的Sessionprivate Map<String, WebSocketSession> clients = new ConcurrentHashMap<>();@Overridepublic void afterConnectionEstablished(WebSocketSession session) throws Exception {// 新的WebSocket连接建立成功clients.put(session.getId(), session);session.getAttributes().put("name", "Guest1"); // 设置默认用户名System.out.println("新连接建立: " + session.getId());}@Overrideprotected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {// 当收到来自客户端的文本消息时调用String clientMessage = message.getPayload(); // 获取消息内容// 1. 解析客户端消息(通常是JSON)// 2. 处理业务逻辑(例如,构建要广播的消息)String broadcastJson = ... // 构造要发送的JSON字符串// 3. 广播消息给所有连接的客户端broadcastMessage(new TextMessage(broadcastJson));}@Overridepublic void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {// WebSocket连接关闭clients.remove(session.getId());System.out.println("连接关闭: " + session.getId());}private void broadcastMessage(TextMessage message) {// 遍历所有Session,发送消息for (WebSocketSession client : clients.values()) {try {if (client.isOpen()) {client.sendMessage(message);}} catch (IOException e) {// 处理异常}}}
}
3. 客户端开发(JavaScript)
现代浏览器都提供了原生的WebSocket对象,使用非常简单。
// 1. 建立连接(注意协议是 ws 或 wss,类似于 http 和 https)
var ws = 