作为后端开发者,你一定听过 Socket、WebSocket,但可能混淆二者的关系 ------ 比如 "WebSocket 是不是基于 Socket?""为什么 HTTP 需要 Filter 链,WebSocket 却不用?"。今天,我们从底层原理到实战场景,结合你关注的internalDoFilter()执行逻辑,彻底讲清 Socket 与 WebSocket 的核心区别,以及 Filter 链在不同通信模型中的应用差异。
本文适合 Java 开发、架构师,以及准备面试的同学,全程结合代码案例(包含 WebSocket Filter 适配实现),拒绝纯理论,做到 "原理 + 源码 + 落地" 三合一。
一、先搞懂:Socket 的核心本质(通信的底层基石)
1.1 Socket 是什么?
Socket(套接字)不是协议,而是操作系统提供的 "网络通信编程接口(API)",是应用层与 TCP/IP 协议族通信的中间软件抽象层。
官方定义:Socket 是对 TCP/IP 协议的封装和应用,开发者无需关注底层的三次握手、数据分包 / 粘包,只需调用 Socket API 即可实现两台主机的双向通信。
通俗比喻
Socket 就像 "电话插座"------ 两台电脑要通信,必须先插好 "插座"(建立 Socket 连接),才能通过 "电话线"(TCP/IP)传输数据;操作系统负责维护 "插座" 的连接状态,开发者只需 "拨号"(发送数据)和 "接听"(接收数据)。
1.2 Socket 的核心通信模型(TCP 为例)
TCP Socket 通信分为服务端 和客户端,核心流程遵循 "建立连接→数据传输→关闭连接" 的经典步骤:
1.2.1 核心流程(必记)

1.2.2 Java Socket 代码示例(TCP 通信)
java
// 服务端(Socket)
public class TcpSocketServer {
public static void main(String[] args) throws IOException {
// 1. 创建ServerSocket,监听8080端口
ServerSocket serverSocket = new ServerSocket(8080);
System.out.println("Socket服务端启动,监听8080端口...");
while (true) {
// 2. 阻塞等待客户端连接(TCP三次握手在此完成)
Socket socket = serverSocket.accept();
System.out.println("新客户端连接:" + socket.getInetAddress());
// 3. 处理客户端请求(单线程,实际开发用线程池)
new Thread(() -> {
try (InputStream is = socket.getInputStream();
OutputStream os = socket.getOutputStream()) {
// 接收客户端数据
byte[] buffer = new byte[1024];
int len = is.read(buffer);
String msg = new String(buffer, 0, len);
System.out.println("接收客户端数据:" + msg);
// 响应客户端
os.write(("Socket响应:" + msg).getBytes());
os.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
socket.close(); // 关闭连接(TCP四次挥手)
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
}
}
// 客户端(Socket)
public class TcpSocketClient {
public static void main(String[] args) throws IOException {
// 1. 创建Socket,连接服务端(IP+端口)
Socket socket = new Socket("localhost", 8080);
// 2. 发送数据
OutputStream os = socket.getOutputStream();
os.write("Hello Socket!".getBytes());
os.flush();
// 3. 接收响应
InputStream is = socket.getInputStream();
byte[] buffer = new byte[1024];
int len = is.read(buffer);
System.out.println("接收服务端响应:" + new String(buffer, 0, len));
// 4. 关闭连接
socket.close();
}
}
1.3 Socket 的核心特点
- 基于 TCP/UDP 协议:Socket 本身不规定传输层协议,可基于 TCP(可靠、面向连接)或 UDP(不可靠、无连接);
- 全双工通信:连接建立后,客户端和服务端可双向、同时传输数据;
- 底层通用:所有网络通信(HTTP、WebSocket、MQTT)最终都基于 Socket 实现;
- 无应用层规范:Socket 仅负责字节流传输,不规定数据格式(如 HTTP 的请求头、响应体),需开发者自行定义。

关键细节:握手阶段(HTTP 升级)
客户端发起的握手请求示例:
php
GET /ws/chat HTTP/1.1
Host: localhost:8080
Upgrade: websocket // 核心:请求升级为WebSocket协议
Connection: Upgrade // 核心:标识连接升级
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== // 随机密钥,用于验证
Sec-WebSocket-Version: 13 // 协议版本
服务端响应示例:
php
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo= // 密钥验证结果
握手完成后,TCP 连接不会关闭,而是升级为 WebSocket 连接,进入全双工数据传输阶段。
2.3 Java WebSocket 代码示例(Tomcat 实现)
java
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
/**
* WebSocket服务端(基于JSR356标准)
* @ServerEndpoint:标注WebSocket的访问路径
*/
@ServerEndpoint("/ws/chat")
public class ChatWebSocket {
/**
* 连接建立时触发(握手成功后)
*/
@OnOpen
public void onOpen(Session session) {
System.out.println("WebSocket连接建立:" + session.getId());
}
/**
* 接收客户端消息时触发
*/
@OnMessage
public void onMessage(String message, Session session) throws IOException {
System.out.println("接收客户端消息:" + message);
// 服务端主动推送消息(核心:全双工)
session.getBasicRemote().sendText("WebSocket响应:" + message);
}
/**
* 连接关闭时触发
*/
@OnClose
public void onClose(Session session) {
System.out.println("WebSocket连接关闭:" + session.getId());
}
/**
* 通信异常时触发
*/
@OnError
public void onError(Session session, Throwable error) {
error.printStackTrace();
}
}
// 客户端(HTML/JS)
/*
<!DOCTYPE html>
<html>
<head>
<title>WebSocket客户端</title>
</head>
<body>
<script>
// 创建WebSocket连接(底层基于TCP Socket)
const ws = new WebSocket("ws://localhost:8080/ws/chat");
// 连接建立成功
ws.onopen = function() {
console.log("WebSocket连接建立");
// 发送消息
ws.send("Hello WebSocket!");
};
// 接收服务端消息(主动推送)
ws.onmessage = function(event) {
console.log("接收服务端消息:" + event.data);
};
// 连接关闭
ws.onclose = function() {
console.log("WebSocket连接关闭");
};
</script>
</body>
</html>
*/
2.4 WebSocket 的核心特点
- 基于 TCP Socket 长连接:握手后连接持续保持,无需重复三次握手;
- 全双工通信:服务端可主动推送数据(如实时聊天、股票行情);
- 应用层规范:定义了数据帧格式(文本帧、二进制帧)、关闭帧等,无需开发者自定义;
- 与 HTTP 兼容:握手阶段基于 HTTP,可通过 80/443 端口传输,兼容现有网络架构(如 Nginx 反向代理);
- 轻量级:数据帧头部开销小(仅 2-10 字节),比 HTTP 请求头更高效。
三、Socket 与 WebSocket 的核心区别(表格对比 + 底层拆解)
| 维度 | Socket(套接字) | WebSocket(协议) |
|---|---|---|
| 本质 | 操作系统提供的网络通信 API(抽象层) | 基于 TCP Socket 的应用层协议(RFC6455 标准) |
| 层级 | 传输层与应用层之间的抽象层 | 应用层(依赖 Socket 底层) |
| 通信模型 | 仅提供字节流传输,无应用层规范 | 定义了握手、帧格式、关闭等完整规范 |
| 连接特性 | 可基于 TCP(长连接)或 UDP(无连接) | 仅基于 TCP 长连接(握手后持续保持) |
| 数据格式 | 无规范,开发者自行定义(如字节数组、字符串) | 标准化帧格式(文本 / 二进制 / 关闭帧) |
| 使用场景 | 所有网络通信的底层(HTTP、WebSocket、MQTT) | Web 场景下的实时通信(聊天、直播、监控) |
| 开发复杂度 | 高(需处理粘包、分包、协议解析) | 低(框架封装了底层细节,如 JSR356) |
| 与 HTTP 的关系 | HTTP 基于 Socket 实现 | 握手阶段基于 HTTP,传输阶段脱离 HTTP |
关键补充:WebSocket ≠ Socket
很多同学会混淆二者,核心结论:
WebSocket 是应用层协议 ,Socket 是底层通信 API;WebSocket 基于 TCP Socket 实现,但 Socket 不等于 WebSocket------ 就像 "HTTP 基于 TCP,但 TCP 不等于 HTTP"。
四、核心关联:Filter 链(internalDoFilter ())在二者中的应用差异
你提供的internalDoFilter()是 Servlet Filter 链的核心执行逻辑,其核心作用是 "在 HTTP 请求到达 Servlet 前,按顺序执行 Filter 的前置 / 后置逻辑"。但 Filter 链仅适用于 HTTP 请求,WebSocket 通信中无法直接使用,这是理解二者差异的关键。
4.1 Filter 链(internalDoFilter ())的适用场景
java
internalDoFilter() {
if (pos < filters.size()) {
Filter filter = filters.get(pos);
pos++;
// 执行当前 Filter 的前置逻辑
filter.doFilter(request, response, this); // 传入自身,调用下一个 Filter
} else {
// 所有 Filter 执行完毕,调用 Servlet 的 service 方法
}
}
Filter 链的核心依赖:
- HTTP 请求 - 响应模型 :Filter 接收
ServletRequest/ServletResponse,对应 HTTP 的请求和响应; - Servlet 容器生命周期:Filter 由 Tomcat 等 Servlet 容器管理,仅在 HTTP 请求流转时触发;
- 短连接特性:每次 HTTP 请求都会触发一次 Filter 链执行,符合 "请求 - 响应" 的短连接逻辑。
4.2 WebSocket 为什么不支持 Filter 链?
- 通信模型不同:WebSocket 是长连接、全双工通信,无 "请求 - 响应" 的单次流转,Filter 链的 "前置 - 后置" 逻辑无法适配;
- 数据格式不同 :WebSocket 传输的是 "帧",而非 HTTP 的请求 / 响应对象,
ServletRequest/ServletResponse无法封装 WebSocket 帧; - 生命周期不同:WebSocket 连接建立后持续存在,Filter 链是单次请求触发,无法覆盖长连接的全生命周期。
4.3 实战:WebSocket 的 "Filter 替代方案"(拦截器)
虽然 WebSocket 不支持 Servlet Filter,但可通过WebSocket 拦截器(EndpointConfig.Configurator) 实现类似的拦截逻辑,替代 Filter 链的功能:
java
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import javax.websocket.server.ServerEndpointConfig;
/**
* WebSocket拦截器(替代Filter链)
*/
public class WebSocketInterceptor extends ServerEndpointConfig.Configurator {
/**
* 握手阶段拦截(对应Filter的前置逻辑)
*/
@Override
public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
// 1. 权限校验(对应AuthFilter)
String token = (String) request.getHeaders().get("token").get(0);
if (token == null || !token.equals("admin")) {
throw new RuntimeException("WebSocket握手失败:未授权");
}
// 2. 日志记录(对应LogFilter)
System.out.println("WebSocket握手成功:" + request.getRequestURI());
// 3. 存储自定义数据(对应Filter的request.setAttribute)
sec.getUserProperties().put("userId", "1001");
}
}
// 应用拦截器的WebSocket服务端
@ServerEndpoint(value = "/ws/chat", configurator = WebSocketInterceptor.class)
public class ChatWebSocketWithInterceptor {
@OnOpen
public void onOpen(Session session, EndpointConfig config) {
// 从拦截器中获取自定义数据(替代request.getAttribute)
String userId = (String) config.getUserProperties().get("userId");
System.out.println("WebSocket连接建立,用户ID:" + userId);
}
@OnMessage
public void onMessage(String message, Session session) throws IOException {
// 业务逻辑:消息处理(对应Servlet的service方法)
session.getBasicRemote().sendText("拦截器验证通过,响应:" + message);
}
}
4.4 核心对比:Filter 链 vs WebSocket 拦截器
| 特性 | Filter 链(internalDoFilter ()) | WebSocket 拦截器 |
|---|---|---|
| 触发时机 | HTTP 请求到达时 | WebSocket 握手阶段 / 消息传输阶段 |
| 处理对象 | ServletRequest/ServletResponse | HandshakeRequest/Session/Frame |
| 核心逻辑 | 前置→Servlet→后置(单次请求) | 握手拦截→消息拦截→关闭拦截(长连接全生命周期) |
| 适用协议 | HTTP(短连接) | WebSocket(长连接) |
| 底层依赖 | Servlet 容器 | WebSocket 容器(如 Tomcat 的 WebSocket 模块) |
五、面试高频考点:Socket 与 WebSocket 核心问题
5.1 WebSocket 是如何基于 Socket 实现的?
- WebSocket 握手阶段:客户端通过 HTTP 请求(基于 TCP Socket)发起升级请求,服务端验证后返回 101 响应;
- 连接升级后:TCP Socket 连接保持,双方不再传输 HTTP 数据,而是按 WebSocket 帧格式传输数据;
- 数据传输:基于 TCP Socket 的全双工特性,服务端可主动推送帧数据到客户端。
5.2 Filter 链(internalDoFilter ())为什么不适用于 WebSocket?
核心原因:Filter 链依赖 HTTP 的 "请求 - 响应" 模型,接收ServletRequest/ServletResponse对象;而 WebSocket 是长连接、帧传输,无单次请求的流转,也无对应的请求 / 响应对象,因此无法适配。
5.3 Socket、HTTP、WebSocket 的层级关系?
php
应用层:HTTP、WebSocket、MQTT...
↓(基于)
传输层:TCP/UDP
↓(封装为)
Socket(操作系统API)
↓(基于)
网络层:IP
核心结论:Socket 是传输层的抽象 API,HTTP 和 WebSocket 是应用层协议,均基于 TCP Socket 实现。
六、总结:核心知识点回顾
- Socket 的本质:操作系统提供的网络通信 API,是所有网络通信的底层基础,无应用层规范;
- WebSocket 的本质:基于 TCP Socket 的应用层协议,专为 Web 长连接、全双工通信设计,解决 HTTP 的推送痛点;
- Filter 链的适配性 :
internalDoFilter()仅适用于 HTTP 的 "请求 - 响应" 模型,WebSocket 需用拦截器替代,核心原因是通信模型和数据格式的差异。
掌握 Socket 与 WebSocket 的区别,不仅能应对面试,更能在项目中做出正确的技术选型(如实时聊天用 WebSocket,底层通信用 Socket),理解 Filter 链在不同协议中的应用边界。