WebRTC数据通道是一种直接建立在浏览器之间的传输通道,专门用于传输非媒体流的数据。它为 Web开发人员提供了一种灵活且可配置的方式,可绕开服务器直接交互数据。使用信令服务器也可以传输数据,但相比基于Socket.IO的信令服务器,数据通道具有以下特点。
数据通道支持传输字符串、文件、图片等数据。数据通道API的使用方式与WebSocket非常相似,但是 WebSocket运行于TCP之上,而数据通道则运行于SCTP之上。
流控制传输协议(Stream Control Transmission Protocol,SCTP)是在 2000年由 IETF 的 SIGTRAN 工作组定义的一个传输层协议。它是面向连接、端到端、全双工、带有流量和拥塞控制的可靠传输协议,与TCP和UDP处于同一级别,可以直接运行在IP之上。
SCTP的连接称为关联。SCTP支持多流机制,一个关联可以有多个流,每个流都给定一个编号,编号包含在SCTP报文中。关联中的流相互独立,一个流出现阻塞不会影响同一关联中的其他流。相比之下,类似的阻塞问题在TCP中却很容易出现。
SCTP 与 TCP、UDP 的对比 | |||
对比项 | TCP | UDP | SCTP |
可靠性 | 可靠 | 不可靠 | 可配置可靠、不可靠两种模式。默认使用可靠模式 |
数据包分发 | 有序 | 无序 | 可配置有序、无序两种方式。默认使用有序方式 |
传输 | 面向字节 | 面向消息 | 面向消息 |
流控 | 支持 | 不支持 | 支持 |
拥塞控制 | 支持 | 不支持 | 支持 |
SCTP采用的是类似TCP的流控和拥塞控制机制,但有所增强。整个传输过程分为慢启动阶段和拥塞避免阶段。与TCP不同的是,SCTP的拥塞窗口的初始值是2个MTU,可以获得比 TCP更快的窗口增长。SCTP的拥塞控制采用了选择确认(SACK)快速重传和快速恢复组合的方式,是TCP各种主流改进机制的集成。因为SCTP采用了块结构和控制块机制,所以可以比TCP有更高的传输性能。由于SCTP有多条通往对端的路径,所以在发送端,它对每一条路径都有一套拥塞控制参数。这类似于有多个通往对端的TCP连接,SCTP为多条路径的流量控制和拥塞控制提供统一的管理机制。
SCTP提供多宿主特性,单个SCTP端点能够支持多个IP地址。该特性为应用程序提供了比TCP更高的可用性。如果一台主机有多个网络接口,且能够通过多个IP地址访问该主机,则这台主机就是多宿主主机。
SCTP使用“关联”一词代替TCP使用的“连接”,这样做的原因是,一个连接只涉及两个IP地址间端到端的通信,而一个关联指代两台主机之间的通信,它可能涉及两个以上IP地址的通信。当端点之间建立一个关联之后,如果某个网络链路发生故障,SCTP就可以切换到关联的另一个地址继续提供服务,从而避免了网络故障导致的服务中断。
SCTP通过自带的心跳机制(heartbeat)可以探测网络链路的可用性,如果某条链路上的心跳超出设定值仍没有响应,则认为该链路不可用。
建立SCTP关联须通过4次握手,关闭SCTP的关联则需要3次握手,同时,数据只有在关联建立之后和关联关闭之前才可以发送。与TCP不同,SCTP不支持半连接状态,也就是说任何一方关闭关联后,对方便不能再发送数据了。下图展示了TCP和SCTP的建立连接过程。
TCP的3次握手带来了一些安全问题。为了建立TCP连接,首先客户端向服务器端发送一个SYN报文,然后服务器端回复SYN-ACK报文进行确认,接着客户端使用ACK报文确认已接收到报文,最终成功建立连接。如果恶意客户端使用虚假的源地址伪造IP报文,TCP的安全问题就暴露出来了。例如,恶意客户端发送大量SYN报文,对服务器端造成攻击。服务器端收到SYN报文后,要为连接分配资源,在大量产生SYN报文的情况下最终耗尽自己的资源,无法处理新的请求。这种情况就是遭到了SYN Flooding 攻击。
SCTP可以通过4次握手的机制及引人 cookie 的概念,有效阻止 SYN Flooding 攻击。在 SCTP 中,客户端使用一个 INIT 报文请求建立关联,服务器端收到 INIT 报文后使用 INIT-ACK 报文进行响应,其中包括了 cookie(关联的唯一标识)。客户端随后使用 COOKIE-ECHO 报文进行响应,其中包含了服务器端发送的cookie。现在,服务器端可以为这个关联分配资源了,并通过向客户端发送一个 COOKIE-ACK 报文对其进行响应,最后成功建立关联。
为了避免 SYN Flooding 攻击,SCTP还采用了一种比较“聪明”的办法,即服务器端不维护半连接信息,而是把半连接信息发送给客户端,如果客户端确实需要建立这个连接。再把半连接信息返回服务器端,这时服务器端就可以根据返回的半连接信息建立连接了。
下图展示了TCP与SCTP关闭过程的对比。在TCP中,建立连接的一方可以关闭自己的套接字(socket),然后发送FIN报文说明这个端点不会再发送数据,但是在关闭套接字之前,它仍然可以继续接收数据,这个状态被称为TCP连接的半关闭状态。
实际上,应用程序很少使用这种半关闭状态,因此SCTP的设计者选择放弃这种状态并将其替换成一个显式的终结序列。在SCTP中,当一方关闭自己的套接字时,会产生一个SHUTDOWN原语,此时建立关联的双方需要全部关闭,且将来任何一方都不允许再进行数据传输了。
SCTP是一种面向消息的传输协议,从上层应用传递下来的数据以消息的形式传输。为便于传输,SCTP提供消息的拆分和组装,以及消息的传输功能。
SCTP进行数据传输的基本单位是块。每个SCTP包含一个SCTP公共标头、一个或多个块。块有两种基本类型: 控制块和数据块。控制块用于SCTP的连接控制,如连接的建立、关闭、传输路径的维护等;数据块用于传送应用层的用户数据。上层用户的每一个消息均被封装在一个数据块中,如果消息长度大于传输路径的最大传输单元(MTU),则消息将被拆分成多个数据块传输,在接收端组装后再向上层提交。如果消息较短,则多个消息可以放入同一个 SCTP 包中,但要求总体大小不能超过MTU,即多个数据块共用一个头部,从而提高传输效率。数据块可以和控制块封装在同一个SCTP包进行传输。
SCTP数据包公共的标头部分占用数据包的前12个字节,如下表所示。
SCTP 数据包标头 | ||||
位 | 0-7 | 8-15 | 16-23 | 24-31 |
0 | 源端口 | 目标端口 | ||
32 | 校验标签 | |||
64 | 校验和 | |||
96 | 块1类型 | 块1标记 | 块1长度 | |
128 | 块1数据 | |||
... | 块N类型 | 块N标记 | 块N长度 | |
... | 块N数据 |
标头各个字段的说明如下。