流控制传输协议(SCTP,Stream Control Transmission Protocol)是一种在网络连接两端之间同时传输多个数据流的协议。SCTP提供的服务与UDP和
TCP类似。
介绍
SCTP提供的服务与UDP和
TCP类似。SCTP在RFC2960中详细说明,并有
RFC3309加以更新。RFC 3286给出了SCTP的简要介绍。SCTP在客户和服务器之间提供关联(association),并像TCP那样给应用提供可靠性、排序、流量控制以及全双工的数据传输。SCTP中使用“关联”一词替代“连接”是为了避免这样的内涵:一个连接只涉及两个IP地址间的通信。一个关联指代两个系统之间的一次通信,它可能因为SCTP支持多宿而涉及不止两个地址。
与TCP不同的是,SCTP是面向消息的(message-oriented)。它提供各个记录的按序递送服务。与UDP一样,由发送端写入的每一条记录的长度随数据一道传递给接收端应用。
SCTP能给在所连接的端点之间提供多个流,每个流各自可靠地按序递送消息。一个流上某个消息的丢失不会阻塞同一关联其他流上消息的投递。这种做法与TCP正好相反,就TCP而言,在单一字节流中任何位置的字节丢失都将在阻塞该连接上其后所有数据的递送,直到该丢失被修复为止。
SCTP还提供多宿特性,使得单个SCTP端点能够支持多个IP地址。该特性可以增强应对网络故障的健壮性。一个端点可能有多个冗余的连接,每个网络又可能有各自接入因特网基础设施的连接。当该端点与另一个端点建立一个关联之后,如果它的某个网络或某个跨域因特网的通路发生故障,SCTP就可以通过切换到使用已与该关联的另一个地址来避免发生的故障。
报文格式
一个SCTP分组含了一个公共的分组头(Common Header)和若干数据块(Chunk),每个数据块中既可以包含控制信息,也可以包含用户数据。
除了INIT、INIT ACK和SHUTDOWN COMPLETE数据块外,其他类型的多个数据块可以捆绑在一个SCTP分组中,以满足对MTU大小的要求。当然,这些数据块也可以不与其他数据块捆绑在一个分组中。如果一个用户消息不能放在一个SCTP分组中,这个消息可以被分成若干个数据块。
特点
和TCP类似,SCTP是面向连接、端到端、全双工、带有流量和拥塞控制的可靠传输协议。SCTP的连接称为关联。SCTP的关联通过4次握手建立。相对于TCP的3次握手建立连接,SCTP的关联能够抵御拒绝服务(DoS)攻击,从而提高了安全性。数据只有在关联建立之后与关联关闭之前才可发送。SCTP的关联通过3次握手关闭,不支持类似TCP的半关闭连接。也就是在任何一方关闭关联后,对方即不再发送数据。
面向消息的传输
SCTP是一种面向消息的传输协议,从上层应用传递下来的数据以消息的形式传输。SCTP提供消息的定界功能。在接收端,数据以消息的形式递交。为便于传输,SCTP提供消息的拆分和组装,以及消息的捆绑传输功能。
SCTP的数据传输基本单位是块。每个SCTP包包括一个SCTP公共头部、一个或多个块。块有两种基本类型:控制块和数据块。控制块用于SCTP的连接控制,包括连接的建立、关闭、传输路径的维护等;数据块传送应用层的用户数据。上层用户的每一个消息均被封装在一个数据块中,如果消息长度大于传输路径的最大传输单元(MTU),消息将被拆分成多个数据块传输,在接收端再组装起来向上层提交,这样每一个SCTP包封装一个数据块。如果消息长度较小,在1个MTU大小的限制下,在同一个SCTP包里可以捆绑多个消息,也即多个数据块共用一个公共头部,从而提高传输效率。数据块可以和控制块封装在同一个SCTP包里传输,这种捆绑受MTU大小的限制。
RFC2960定义了13种块类型,包括1种数据块和12种控制块。为实现新功能扩展,可以定义新的块类型。块包括块参数,用于协助完成块功能。块和块参数都是采用类型-长度-值(TLV)的结构定义的。用这种结构定义新的块类型及块参数类型来实现SCTP新功能非常方便。SCTP包括较完善的容错机制,如果通信双方的某一方不支持对端的某项扩展功能,可以通过容错和报错机制保证关联的健壮性。体现了SCTP的良好可扩展性。
多穴主机
SCTP的一个主要特点是支持多穴主机。SCTP关联的每个端点都可以拥有多个网络层地址。SCTP可以支持不同的网络层协议,为描述方便,本文以IP作为网络层协议来说明,即每个SCTP端点可以拥有多个IP地址用于数据传输。
对多穴主机的支持是为了在网络级提高容错能力。如果接收端是多穴主机,那么对于发送端来说每一个接收端的IP地址代表着一条通往对端的路径,这样发送端可以选择任一条路径来发送数据。SCTP规定任何时间都有一条路径作为首选路径来发送数据,其他路径作为备份路径。如果首选路径因接口故障或者网络拥塞等原因而失效,SCTP可以自动切换到另外一条路径来发送,避免单点失效,从而提高整个关联的容错能力。多穴主机之间的SCTP关联如图1所示。主机A到主机B有两条路径,A是多穴主机,这里只考虑不同的IP地址对应不同的网络接口的情况,A有两个网络接口,选择哪个接口来发送数据是A自身的路由策略问题(源地址选择问题)。
多流
SCTP的另一主要特点是多流。SCTP消息在不同的流内发送,这也是流传输控制协议名称的由来。从发送端到接收端可以有多个流,在同一流内发送的消息有序,而不同流之间的消息无序,因此不同流之间的消息传输是相对独立的。在某一个流内由于数据传输失败而引起的阻塞不会影响其他流的消息递交。多流特性可以帮助解决TCP中的队头阻塞(HOL)问题。因为TCP传输是按字节严格有序的,先行传送的字节如果丢失或损坏,即使后续的字节正确地被接收到也不能向上层递交,必须在接收端缓冲起来,直到先行字节由于重传而全部正确接收到后才可以提交,并且释放缓冲区。
图2描述了一个用3个流发送消息的SCTP实例。发送端有3个出流,相应的接收端就有3个入流。图2中给出了发送从1到9的9个消息实例。其中消息1、2、3在同一个流,4、5、6在同一个流,7、8、9在同一个流,分别在各自流内有序。由于消息1没有正确接收,造成消息2、3不能向上层协议(ULP)提交。然而从4到9的消息由于在不同的流中,则可以提交给ULP。这种流机制提供了无序递交功能,提高了传输效率。
此外,SCTP还定义了无序消息。如果消息带有无序标志,则不论它在哪个流中(在具体实现中,数据块中的流号不被解析),只要被正确接收,都提交给ULP,从而实现和流无关的无序递交。
流量、拥塞和错误的控制
SCTP仍然采用类似TCP的流量控制和拥塞控制机制,但又有所增强。整个传输分为慢启动阶段和拥塞避免阶段。与TCP不同的是,SCTP的拥塞窗口初始值可以是2个MTU,可以比TCP获得更快的窗口增长。SCTP的拥塞控制采用了选择确认(SACK)快速重传和快速恢复机制,是TCP各种主流改进机制的集成。但是由于SCTP采用了块结构和控制块机制,可以比TCP更大地提升传输性能。例如SCTP在移动通信的切换中表现得比TCP SACK更优越[4]。 由于SCTP有多个通往对端的路径,在发送端对每一个路径都有一套拥塞控制参数和控制用的数据结构。这类似于有多个通往对端的TCP连接,SCTP为多条路径的流量控制和拥塞控制提供统一的管理机制。消息可以在不同的路径上传输,流管理和路径管理是正交的,即相对独立。
每个路径有一个错误计数器,当某一路径上的错误达到一个门限时,该路径将会被标记为不活动的(Inactive),SCTP把传输转移到另一条路径上进行。同时SCTP对整个关联设置一个错误计数器,每个路径上的错误计数时,整个关联的错误计数也要增加,只要对端返回确认,则关联错误计数器清零(不管是对哪条路径返回的确认)。如果关联错误计数器达到一个门限值,则整个关联被非正常关闭。由此可见,多路径带来比TCP更好的网络级容错机制。
工作过程
建立连接
不同于TCP,SCTP通过四次握手来完成连接的建立:
在一次SCTP四次握手中,INIT消息的接收端不必保存任何状态信息或者分配任何资源,这样就可防范SYNFlooding等DoS攻击。它在发送INIT-ACK消息时,采用了一种机制——“状态Cookie”,该Cookie具有发送端要建立自己状态所需的全部信息。
用于建立连接的INIT ACK只能在COOKIE WATI状态收到,在其它状态收到该报文时都会直接丢弃,类似的,COOKIE ACK只能在COOKIE ECHOED状态接收。
在常规的握手中,主动发起方的本地tag在发起握手时产生,主动发起方的对端tag在收到INIT ACK时产生。而连接的被动方的本地tag和对端tag都在收到INIT时产生,但是最终要到收到了COOKIE ECO后才确定并保存下来。
SCTP产生一个状态Cookie的过程如下:
INIT和INIT-ACK都必须包含建立初始状态所需的参数:一组IP地址,保证可靠传输的初始序列号,每个被接收的SCTP报文中必须含有的验证标签,每一端请求发出的流数目和每一端能支持接收的流数目。交换完这些消息之后,INIT的发送端以COOKIE-ECHO消息的方式发送回状态Cookie。接收端根据所接收到的COOKIE-ECHO中的状态Cookie,完整地重建自己的状态,并回送COOKIE-ACK来确认关联已建立。
因此对于SCTP,即使接收再多的INIT消息,接收端也没有任何资源的消耗:它既不分配任何系统资源,也不保存此次新关联的状态,它只是把相应重建状态所用的状态Cookie作为参数,包含在每一个回送的INIT-ACK消息中,最后该状态Cookie会被COOKIE-ECHO消息发送回来。
类似于TCP,SCTP也多由客户端执行主动打开,而服务器执行被动打开。
断开连接
与TCP不同,SCTP使用三次握手来关闭一个耦联。而且SCTP不支持TCP所支持的“半关闭”状态。典型的SCTP关闭一个耦联的过程如下:
同时打开连接
RFC规定,如果SCTP在COOKIE-WAIT或者COOKIE-ECHOED状态接收到INIT报文。则:
如果SCTP在非COOKIE-WAIT状态接收到了INIT-ACK,则丢弃它。
同时断开连接
极少数情况下,耦联的双发可能同时执行主动关闭,即同时进入发送SHUTWODN并进入SHUTDOWN-SENT状态。在这种情况下关闭的流程为:
状态变化图
C实例
下面展示一个通过类Unix下C编写的、用SCTP的一到多实现的一个回显服务器。
1、服务端
Server.h
Server.cpp
main.cpp
2、客户端
Client.h
Client.cpp