0%

webSocket简介

WebSocket 详解与实践拓展

WebSocket 作为一种在 TCP 协议之上的应用层协议,解决了 HTTP 协议在实时通信场景中的局限性,为客户端与服务器之间提供了高效的双向全双工通信能力。下面将从核心特性、工作机制、代码实践及拓展应用等方面进行详细阐述。

WebSocket 核心特性

  1. 双向全双工通信
    连接建立后,客户端和服务器可随时向对方发送数据,无需等待对方响应,通信效率远高于 HTTP 的请求 - 响应模式。
  2. 持久连接
    一旦通过握手建立连接,会保持持久化状态,避免 HTTP 每次通信都需重新建立连接的开销。
  3. 协议对称性
    连接建立后,客户端与服务器的通信地位平等,没有严格的 “请求方” 与 “响应方” 之分。
  4. 多客户端支持
    单个服务器可同时接纳多个客户端连接,而客户端通常只连接一个服务器。

WebSocket 工作流程

1. 握手阶段(协议升级)

客户端通过 HTTP 请求发起握手,核心是请求将协议从 HTTP 升级为 WebSocket。

  • 客户端请求头关键字段
    • Upgrade: websocket:声明要升级到 WebSocket 协议
    • Connection: Upgrade:配合 Upgrade 字段,确认协议升级意图
    • Sec-WebSocket-Key:随机字符串,用于服务器验证并生成 Sec-WebSocket-Accept
    • Sec-WebSocket-Version: 13:指定 WebSocket 协议版本(当前主流版本)
  • 服务器响应头关键字段
    • HTTP/1.1 101 Switching Protocols:表示协议切换成功
    • Sec-WebSocket-Accept:由服务器通过 Sec-WebSocket-Key 计算生成,客户端会验证该值以确认握手成功

2. 数据传输阶段

握手成功后,双方通过 WebSocket 帧格式传输数据,支持文本、二进制等类型。传输过程中可随时发送消息,无需额外的请求头开销。

3. 连接关闭阶段

任意一方可主动关闭连接,关闭时会触发 onclose 事件,并可携带关闭原因(如正常关闭、协议错误等)。

WebSocket 端点与 URI

端点 URI 格式

WebSocket 端点的 URI 格式为:

1
2
ws://host:port/path?query  // 非加密连接
wss://host:port/path?query // 加密连接(基于 TLS/SSL)
  • ws/wss:分别对应非加密和加密的 WebSocket 协议
  • host:port:服务器地址和端口(默认端口与 HTTP 一致:ws 为 80,wss 为 443)
  • path?query:资源路径和查询参数,用于标识具体的 WebSocket 端点

前端实现(JavaScript)

通过 WebSocket 对象创建连接并处理通信,核心代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 1. 创建 WebSocket 连接
const ws = new WebSocket("ws://localhost:8080/echo");

// 2. 连接建立成功(open 事件)
ws.onopen = (event) => {
console.log("连接已建立,可发送消息");
ws.send("Hello, Server!"); // 发送文本消息
};

// 3. 接收服务器消息(message 事件)
ws.onmessage = (event) => {
console.log("收到服务器消息:", event.data); // event.data 为消息内容(文本或二进制)
};

// 4. 连接错误(error 事件)
ws.onerror = (event) => {
console.error("连接错误:", event);
};

// 5. 连接关闭(close 事件)
ws.onclose = (event) => {
console.log(`连接关闭,代码:${event.code},原因:${event.reason}`);
};

// 主动关闭连接(可选)
// ws.close(1000, "客户端主动关闭"); // 1000 表示正常关闭

注意send 方法需在 onopen 事件触发后调用,否则会失败。

后端实现(Java)

Java 中可通过 JSR-356 规范(javax.websocket API)实现 WebSocket 服务器,需引入依赖:

1
2
3
4
5
6
<dependency>
<groupId>javax.websocket</groupId>
<artifactId>javax.websocket-api</artifactId>
<version>1.1</version>
<scope>provided</scope> <!-- 容器(如 Tomcat)通常已内置实现 -->
</dependency>

方式 1:编程式端点(继承 Endpoint)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;

// 注册端点路径
@ServerEndpoint("/test")
public class TestWebSocket extends Endpoint {

// 连接建立时触发
@Override
public void onOpen(Session session, EndpointConfig config) {
System.out.println("新客户端连接,会话 ID:" + session.getId());

// 注册消息处理器(处理客户端发送的消息)
session.addMessageHandler(new MessageHandler.Whole<String>() {
@Override
public void onMessage(String message) {
System.out.println("收到消息:" + message);
try {
// 向客户端发送响应
session.getBasicRemote().sendText("服务器已收到:" + message);
} catch (IOException e) {
e.printStackTrace();
}
}
});
}

// 连接关闭时触发
@Override
public void onClose(Session session, CloseReason reason) {
System.out.println("连接关闭,原因:" + reason.getReasonPhrase());
}

// 连接错误时触发
@Override
public void onError(Session session, Throwable throwable) {
System.err.println("连接错误:" + throwable.getMessage());
}
}

方式 2:注解式端点(简化开发)

通过注解直接定义端点行为,无需继承 Endpoint

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;

@ServerEndpoint("/echo") // 端点路径
public class EchoEndpoint {

// 接收文本消息(自动关联 message 事件)
@OnMessage
public void onMessage(Session session, String message) throws IOException {
System.out.println("收到消息:" + message);
session.getBasicRemote().sendText("回声:" + message); // 发送响应
}

// 连接建立(对应 onOpen)
@OnOpen
public void onOpen(Session session) {
System.out.println("客户端连接:" + session.getId());
}

// 连接关闭(对应 onClose)
@OnClose
public void onClose(Session session, CloseReason reason) {
System.out.println("连接关闭:" + reason.getReasonPhrase());
}

// 连接错误(对应 onError)
@OnError
public void onError(Session session, Throwable throwable) {
System.err.println("错误:" + throwable.getMessage());
}
}

WebSocket 与 HTTP 的对比

特性 WebSocket HTTP
连接类型 持久连接 短连接(每次请求后关闭)
通信方向 双向全双工 单向(请求 - 响应)
协议头 握手阶段使用 HTTP 头,之后无 每次请求都带完整头信息
适用场景 实时通信(聊天、监控等) 普通数据请求(页面加载等)
连接建立开销 一次握手,长期复用 每次请求都需建立连接

常见应用场景

  1. 实时聊天系统:如网页版即时通讯工具,支持双方实时收发消息。
  2. 实时数据监控:如股票行情、服务器性能指标实时展示。
  3. 多人协作工具:如在线文档同时编辑,实时同步内容变更。
  4. 游戏实时交互:如网页多人游戏,同步玩家操作和状态

欢迎关注我的其它发布渠道

表情 | 预览
快来做第一个评论的人吧~
Powered By Valine
v1.3.10