WebSocket 核心:借 HTTP 建联,做自己的通信

为什么 WebSocket 握手看起来像 HTTP 请求?它和 HTTP 到底是什么关系?TCP 在其中扮演什么角色?本文一次性讲清楚。


一、先理清三个协议的关系

在讲 WebSocket 之前,必须先搞清楚 TCP、HTTP、WebSocket 三者是什么关系。

层次关系

复制代码
                     ┌─────────────┐
                     │   HTTP      │  ← 应用层(文本协议)
                     ├─────────────┤
                     │ WebSocket   │  ← 应用层(二进制协议)
                     ├─────────────┤
                     │    TCP      │  ← 传输层
                     ├─────────────┤
                     │    IP       │  ← 网络层
                     └─────────────┘

一句话总结各自角色

协议 角色
TCP 可靠传输管道,保证数据不丢、不重、有序
HTTP 在 TCP 上定义了"请求-响应"规则,半双工
WebSocket 在 TCP 上定义了"全双工"规则,支持服务器主动推送

核心结论

TCP 是管道,HTTP 和 WebSocket 是两套独立的语言。

WebSocket 只是在打招呼的时候说了一句 HTTP 的话,让门卫放行。进去之后,它说的完全是自己的语言。


二、一个常见的误解

很多人以为 WebSocket 是 HTTP 的"升级版"或"加强版",甚至认为 WebSocket 依赖 HTTP。

真相是 :WebSocket 和 HTTP 没啥关系 ,只是握手时借用了 HTTP 的格式


三、WebSocket 的完整握手过程

整个建立连接的过程只有三步:

第 1 步:TCP 三次握手

这是传输层的事,WebSocket 和 HTTP 都绕不开:

复制代码
客户端 ──SYN──▶ 服务端
客户端 ◀─SYN+ACK─ 服务端
客户端 ──ACK──▶ 服务端

结果:TCP 连接建立,可以发数据了。


第 2 步:借 HTTP 格式完成握手

客户端发一个看起来像 HTTP 的请求:

http 复制代码
GET /chat HTTP/1.1
Host: example.com
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Version: 13

注意:这只是披着 HTTP 的外衣 ,目的不是获取 /chat 资源,而是告诉服务器:"我想把协议换成 WebSocket"。

服务端同意切换,回复:

http 复制代码
HTTP/1.1 101 Switching Protocols
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=

结果:双方达成一致,准备切换协议。


第 3 步:切换协议,用 opcode 进行长连接通信

握手完成后,双方彻底抛弃 HTTP 格式,改用 WebSocket 帧格式通信:

复制代码
客户端 ── [帧头: opcode=0x1] + "Hello" ──▶ 服务端
服务端 ── [帧头: opcode=0x1] + "World" ──▶ 客户端
(随时双向发,连接保持)

opcode(操作码) 是 WebSocket 帧里的核心字段,决定了这一帧的用途:

opcode 含义 说明
0x1 文本帧 UTF-8 文本数据
0x2 二进制帧 任意二进制数据
0x8 关闭连接 主动关闭连接
0x9 Ping 心跳探测
0xA Pong 心跳回复

这就是"opcode 沟通"------双方通过 opcode 告诉对方:这帧是文本、二进制,还是心跳、关闭。


四、为什么要"借"HTTP 格式?

直接原因:防火墙、代理、负载均衡器只认识 HTTP

如果不借 HTTP 外衣

复制代码
客户端 → 发一个自定义的握手包 → 防火墙看不懂 → 直接丢掉

借了之后

复制代码
客户端 → 发一个"看起来像 HTTP"的包 → 防火墙一看是 HTTP → 放行

本质:穿着 HTTP 的衣服混过中间设备,进去之后脱掉衣服,换上 WebSocket 自己的衣服。


五、TCP、HTTP、WebSocket 完整对比

维度 TCP HTTP WebSocket
层级 传输层 应用层 应用层
通信模式 全双工 请求-响应(半双工) 全双工
服务器主动推送 可以 ❌ 不支持 ✅ 支持
连接时长 可长可短 短(默认请求完就关) 长(一直保持)
消息边界 无(流式) 有(空行+Content-Length) 有(帧头带长度)
协议形式 二进制 文本 二进制
浏览器 JS 可用

六、为什么浏览器不直接用 TCP?

这是很多人会问的问题:既然 WebSocket 底层也是 TCP,为什么不直接给 JS 暴露 TCP API?

答案:安全。

如果 JS 能直接操作 TCP:

  • 恶意网站可以扫描你内网端口
  • 可以绕过同源策略攻击你的路由器
  • 可以伪造请求攻击内网服务

所以浏览器只开放了 HTTP 和 WebSocket 这两个"受控"的 API,不开放原始 TCP。

后端程序就不一样,Go/Java/Python 可以直接用 TCP:

go 复制代码
// 后端可以直接用 TCP
conn, _ := net.Dial("tcp", "127.0.0.1:8080")
conn.Write([]byte("自定义协议"))

七、WebSocket 的数据帧结构(了解即可)

WebSocket 帧的最小结构(2字节头 + 可变长负载):

复制代码
 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-------+-+-------------+-------------------------------+
|F|R|R|R| opcode|M| Payload len |    Extended payload length    |
|I|S|S|S|  (4)  |A|     (7)     |             (16/64)           |
|N|V|V|V|       |S|             |                               |
| |1|2|3|       |K|             |                               |
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
  • opcode:4 位,表示帧类型(文本/二进制/关闭/Ping/Pong)
  • MASK:1 位,表示是否掩码(客户端发服务器必须掩码)
  • Payload len:7 位,负载长度

对比 HTTP 头部:HTTP 每次请求几百字节头部,WebSocket 帧头只有 2-14 字节,这就是 WebSocket 更高效的原因之一。


八、常见问题 Q&A

Q1:WebSocket 和 HTTP/2 的 Server Push 有什么区别?

HTTP/2 Server Push WebSocket
推送内容 只能推送资源(如 CSS、JS、图片) 可以推送任意数据(文本、二进制、JSON)
推送时机 响应请求时顺便推 任何时候都可以推
双向通信 不支持(还是请求-响应) 支持全双工

HTTP/2 的 Server Push 是"你问 A,我顺便给你 B、C、D"。

WebSocket 是"随时可以互相发任何东西"。

Q2:WebSocket 能替代 HTTP 吗?

不能。 两者定位不同:

  • HTTP:适合 REST API、静态资源、文件上传下载
  • WebSocket:适合实时通信(聊天、游戏、行情)

各司其职。

Q3:WebSocket 的 Ping/Pong 是什么?

WebSocket 协议内置的心跳机制:

  • Ping:一方发送 Ping 帧
  • Pong:另一方回复 Pong 帧

作用:检测连接是否存活,保持 NAT 映射不过期。

对比 TCP 的 KeepAlive:TCP 的 KeepAlive 是操作系统层面的,默认 2 小时才发一次;WebSocket 的 Ping/Pong 是应用层可控的,可以按需设置频率。

Q4:为什么 WebSocket 握手必须用 101 状态码?

101 是 HTTP 协议专门预留的 Switching Protocols 状态码,表示"服务器同意切换协议"。这是 HTTP/1.1 标准的一部分,不是 WebSocket 独有。

Q5:WebSocket 和 Socket 是什么关系?

Socket WebSocket
定义 网络编程接口(API) 应用层协议
层级 传输层接口 应用层协议
关系 WebSocket 底层使用 Socket 编程实现

简单说:Socket 是编程接口,WebSocket 是协议规范。


九、一个完整的 WebSocket 示例(Go + HTML)

服务端(Go)

go 复制代码
package main

import (
    "fmt"
    "net/http"
    "github.com/gorilla/websocket"
)

var upgrader = websocket.Upgrader{
    CheckOrigin: func(r *http.Request) bool { return true },
}

func handler(w http.ResponseWriter, r *http.Request) {
    conn, _ := upgrader.Upgrade(w, r, nil)
    defer conn.Close()
    
    for {
        // 读取消息
        _, msg, _ := conn.ReadMessage()
        fmt.Printf("收到: %s\n", msg)
        
        // 回复消息
        conn.WriteMessage(websocket.TextMessage, []byte("收到: " + string(msg)))
    }
}

func main() {
    http.HandleFunc("/ws", handler)
    http.ListenAndServe(":8080", nil)
}

客户端(HTML + JS)

html 复制代码
<script>
    const ws = new WebSocket("ws://localhost:8080/ws");
    
    ws.onopen = () => {
        ws.send("Hello WebSocket!");
    };
    
    ws.onmessage = (event) => {
        console.log("收到:", event.data);
    };
</script>

十、总结

你的理解完全正确

  1. 走完 TCP 三次握手
  2. 建立 HTTP 请求(借 HTTP 形式)
  3. 进行长连接 opcode 沟通

一句话总结

WebSocket 不是 HTTP 的升级版,它只是借 HTTP 的形式完成握手,然后用自己的协议(opcode + 帧格式)在长连接上进行双向通信。

最终记忆口诀

  • 握手时:穿 HTTP 衣服
  • 握手后:脱掉 HTTP 衣服,换上 WebSocket 衣服
  • 通信时:用 opcode 告诉对方发的是什么

思考题

如果防火墙和代理都原生支持 WebSocket 协议,你觉得 WebSocket 还需要借 HTTP 的格式握手吗?

(答案:不需要,直接自定义握手就行。但现实是------它们只认 HTTP。)

相关推荐
難釋懷2 小时前
OpenResty封装http工具
http·junit·openresty
cccyi72 小时前
【C++ 脚手架】cpp-httplib 与 websocketpp 库的介绍与使用
c++·websocket·http
TON_G-T2 小时前
WebSocket实现长链接
网络·websocket·网络协议
2501_921649492 小时前
WebSocket 金融实时行情推送 API 实战解析:低延迟、高可用架构设计与落地
websocket·网络协议·金融·node.js
wqww_13 小时前
Java 前后端 WebSocket 完整实现
java·开发语言·websocket
weixin_425023003 小时前
Spring Boot 2.7+JDK8+WebSocket对接阿里云百炼Qwen3.5-Plus 实现流式对话+思考过程实时展示
java·spring boot·websocket·ai编程
王家视频教程图书馆3 小时前
你在 HTTPS 页面 里加载 HTTP 资源 → ,不支持 HTTPS → 握手失败。浏览器自动升级为 HTTPS。你的 8080 端口只支持 HTTP
网络协议·http·https
程序0073 小时前
在线五子棋小游戏(.NET Core+FreeSql+WebSocket ) html+js
websocket·html·.netcore
Mountain and sea3 小时前
从一次通讯中断事故说起:Modbus TCP 调试实战与避坑指南
网络·网络协议·tcp/ip·工业机器人