1.SCTP是什么?
只要是接触过编程的人,当你问他传输层都有哪些协议?我想几乎很多人会说TCP,IP协议而很少有人知道SCTP(流控制传输协议)这个和上述俩个协议具有相同地位的协议。
SCTP提供的服务与TCP,UDP类似,或者甚至可以理解为其是TCP与UDP协议各自优点的组合后的产物。
2.SCTP的特点
(1)SCTP连接的建立
SCTP协议建立连接可调用
- 1
- 2
- 3
- 4
- 5
介绍完建立连接的接口,那么就来谈谈其连接建立的具体过程,废话不多说,先给出其建立连接过程的示意图
SCTP连接建立的过程如上图所示:
(1)客户端给服务器发送一个INIT初始化消息,消息中包含有客户端要告诉服务器自己的IP地址的清单,初始化列号(可以和TCP初始化序列一样来理解),用于表示本关联中的所有分组的其实标志,客户请求以及能够支持流的数目等
(2)服务器给客户端回一个INIT ACK来确认刚收到的消息,并且还有和刚才客户端给服务器发的所有种类的服务器自己的信息,除此之外还会还有一个状态cookie
(3)客户端收到状态cookie之后,给服务器回一个COOKIE ECHO 并且此时还可以在此数据包中包含用户数据
(4)服务器收到客户端给其发的COOKIE ECHO之后在给其发个COOKIE ACK 此时同样也可以携带数据
至此一个SCTP关联就建立成功
(2)SCTP断开连接
SCTP断开连接和TCP的接口相同都是调用shutdown(),但是语义却不同其how参数对SCTP来说都是读写都禁掉
其具体流程如下图
SCTP不像TCP那样允许”半关闭的关联”。当一端关闭某个关联时,另一段必须停止发送数据。
(3)多宿主
TCP为客户与服务器之间提供连接,从而可以使双方安全的传送数据,而SCTP将连接改为了”关联”。
要解释清楚为什么SCTP将TCP的连接改为”关联”我打算从他们的bind(绑定接口)来说明原因,先以服务器调用bind为例,
TCP的bind接口如下
- 1
SCTP的bind接口如下
- 1
上面给出了TCP和STCP对应的绑定套接字的接口,我们逐一的对比其参数
(1)首先二者的第一个参数sockfd含义相同,都是指待绑定的套接字
(2)bind中的参数my_addr指的是要把哪个插座(IP地址和端口号)绑定到sockfd上,这相当与给了sockfd一个身份,之后网络中就可以唯一的标识该sockfd了,而sctp_bindx中对应位置的参数名变为my_addrs,细心的读者会发现这个参数变为了复数了。没错该参数并不是单一的某个sockaddr结构体的地址,而是sockaddr结构体数组的首地址,参数addrcnt表示该数组中元素的个数。既然相比TCP的bind接口,此处为多个地址,我们也不难理解sctp_bindx所做的工作是将这些地址都绑定到sockfd上。这样其和TCP的第一个不同点就出来了。即TCP的bind之后的socket只有一个身份(只绑定了一个地址),而SCTP bind之后socket有多个身份(绑定了多个地址)。关于flags参数我们之后在补充
上述中我们的俩种协议的服务器调用bind接口有所区别,那么SCTP其对应的客户端建立连接时调用的connect接口也类似稍有不同
sctpconnect接口
- 1
可以看出SCTP在建立连接时addrs也为一个sockaddr结构体数组
那么SCTP相较TCP的绑定端口和连接时使用了地址数组有什么用意呢?没错这就是我们这里最终想要说明的其多宿主的特性。服务器调用多个地址来标识自己,客户端可以和每一个地址建立一个路径。这样当客户端的哪条路劲失效时,可以自动切换到另一条路径上,应用程序甚至都不必知道发生了故障,这样是不是比起TCP的单一路径安全保障性更好一点呢?
(4)多流解决头端阻塞
还是与TCP做比较,TCP虽然是个全双工协议,但是其读写方向各自只有一个流。一个流很多情况下会发生头端阻塞,其大概意思如下图
如上图所示,因为TCP每一个方向上只有一个流,那么当该流中的某个部分的报文丢失之后,其后的所有报文都只能等待丢失部分重传之后,并在重新排序之后方可被送入应用的接受缓冲区。这种协议设定对发送数据有严格顺序要求时还可以接受,但如果对发送数据没有这么强的顺序限制时就显的不那么友好了。
一个具体的场景
当我们的一个web页面要展示好多张图片时,就像上图所示。在这种情况下其实图片1到4之间到达的先后顺序是完全不影响的。此时如果你用TCP这种单项流协议,那么图片一有数据丢失,导致你因此也看不了其实已经发来的图二到图4。如果你改用SCTP这种支持多流的协议,那么你的每张图片发送都使用不同的流号,到时候,当图一对应流号的数据有丢失,那么只有这一个流会等待重传,其他几张图片都不会被其影响,这样我们就可以先看到图2到图4了,完全不受图1丢失的影响。不知道读者此时会不会感觉出来点多流在此种场景下的巨大优势
(5) 面向消息
SCTP是面向消息的协议,不像TCP那样没有包的概念,也意味着消息没有边界,边界只能由应用层来设计和划分,而SCTP一个包就是一个消息,这就大大降低了编程者的难度。其次它的发送接受接口还可以传递消息类型,接口具体如下
- 1
- 2
- 3
上述的发送接口中flags参数就是用来标识消息类型的参数。通过这样直接获取消息类型由可以减少我们不必要的拆包操作,真的是方便之极
(6)一到多特性
SCTP的一到多特性其实和UDP的套接字一样,都能通过一个套接字接受多个消息,这意味着程序员可以不用向TCP那样管理大量的套接字了
3.SCTP常用接口
一下接口我们都是针对一到多形式的SCTP
(1)sctp_bindx端口绑定
该接口用来命名一个套接字
- 1
- 2
该接口用来给sd绑定一组地址,或从addrs地址组中添加,删除某个地址。具体操作由flags来控制,由于之前我们以介绍过其他参数,这里值介绍flags
flags | 说明 |
---|---|
SCTP_BINDX_ADD_ADDR | 往套接字里添加地址 |
SCTP_BINDX_REM_ADDR | 从套接字中删除地址 |
(2)sctp_connectx函数
该接口用于与服务器建立连接
- 1
参数含义上文有介绍这里不在赘余
(3)sctp_sendmsg
如果之前没有调用sctp_connectx那么第一次调用该接口既负责建立连接也负责发送数据
- 1
- 2
- 3
前5个参数与UDP的sendto参数含义相同,我们在此只讨论后4个
ppid参数指定将随数据块传递的净荷协议
flags参数标识消息类型
stream_no参数标识具体的流号
timetolive指定消息的生命期
context保存消息传输过程中可能产生的上下文
(4)sctp_recvmsg
该接口负责接受数据
- 1
- 2
- 3
由于前5个参数与UDP的recvfrom相同,在此我们同样也只讨论后几个参数
sinfo保存了消息相关的细节
msg_flags和sctp_sendmsg中的flags相对应