BBR 与 TCP 原生拥塞控制算法的对比

 

1. 什么是拥塞控制?

要解释拥塞控制,那就要解释拥塞是什么。简单来说,拥塞是指由于带宽不足(或其他原因,但主要是带宽),导致包的主动或被动的丢失。而拥塞控制就是尽可能的减少包的丢失。

假设说没有拥塞控制算法的情况下,A 想发送 100 个数据包,由于拥塞,丢失了 99 个数据包,在这种条件下,A 只能重新传输 99 个数据包,接下来,可能又有 98 个丢失…每一次发送都会有成本,为了避免不必要的浪费,拥塞控制算法就很有必要了。

2. TCP 经典拥塞控制算法

TCP 作为传输层的协议,提供了拥塞控制算法,名字叫 Tahoe(version 1)/Reno(version 2)。他们的核心思想是:将传输速度按一定速度增加,当出现丢包等问题的时候,我们就降低传输速度(减半/变为 1),然后再次增加,如此循环。

3. TCP 拥塞控制的缺陷

TCP 的拥塞控制算法从代码层面比较好写,但是也有个明显的缺陷。

我们都知道,传输的流量为

而从上面的图可知,TCP 的拥塞算法,不可能完全利用带宽,从好的方面思考则是为其他的 TCP 连接留有空间,但是从另一个角度来说,这是一种浪费。

那么如何完美利用我们的带宽呢?

4. 符合现实的拥塞控制算法 - BBR

BBR (基于 Bottleneck Bandwidth and Round-trip 的拥塞算法) 是 Google 开源的拥塞控制算法,它的核心思想是:通过测量网络的带宽和延迟,来决定传输速度。说人话就是,我们测量出当前网络的带宽,然后就按照这个速度一直跑流量。

可是我们如何测定带宽?

BBR 会在一定的时间试探当前网络能否发送更多数据包,如果能,则增加单位时间发送的数据包,如果不能,则保持当前速度。

如图所示,BBR 算法会试探当前网络的带宽,如果能够发送更多的数据包,则会增加单位时间发送的数据包,如果不能,则保持当前速度。这样,理论情况下,我们可以完美的利用我们的带宽。

5. BBR 提升有多少?

Google 的全球广域网(B4)在 2016 年就已经将全部 TCP 流量从 CUBIC 切换到 BBR, 吞吐提升了 2~25 倍;在做了一些配置调优之后,甚至进一步提升到了 133 倍。

查看AS声明前缀与AS路由信息

 

前言

BGP 是各个 AS 之间通讯的协议,它的作用是将 AS 内部的路由信息传递给其他 AS,以便于实现跨 AS 的路由。

查看 AS 声明前缀与 AS 路由信息

可以通过以下网站查看 AS 的各种信息

同样可以通过此网站查看 IP 地址的各种信息,例如 IP 所属的运营商、IP 所属的 AS 等等

bgp.he.net

示例

IPv6的邻居发现协议NDP

 

Neighbor Discovery Protocol

Neighbor Discovery Protocol 是 IPv6 中新增的协议类型,主要用于替代 IPv4 中的 ARP 协议,同时也可以替代 DHCP 服务。NDP 内容包含在 ICMPv6 中。

起到 DHCP 功效的 RS 和 RA

在 IPv6 中,我们仍可以使用 IPv4 中常用的 Dynamic Host Configuration Protocol(DHCP) 服务,这项服务在 IPv6 中叫做 DHCPv6。不过标准的制定者想必也是考虑到 Plug and Play 这种需求,因此在原生 IPv6 中,就提供了一种类似 DHCP 功能的协议,叫做 Neighbor Discovery Protocol。

DHCP 工作流程

在 DHCP 中,没有 IP 的设备插到以太网上后,设备会尝试广播一个 DHCP Discover 包,然后 DHCP 服务器会回复一个 DHCP Offer 包,然后设备再回复一个 DHCP Request 包,最后 DHCP 服务器再回复一个 DHCP Ack 包,这样就完成了 IP 地址的分配。

NDP 工作流程

在原生 IPv6 中,这个过程类似,没有 IP 的设备插到以太网上后,设备会尝试广播一个 Router Solicitation(RS) 包,当路由器收到这个组播包后(IPv6 没有广播,使用组播代替了广播)路由器会回复一个 Router Advertisement(RA) 包,RA 包的内容包括了路由器的 IP 地址,子网前缀,以及其他一些信息。此时设备会自动生成一个后缀,然后和子网前缀组合成一个 IPv6 地址,这样就完成了 IP 地址的分配。


NDP 和 DHCP 的对应表

DHCPNDP
DHCP DiscoverRouter Solicitation
DHCP OfferRouter Advertisement
DHCP RequestN/A(客户端会自动生成一个 IPv6 地址)
DHCP AckN/A

起到 ARP 功效的 NS 和 NA

ARP 协议用于解析 IP 地址和 mac 地址的对应关系,NDP 中也有类似的协议,叫做 Neighbor Solicitation(NS)和 Neighbor Advertisement(NA)。

当用户机器 A 想要和另一个机器 B 通信时,若没有机器 B 的 MAC 地址,A 会发送一个 NS 包,询问 B 的 MAC 地址,B 收到 NS 包后,会回复一个 NA 包,告诉 A 自己的 MAC 地址。这个过程和 ARP 协议中的 ARP Request 和 ARP Reply 过程类似。

ARP 和 NDP 对应表

ARPNDP
ARP RequestNeighbor Solicitation
ARP ReplyNeighbor Advertisement

综上,我们在连接到以太网后,通过 NDP 协议成功获取到了路由器的 IP 地址,也生成了自己的 IP 地址,我们也有能力获得其他设备的 IP 地址和 mac 地址,这样就可以进行通信了。

Socks5协议详解|

0. 什么是 Socks5

根据 Wiki :

SOCKS 是一种网络传输协议,名字取自 SOCKetS,主要用于客户端与外网服务器之间通讯的中间传递。

1. Socks5 协议的基本流程

1.1. 代理 TCP 链接( CMD = CONNECT

1.1.0. TCP 链接

客户端与服务器建立 TCP 连接

1.1.1. 客户端确认版本与验证方法

客户端发送握手包,包含以下内容:

VER

NMETHODS

METHODS

1 Byte

1 Byte

1~255 Bytes

VER 代表 Socks 的版本,Socks5 服务器会返回 0x05

NMETHODS 代表客户端支持的认证方式的数量

METHODS 代表客户端支持的认证方式

0x00 不需要认证

0x01 GSSAPI 认证

0x02 用户名密码认证

0x03~0x7F IANA 分配

0x80~0xFE 私人方法保留

0xFF 无可接受方法

1.1.2. 服务器确认协议版本与验证方法

服务器返回握手包,包含以下内容:

VER

METHOD

1 Byte

1 Byte

VER 代表 Socks 的版本,Socks5 服务器会返回 0x05

METHOD 代表服务器选择的认证方式,选择内容应当是客户端发送的 METHODS 中的一种,如果客户端发送的 METHODS 中没有服务器支持的认证方式,服务器会返回 0xFF

1.1.3. (可选)客户端发送用户名密码

如果服务器选择的认证方式是 0x02,那么客户端需要发送用户名密码包,包含以下内容:

VER

ULEN

UNAME

PLEN

PASSWD

1 Byte

1 Byte

N Bytes

1 Byte

N Bytes

VER 代表 Socks 的版本,Socks5 服务器会返回 0x05

ULEN 代表用户名的长度

UNAME 代表用户名

PLEN 代表密码的长度

PASSWD 代表密码(明文)

1.1.4. (可选)服务器确认用户名密码

选择了用户名密码认证的服务器在收到用户名密码包后,会返回以下内容:

VER

STATUS

1 Byte

1 Byte

VER 代表 Socks 的版本,Socks5 服务器会返回 0x05

STATUS 代表认证状态,其中:

0x00 代表认证成功

0x01 代表认证失败

1.1.5. 客户端发送连接请求包

客户端发送连接请求包,包含以下内容:

VER

CMD

RSV

ATYP

DST.ADDR

DST.PORT

1 Byte

1 Byte

1 Byte

1 Byte

N Bytes

2 Bytes

VER 代表 Socks 的版本,Socks5 服务器会返回 0x05

CMD 代表请求类型,其中:

0x01 代表 CONNECT

0x02 代表 BIND

0x03 代表 UDP ASSOCIATE

这里需要代理 TCP,所以 CMD=CONNECT,即为 0x01

RSV 保留字段,值为 0x00

ATYP 代表请求的地址类型,其中:

0x01 代表 IPv4

0x03 代表域名

0x04 代表 IPv6

DST.ADDR 代表请求的地址,

如果 ATYP IPv4,那么 DST.ADDR 4 Bytes IPv4 地址

如果 ATYP 为 域名,那么 DST.ADDR 1~255 Bytes 的域名

此时 DST.ADDR 的第一个字节代表域名的长度

如果 ATYP IPv6,那么 DST.ADDR 16 Bytes IPv6 地址

DST.PORT 代表请求的端口

1.1.6. 服务器确认连接请求包

服务器在收到连接请求包后,会返回以下内容:

VER

REP

RSV

ATYP

BND.ADDR

BND.PORT

1 Byte

1 Byte

1 Byte

1 Byte

N Bytes

2 Bytes

VER 代表 Socks 的版本,Socks5 服务器会返回 0x05

REP 代表响应状态,其中:

0x00 代表成功

0x01 代表普通 SOCKS 服务器连接失败

0x02 代表现有规则不允许连接

0x03 代表网络不可达

0x04 代表主机不可达

0x05 代表连接被拒绝

0x06 代表 TTL 过期

0x07 代表不支持的命令

0x08 代表不支持的地址类型

0x09~0xFF 保留

RSV 保留字段,值为 0x00

ATYP 代表绑定的地址类型,其中:

0x01 代表 IPv4

0x03 代表域名

0x04 代表 IPv6

BND.ADDR 代表绑定的地址,

如果 ATYP IPv4,那么 BND.ADDR 4 Bytes IPv4 地址

如果 ATYP 为 域名,那么 BND.ADDR 1~255 Bytes 的域名

此时 BND.ADDR 的第一个字节代表域名的长度

如果 ATYP IPv6,那么 BND.ADDR 16 Bytes IPv6 地址

BND.PORT 代表绑定的端口

1.1.7. 客户端与服务器通讯

此时客户端或服务端发送到任意数据包都将由中转服务器转发

1.2. 代理 UDP 链接( CMD = UDP ASSOCIATE

1.2.0. TCP 链接

客户端与服务器建立 TCP 连接

1.2.1. 客户端确认版本与验证方法

客户端发送握手包,包含以下内容:

VER

NMETHODS

METHODS

1 Byte

1 Byte

1~255 Bytes

VER 代表 Socks 的版本,Socks5 服务器会返回 0x05

NMETHODS 代表客户端支持的认证方式的数量

METHODS 代表客户端支持的认证方式

0x00 不需要认证

0x01 GSSAPI 认证

0x02 用户名密码认证

0x03~0x7F IANA 分配

0x80~0xFE 私人方法保留

0xFF 无可接受方法

1.2.2. 服务器确认协议版本与验证方法

服务器返回握手包,包含以下内容:

VER

METHOD

1 Byte

1 Byte

VER 代表 Socks 的版本,Socks5 服务器会返回 0x05

METHOD 代表服务器选择的认证方式,选择内容应当是客户端发送的 METHODS 中的一种,如果客户端发送的 METHODS 中没有服务器支持的认证方式,服务器会返回 0xFF

1.2.3. (可选)客户端发送用户名密码

如果服务器选择的认证方式是 0x02,那么客户端需要发送用户名密码包,包含以下内容:

VER

ULEN

UNAME

PLEN

PASSWD

1 Byte

1 Byte

N Bytes

1 Byte

N Bytes

VER 代表 Socks 的版本,Socks5 服务器会返回 0x05

ULEN 代表用户名的长度

UNAME 代表用户名

PLEN 代表密码的长度

PASSWD 代表密码(明文)

1.2.4. (可选)服务器确认用户名密码

选择了用户名密码认证的服务器在收到用户名密码包后,会返回以下内容:

VER

STATUS

1 Byte

1 Byte

VER 代表 Socks 的版本,Socks5 服务器会返回 0x05

STATUS 代表认证状态,其中:

0x00 代表认证成功

0x01 代表认证失败

1.2.5. 客户端发送转发请求包

客户端发送连接请求包,包含以下内容:

VER

CMD

RSV

ATYP

DST.ADDR

DST.PORT

1 Byte

1 Byte

1 Byte

1 Byte

N Bytes

2 Bytes

VER 代表 Socks 的版本,Socks5 服务器会返回 0x05

CMD 代表请求类型,其中:

0x01 代表 CONNECT

0x02 代表 BIND

0x03 代表 UDP ASSOCIATE

这里需要代理 UDP,所以 CMD=UDP ASSOCIATE,即为 0x03

RSV 保留字段,值为 0x00

ATYP 代表请求的地址类型,其中:

0x01 代表 IPv4

0x03 代表域名

0x04 代表 IPv6

注意: 与 CONNECT 不同的是,DST.ADDR 不再代表请求的地址,而是代表客户端期望发送 UDP 数据包的 Socket,也就是说,DST.ADDR 代表客户端的地址,DST.PORT 代表客户端的端口(用于发送 UDP 数据包的端口)

如果 ATYP IPv4,那么 DST.ADDR 4 Bytes IPv4 地址

如果 ATYP 为 域名,那么 DST.ADDR 1~255 Bytes 的域名

此时 DST.ADDR 的第一个字节代表域名的长度

如果 ATYP IPv6,那么 DST.ADDR 16 Bytes IPv6 地址

1.2.6. 服务器确认转发请求包

服务器在收到连接请求包后,会返回以下内容:

VER

REP

RSV

ATYP

BND.ADDR

BND.PORT

1 Byte

1 Byte

1 Byte

1 Byte

N Bytes

2 Bytes

VER 代表 Socks 的版本,Socks5 服务器会返回 0x05

REP 代表响应状态,其中:

0x00 代表成功

0x01 代表普通 SOCKS 服务器连接失败

0x02 代表现有规则不允许连接

0x03 代表网络不可达

0x04 代表主机不可达

0x05 代表连接被拒绝

0x06 代表 TTL 过期

0x07 代表不支持的命令

0x08 代表不支持的地址类型

0x09~0xFF 保留

RSV 保留字段,值为 0x00

ATYP 代表绑定的地址类型,其中:

0x01 代表 IPv4

0x03 代表域名

0x04 代表 IPv6

注意: 与 CONNECT 不同的是,这里的 BND.ADDR 代表服务器监听的 UDP 的地址BND.PORT 代表服务器监听的 UDP 的端口,也就是说,BND.ADDR 代表服务器的地址,BND.PORT 代表服务器的端口(用于接收 UDP 数据包的端口)

如果 ATYP IPv4,那么 BND.ADDR 4 Bytes IPv4 地址

如果 ATYP 为 域名,那么 BND.ADDR 1~255 Bytes 的域名

此时 BND.ADDR 的第一个字节代表域名的长度

如果 ATYP IPv6,那么 BND.ADDR 16 Bytes IPv6 地址

1.2.7. 客户端断开 TCP 链接

根据规定,此时应由客户端断开 TCP 链接

1.2.8 客户端向服务器发送 UDP 数据包

客户端向服务器发送 UDP 数据包,UDP 数据包封装格式如下:

RSV

FRAG

ATYP

DST.ADDR

DST.PORT

DATA

2 Bytes

1 Byte

1 Byte

N Bytes

2 Bytes

N Bytes

RSV 保留字段,值为 0x0000

FRAG 代表分段,以下为定义:

0x00 代表不分段

0x01-0x7F 用于分段

注意,当最高位为 1 时,代表结束分段,即 0x80-0xFF 用于结束分段

例:当最后一个包为 0x85 时,代表这是第 5 个分段,且这是最后一个分段

注:应用应当尽可能避免分段

ATYP 代表请求的地址类型,其中:

0x01 代表 IPv4

0x03 代表域名

0x04 代表 IPv6

DST.ADDR 代表请求的地址,

如果 ATYP IPv4,那么 DST.ADDR 4 Bytes IPv4 地址

如果 ATYP 为 域名,那么 DST.ADDR 1~255 Bytes 的域名

此时 DST.ADDR 的第一个字节代表域名的长度

如果 ATYP IPv6,那么 DST.ADDR 16 Bytes IPv6 地址

DST.PORT 代表请求的端口

DATA 代表数据

中转服务器收到数据后,会将数据转发给目标服务器,然后将目标服务器的响应转发给客户端。

中转服务器返回数据时同样遵守上述格式

1.3. 绑定命令( CMD = BIND

这个命令使用的很少,几乎大部分客户端都不支持,根据 RFC 文档,这个命令可以使用在 FTP 传输数据。(FTP 都几乎没有人在使用了,因此这个命令使用很少)

BIND 代表客户端请求中转服务器开放一个端口,用于外部连接,即"穿透"效果。

1.3.0. TCP 链接

客户端与服务器建立 TCP 连接

1.3.1. 客户端确认版本与验证方法

客户端发送握手包,包含以下内容:

VER

NMETHODS

METHODS

1 Byte

1 Byte

1~255 Bytes

VER 代表 Socks 的版本,Socks5 服务器会返回 0x05

NMETHODS 代表客户端支持的认证方式的数量

METHODS 代表客户端支持的认证方式

0x00 不需要认证

0x01 GSSAPI 认证

0x02 用户名密码认证

0x03~0x7F IANA 分配

0x80~0xFE 私人方法保留

0xFF 无可接受方法

1.3.2. 服务器确认协议版本与验证方法

服务器返回握手包,包含以下内容:

VER

METHOD

1 Byte

1 Byte

VER 代表 Socks 的版本,Socks5 服务器会返回 0x05

METHOD 代表服务器选择的认证方式,选择内容应当是客户端发送的 METHODS 中的一种,如果客户端发送的 METHODS 中没有服务器支持的认证方式,服务器会返回 0xFF

1.3.3. (可选)客户端发送用户名密码

如果服务器选择的认证方式是 0x02,那么客户端需要发送用户名密码包,包含以下内容:

VER

ULEN

UNAME

PLEN

PASSWD

1 Byte

1 Byte

N Bytes

1 Byte

N Bytes

VER 代表 Socks 的版本,Socks5 服务器会返回 0x05

ULEN 代表用户名的长度

UNAME 代表用户名

PLEN 代表密码的长度

PASSWD 代表密码

1.3.4. (可选)服务器确认用户名密码

选择了用户名密码认证的服务器在收到用户名密码包后,会返回以下内容:

VER

STATUS

1 Byte

1 Byte

VER 代表 Socks 的版本,Socks5 服务器会返回 0x05

STATUS 代表认证状态,其中:

0x00 代表认证成功

0x01 代表认证失败

1.3.5. 客户端发送请求包

客户端发送连接请求包,包含以下内容:

VER

CMD

RSV

ATYP

DST.ADDR

DST.PORT

1 Byte

1 Byte

1 Byte

1 Byte

N Bytes

2 Bytes

VER 代表 Socks 的版本,Socks5 服务器会返回 0x05

CMD 代表请求类型,其中:

0x01 代表 CONNECT

0x02 代表 BIND

0x03 代表 UDP ASSOCIATE

此处需要绑定,所以 CMD=BIND,即为 0x02

RSV 保留字段,值为 0x00

ATYP 代表请求的地址类型,其中:

0x01 代表 IPv4

0x03 代表域名

0x04 代表 IPv6

DST.ADDR DST.PORT 代表可能的外部来源地址和端口(外部客户端/服务器尝试连接 Socks 服务器时外部客户端/服务器使用的地址与端口)。

如果 ATYP IPv4,那么 DST.ADDR 4 Bytes IPv4 地址

如果 ATYP 为 域名,那么 DST.ADDR 1~255 Bytes 的域名

此时 DST.ADDR 的第一个字节代表域名的长度

如果 ATYP IPv6,那么 DST.ADDR 16 Bytes IPv6 地址

1.3.6. 服务器确认绑定地址

服务器在收到连接请求包后,会返回以下内容:

VER

REP

RSV

ATYP

BND.ADDR

BND.PORT

1 Byte

1 Byte

1 Byte

1 Byte

N Bytes

2 Bytes

VER 代表 Socks 的版本,Socks5 服务器会返回 0x05

REP 代表响应状态,其中:

0x00 代表成功

0x01 代表普通 SOCKS 服务器连接失败

0x02 代表现有规则不允许连接

0x03 代表网络不可达

0x04 代表主机不可达

0x05 代表连接被拒绝

0x06 代表 TTL 过期

0x07 代表不支持的命令

0x08 代表不支持的地址类型

0x09~0xFF 保留

RSV 保留字段,值为 0x00

ATYP 代表绑定的地址类型,其中:

0x01 代表 IPv4

0x03 代表域名

0x04 代表 IPv6

BIND.ADDR BIND.PORT 代表中转服务器绑定的地址和端口,即"穿透"后的地址和端口,共外部客户端/服务器连接。

如果 ATYP IPv4,那么 BND.ADDR 4 Bytes IPv4 地址

如果 ATYP 为 域名,那么 BND.ADDR 1~255 Bytes 的域名

此时 BND.ADDR 的第一个字节代表域名的长度

如果 ATYP IPv6,那么 BND.ADDR 16 Bytes IPv6 地址

1.3.7. 服务器通知外部链接包

当外部客户端/服务器连接中转服务器时,中转服务器会向客户端发送以下内容:

VER

REP

RSV

ATYP

BND.ADDR

BND.PORT

1 Byte

1 Byte

1 Byte

1 Byte

N Bytes

2 Bytes

详细定义同上,但是 BIND.ADDR BIND.PORT 代表外部客户端/服务器的地址和端口。

1.3.8. 客户端与服务器通讯

此时客户端或服务端发送到任意数据包都将由中转服务器转发

2. 参考

WebSocket 是什么?——从实时通信的演进到全双工协议的深度解析

在互联网技术飞速发展的今天,我们已经习惯了网页上的“实时性”:社交软件上的消息秒回、股票行情曲线的实时跳动、多人协作文档中的光标同步,以及网络游戏中的低延迟互动。在这些技术的背后,除了传统的 HTTP 协议外,一个至关重要的主角便是 WebSocket

本文将带你深入了解 WebSocket 的前世今生、工作原理、核心优势,以及它如何改变了现代 Web 应用的开发范式。


一、 诞生背景:为什么需要 WebSocket?

在 WebSocket 出现之前,Web 浏览器与服务器之间的通信主要依赖于 HTTP 协议。HTTP 协议的设计初衷是“请求-响应”模式,即客户端发送一个请求,服务器返回一个响应。这种模式在处理静态网页时非常完美,但在处理“实时数据更新”时却显得捉襟见肘。

1. HTTP 的局限性

  • 单向性(Half-Duplex): 只有客户端能发起请求,服务器无法主动推送数据给客户端。
  • 高开销(Overhead): 每一个 HTTP 请求都包含大量的 Header(头部信息),对于频繁传输的小型数据包(如心跳包)来说,这种开销是巨大的。
  • 无状态性: 虽然 Cookie 和 Session 解决了身份识别问题,但每个请求依然是独立的,维护长连接的成本很高。

2. 传统“伪实时”方案

在 WebSocket 普及前,开发者通常采用以下几种折中方案:

  • 短轮询(Short Polling): 客户端每隔几秒发一个请求问服务器:“有新消息吗?”。缺点:大量无效请求浪费带宽和服务器资源。
  • 长轮询(Long Polling): 客户端发起请求,服务器挂起请求,直到有新数据才返回。缺点:虽然减少了请求数,但服务器依然需要维持大量挂起的连接,且每次连接建立仍需握手。
  • SSE(Server-Sent Events): 服务器向客户端单向推送。缺点:仅支持单向通信。

为了解决这些痛点,2011 年,IETF 制定了 RFC 6455 标准,正式定义了 WebSocket 协议。


二、 什么是 WebSocket?

WebSocket 是一种在单个 TCP 连接上进行 全双工(Full-Duplex) 通信的协议。

它允许服务端主动向客户端推送数据,同时也允许客户端随时向服务端发送数据。一旦握手成功,客户端和服务器之间就建立了一条持久的、双向的“隧道”,数据可以像流水一样在两端自由流动。

核心特征:

  1. 持久连接: 一次握手,终身受益(除非主动关闭)。
  2. 全双工: 双方可以同时发送和接收数据。
  3. 轻量级: 数据帧头部非常小(通常只有 2 到 14 字节),远低于 HTTP 头部。
  4. 跨域支持: 协议本身支持跨域通信。
  5. 协议标识符: 使用 ws://(非加密)和 wss://(加密,基于 TLS/SSL)。

三、 WebSocket 的工作流程图

为了更直观地理解 WebSocket 的工作过程,我们可以将其分为 握手阶段数据传输阶段


四、 核心原理详解

1. 握手(The Handshake)

WebSocket 的巧妙之处在于利用了 HTTP 协议来完成初始握手。这使得它能够兼容现有的 Web 基础设施(如 80/443 端口、防火墙、代理服务器)。

  • 客户端请求: 客户端发送一个特殊的 HTTP GET 请求,包含以下关键头部:
    <HTTP>
    GET /chat HTTP/1.1
    Host: example.com
    Upgrade: websocket <-- 告诉服务器我要升级协议
    Connection: Upgrade <-- 连接类型为升级
    Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== <-- 随机字符串,用于安全验证
    Sec-WebSocket-Version: 13
  • 服务端响应: 如果服务器支持 WebSocket,会返回 101 Switching Protocols 状态码:
    <HTTP>
    HTTP/1.1 101 Switching Protocols
    Upgrade: websocket
    Connection: Upgrade
    Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo= <-- 根据 Key 计算出的签名

一旦收到 101 响应,HTTP 协议的任务就完成了,连接正式切换到 WebSocket 协议。

2. 数据帧(Data Framing)

在 WebSocket 中,数据被切分成一个个“帧”(Frame)。

  • 控制帧: 用于管理连接(如 Close、Ping、Pong)。
  • 数据帧: 承载实际内容(Text 文本或 Binary 二进制)。 由于没有了冗长的 HTTP 头部,WebSocket 的数据传输效率极高。

五、 WebSocket vs HTTP:深度对比

特性HTTP (1.1)WebSocket
连接方式短连接(或 Keep-alive 伪长连接)持久长连接
通信模式单向(请求-响应)双向全双工
头部开销很大(几百到几千字节)极小(2-14 字节)
实时性差(依赖轮询)极高(实时推送)
服务器压力频繁创建/销毁连接压力大维持大量长连接压力大(需优化内存)
场景静态资源、API 接口聊天、直播、游戏、实时监控

六、 WebSocket 的实际应用场景

  1. 即时通讯(IM): 微信网页版、飞书、Slack 等消息的实时收发。
  2. 实时金融行情: 股票、加密货币价格的秒级跳动。
  3. 多人协作工具: 如 Google Docs、Figma,多个人同时编辑一个文档并看到对方的光标。
  4. 在线竞技游戏: 动作类或射击类游戏需要极低的指令延迟。
  5. 物联网(IoT): 智能家居设备状态的实时监控与控制。
  6. 实时通知系统: 网站右下角的弹窗提醒、系统报警。

七、 进阶话题:挑战与解决方案

虽然 WebSocket 很强大,但在实际工程中也会遇到挑战:

1. 心跳检测(Heartbeat)

网络环境复杂(如移动网络切换、代理服务器超时),连接可能会“假死”。

  • 方案: 客户端定时发送 Ping,服务器回复 Pong。如果一段时间没收到回应,则认为连接已断开,触发重连机制。

2. 负载均衡

传统的负载均衡器(如 Nginx)需要特殊配置才能支持 WebSocket,因为它是长连接。

  • 方案: 在 Nginx 配置中开启 proxy_set_header Upgrade $http_upgrade。同时,由于长连接的特性,服务器集群需要解决“Session 共享”或“消息广播”问题(通常配合 Redis Pub/Sub 使用)。

3. 安全性(WSS)

就像 HTTPS 之于 HTTP,WSS 是 WebSocket 的加密版本。

  • 建议: 在生产环境中务必使用 wss://,以防止中间人攻击和数据篡改,同时绕过某些防火墙对非标准协议的拦截。

八、 总结

WebSocket 的出现是 Web 通信技术的一次革命。它打破了 HTTP 协议“一问一答”的局限,为 Web 应用注入了真正的“实时”灵魂。

虽然随着 HTTP/2 和 HTTP/3(QUIC)的普及,HTTP 协议也开始支持多路复用和服务器推送,但 WebSocket 在双向对称通信、低延迟控制流以及二进制流处理方面,依然是目前最成熟、兼容性最好的首选方案。

如果你正在构建一个需要频繁数据交互、追求极致用户体验的现代应用,WebSocket 无疑是你技术栈中不可或缺的一环。