面试里常有人把这三个放一起问:"WebSocket、Socket、TCP 有什么区别?"其实它们根本不在一个层次上——TCP 是协议,Socket 是编程接口,WebSocket 是应用层协议。把它们并列比较,本身就有点像问"汽车、方向盘、高速公路有什么区别"。
先用一张图理清它们的位置:
应用层 HTTP / WebSocket / FTP / SMTP
↑
运输层 TCP / UDP
↑
网络层 IP
↑
链路层 以太网 / WiFi
而 Socket 是贯穿在代码里的"编程接口",
不是某一层的协议,而是操作系统提供给应用读写网络数据的抽象。
这篇分别讲清三者是什么、各自解决什么问题,最后给出对比和选型。
一、TCP:运输层的可靠传输协议
TCP(Transmission Control Protocol,传输控制协议)工作在运输层,负责在两个进程之间建立一条可靠的、面向连接的、基于字节流的通道。
它解决的问题是:IP 层只负责把包"尽力送到",不保证顺序、不保证不丢、不保证不重复。TCP 在这之上补齐了这些:
- 面向连接:通信前要三次握手建立连接,结束后四次挥手断开。
- 可靠传输:丢包重传、超时重传、确认应答(ACK)。
- 有序交付:给字节编号,接收端按序重组。
- 流量控制:滑动窗口,防止发送方压垮接收方。
- 拥塞控制:慢启动、拥塞避免,防止压垮网络。
三次握手:
Client → SYN → Server
Client ← SYN + ACK ← Server
Client → ACK → Server
连接建立,双方可以收发数据
一句话:TCP 是一条"不丢、不乱、可靠"的字节流管道,但不关心你在这条管道里传的是什么内容。
二、Socket:操作系统的网络编程接口
严格来说,Socket(套接字)不是协议,而是操作系统提供的一套 API / 抽象。它是应用层和运输层之间的"插座":应用程序通过 Socket 把数据交给 TCP/UDP,也从 Socket 读取收到的数据。
一个 Socket 由四元组唯一标识:
源 IP : 源端口 + 目的 IP : 目的端口
常见操作(以 Node.js 为例):
// TCP Socket:直接和运输层打交道
const net = require('net')
const server = net.createServer((socket) => {
console.log('客户端已连接:', socket.remoteAddress, socket.remotePort)
socket.on('data', (buf) => {
console.log('收到:', buf.toString())
socket.write('已收到\n') // 回写
})
socket.on('end', () => console.log('连接关闭'))
})
server.listen(9000)
客户端:
const net = require('net')
const client = net.createConnection({ port: 9000 }, () => {
client.write('hello\n')
})
client.on('data', (data) => console.log(data.toString()))
关键理解:
- Socket 是编程概念,TCP 是协议。你用 Socket,底层可能跑的是 TCP,也可能是 UDP,取决于你创建时选的类型。
- 浏览器有安全沙箱,无法直接创建裸 TCP Socket,只能通过 WebSocket、HTTP 等应用层协议间接使用网络。裸 Socket 一般出现在 Node.js、服务端、桌面/移动原生程序里。
三、WebSocket:跑在 TCP 之上的应用层协议
WebSocket 是应用层协议,定义在 RFC 6455。它借用 HTTP 完成一次"升级握手",之后就在同一条 TCP 连接上做全双工通信。
它的诞生是为了解决 HTTP 的一个痛点:HTTP 是"请求-响应"模型,服务端不能主动推消息。要实时推送,以前只能用轮询或长轮询,浪费连接和带宽。
握手过程
WebSocket 复用了 HTTP 的 80/443 端口,先发一个带 Upgrade 头的 HTTP 请求:
GET /chat HTTP/1.1
Host: example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13
服务端返回 101 Switching Protocols,连接就从 HTTP 升级为 WebSocket,之后走的是 WebSocket 自己的帧格式,不再是 HTTP 报文:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
使用示例(浏览器原生)
const ws = new WebSocket('wss://example.com/chat')
ws.onopen = () => {
console.log('连接已建立')
ws.send(JSON.stringify({ type: 'join', room: '1' }))
}
ws.onmessage = (event) => {
console.log('收到消息:', event.data)
}
ws.onclose = () => console.log('连接关闭')
ws.onerror = (err) => console.error(err)
特点:
- 全双工:客户端和服务端可以随时互发消息。
- 长连接:一次握手后连接持续复用,不必每次带一大堆 HTTP 头。
- 轻量帧:数据帧头部很小,适合高频小消息。
- 基于 TCP:它本身不处理可靠性,可靠传输、有序交付都由底下的 TCP 保证。
四、三者关系:一条客户端请求的完整路径
把三者串起来,从浏览器发一条实时消息看:
浏览器 new WebSocket(...)
→ 应用层:WebSocket 协议(握手后发送 WS 帧)
→ 运输层:交给 TCP 传输
→ 网络层:IP 寻址
→ 链路层:物理网卡发出
服务端:
→ 网卡收到 → IP 层 → TCP 层
→ 操作系统把数据交给对应的 Socket(四元组匹配)
→ 应用进程从 Socket 读到数据
→ 若上面跑的是 WebSocket,再由 WebSocket 库解析成消息
一句话概括层次关系:
- TCP:底层的可靠管道(运输层协议)。
- Socket:应用程序操作这条管道的把手(编程接口)。
- WebSocket:跑在这条管道上的实时通信协议(应用层协议)。
五、对比表
| 维度 | TCP | Socket | WebSocket |
|---|---|---|---|
| 本质 | 传输层协议 | 编程接口/抽象 | 应用层协议 |
| 所属层次 | 运输层 | 跨层(应用操作运输层) | 应用层 |
| 连接方式 | 面向连接 | 无概念(取决于协议) | 基于 TCP 长连接 |
| 数据形态 | 字节流 | 字节流读写 | 消息/帧 |
| 谁定义 | RFC 793 | 操作系统 API | RFC 6455 |
| 浏览器支持 | 不能直接用 | 不能直接创建 | 原生支持 |
| 典型用途 | 一切可靠传输的底座 | Node/服务端/原生程序 | 聊天、实时推送、协同编辑 |
六、和 HTTP、UDP 的关系
顺带把容易混的也一并理清:
- HTTP 也是应用层协议,跑在 TCP 之上,但是"请求-响应"半双工,服务端不能主动推。WebSocket 正是它的补充。
- UDP 是运输层的另一员,无连接、不保证可靠,但快、开销小,适合直播、游戏、DNS。Socket 也可以基于 UDP(
dgram),和 WebSocket 完全是两码事。 - Socket.IO 是建立在 WebSocket 之上的库(WebSocket 不可用时降级为轮询),不是协议本身,别和 WebSocket 混为一谈。
七、怎么选
| 需求 | 选择 |
|---|---|
| 服务端主动推送、实时双向通信 | WebSocket |
| 普通请求-响应、无实时性 | HTTP |
| 极低延迟、可容忍丢包 | UDP(配合 Socket) |
| 服务端/Node 里自建长连接协议 | TCP Socket |
| 需要兼容老浏览器、自动降级 | Socket.IO |
小结
- 三者层次不同:TCP 是运输层协议,Socket 是编程接口,WebSocket 是应用层协议,不能平级对比。
- TCP 负责"可靠地把字节流送到",不关心内容;WebSocket 在它之上定义了消息级、全双工的实时协议。
- Socket 是应用读写网络的把手,四元组(源 IP、源端口、目的 IP、目的端口)唯一标识一条连接。
- 浏览器不能直接开裸 TCP Socket,只能借 WebSocket/HTTP 这类应用层协议使用网络。
- 记忆口诀:TCP 是路,Socket 是门,WebSocket 是门里的对讲机。