可靠且快速的传输层协议SCTP详解

概述

传输层通信协议

SCTP 被视为一个传输层协议,它的上层为SCTP 用户应用,下层作为分组网络。在SIGTRAN 协议的应用中,SCTP 上层用户是SCN 信令的适配模块(如M2UA、M3UA),下层是IP 网。

image

两种最流行的传输层协议是传输控制协议 (TCP) 和用户数据报协议 (UDP):

  • TCP 是一种可靠的协议,可确保有序、有序地传递数据并管理网络中的拥塞。
  • UDP 是一种面向消息的协议,既不能保证传递顺序,也不能管理拥塞。

但是,UDP 是一种快速协议,用于保留它传输的消息的边界。

本文提供了另一个选项:SCTP。它提供了可靠、有序地传递数据(如 TCP),但以 UDP 等面向消息的方式运行,从而保留消息边界。SCTP 还提供几个高级功能:

  • 多宿主
  • 多流
  • 启动保护
  • 消息框架
  • 可配置的无序交付
  • 优雅关机

术语

传送地址

传送地址由 IP 地址、传输层协议类型和传输层端口号定义。由于SCTP 在IP 上传 输,所以一个SCTP 传送地址由一个IP 地址加一个SCTP 端口号决定。SCTP 端口 号就是SCTP 用来识别同一地址上的用户,和TCP 端口号是一个概念。比如IP 地 址10.105.28.92 和SCTP 端口号1024 标识了一个传送地址,而10.105.28.93 和 1024 则标识了另外一个传送地址,同样,10.105.28.92 和端口号1023 也标识了一 个不同的传送地址。

主机和端点

  • 主机(HoST) 主机配有一个或多个 IP 地址,是一个典型的物理实体。
  • 端点(SCTP Endpoint)

端点是SCTP 的基本逻辑概念,是数据报的逻辑发送者和接收者,是一个典型的逻 辑实体。

一个传送地址(IP 地址+SCTP 端口号)唯一标识一个端点。一个端点可以由多个 传送地址进行定义,但对于同一个目的端点而言,这些传送地址中的IP 地址可以配 置成多个,但必须使用相同的SCTP 端口。

关联和流

关联(AssociaTIon)

关联就是两个 SCTP 端点通过SCTP 协议规定的4 步握手机制建立起来的进行数据传递的逻辑联系或者通道。 SCTP 协议规定在任何时刻两个端点之间能且仅能建立一个关联。由于关联由两个端点的传送地址来定义,所以通过数据配置本地IP 地址、本地SCTP 端口号、对端 IP 地址、对端SCTP 端口号等四个参数,可以唯一标识一个SCTP 关联。正因为如 此,在GTSOFTX3000 中,关联可以被看成是一条M2UA 链路或M3UA 链路。

流(Stream)

流是 SCTP 协议的一个特色术语。SCTP 关联中的流用来指示需要按顺序递交到高 层协议的用户消息的序列,在同一个流中的消息需要按照其顺序进行递交。严格地 说,“流”就是一个SCTP 关联中,从一个端点到另一个端点的单向逻辑通道。一 个关联是由多个单向的流组成的。各个流之间相对独立,使用流ID 进行标识,每个 流可以单独发送数据而不受其他流的影响。

通路(Path)和首选通路(Primary Path)

通路(Path)

通路是一个端点将 SCTP 分组发送到对端端点特定目的传送地址的路由。如果分组发送到对端端点不同的目的传送地址时,不需要配置单独的通路。

首选通路(Primary Path)

首选通路是在默认情况下,目的地址、源地址在SCTP 分组中发到对端端点的通路。

如果可以使用多个目的地地址作为到一个端点的目的地址,则这个SCTP 端点为多 归属。如果发出SCTP 分组的端点属于多归属节点时,如果定义了目的地址、源地 址,能够更好控制响应数据块返回的通路和数据包被发送的接口。 一个 SCTP 关联的两个SCTP 端点都可以配置多个IP 地址,这样一个关联的两个 端点之间具有多条通路,这就是SCTP 关联的多地址性。SCTP 关联的多地址性是 SCTP 与TCP 最大的不同。

一个关联可以包括多条通路,但只有一个首选通路。如图1所示,MGC(如 GTSOFTX3000)一个端点包括两个传送地址(10.11.23.14:2905 和10.11.23.15: 2905),而SG 一个端点也包括两个传送地址(10.11.23.16:2904 和10.11.23.17: 2904)。

image

图2 SCTP 双归属

此两个端点决定了一个关联,该关联包括4 条通路(Path0、Path1、Path2 和Path3)。 根据数据配置可以确定此4 条通路的选择方式,如图2所示。图中定义了4 条通 路,而且首选通路为Path0: Path0:本端传送地址1(10.11.23.14:2905)发送SCTP 分组到对端传送地 址1(10.11.23.16:2904)。

Path1:本端传送地址1(10.11.23.14:2905)发送SCTP 分组到对端传送地 址2(10.11.23.17:2904)。

Path2:本端传送地址2(10.11.23.15:2905)发送SCTP 分组到对端传送地 址1(10.11.23.16:2904)。

Path3:本端传送地址2(10.11.23.15:2905)发送SCTP 分组到对端传送地 址2(10.11.23.17:2904)。

端点发送的 SCTP 工作原理为:本端点传送地址A 发送的SCTP 包通过首选通路发 送到对端端点。当首选通路出现故障后,SCTP 可以自动切换到其他备用通路上, 优先切换对端端点的传送地址,再次切换本端端点的传送地址。

SCTP 定义了心跳消息(Heart Beat)。当某条通路空闲时,本端SCTP 用户要求 SCTP 生成相应的心跳消息并通过该通路发送到对端端点,而对端端点必须立即发 回对应的心跳确认消息。这种机制被用来精确测量回路时延RTT(Round Trip Time),而且可以随时监视关联的可用情况和保持SCTP 关联的激活状态。

image

图3 确定通路选择方式的数据配置

TSN 和SSN

传输顺序号 TSN(Transmission Sequence Number)

SCTP 使用TSN 机制实现数据的确认传输。一个关联的一端为本端发送的每个数据 块顺序分配一个基于初始TSN 的32 位顺序号,以便对端收到时进行确认。 TSN 是基于关联进行维护的。

流顺序号 SSN(Stream Sequence Number)

SCTP 为本端在这个流中发送的每个数据块顺序分配一个16 位SSN,以便保证流 内的顺序传递。 在关联建立时,所有流中的SSN 都是从0 开始。当SSN 到达65535 后,则接下来 的SSN 为0。 TSN 和SSN 的分配是相互独立的。

拥塞窗口CWND(Congestion Window)

SCTP 也是一个滑动窗口协议,拥塞窗口是针对每个目的地址维护的,它会根据网 络状况调节。当目的地址的发送未证实消息长度超过其CWND 时,端点将停止向这 个地址发送数据。

接收窗口RWND(Receive Window)

RWND 用来描述一个关联对端的接收缓冲区大小。关联建立过程中,双方会交换彼 此的初始RWND。RWND 会根据数据发送、证实的情况即时地变化。RWND 的大 小限制了SCTP 可以发送的数据的大小。当RWND 等于0 时,SCTP 还可以发送一 个数据报,以便通过证实消息得知对方缓冲区的变化,直到达到CWND 的限制。

传输控制块TCB(Transmission Control Block)

TCB 是一种内部数据结构,是一个SCTP 端点为它与其他端点之间已经启动的每一 个关联生成的。TCB 包括端点的所有状态、操作信息,便于维护和管理相应的关联。

功能

与传统传输层协议相比,SCTP 的两个最重要的增强功能是端宿多宿主和多流功能。

多宿主

多宿主为应用程序提供比使用 TCP 的应用程序更高的可用性。多宿主主机是具有多个网络接口,因此可以寻址的多个 IP 地址的主机。在 TCP 中,连接是指两个端点之间的通道(在这种情况下,是两个主机接口之间的套接字)。SCTP 引入了存在于两个主机之间的关联的概念,但可能与每个主机的多个接口协作。

image

图4.TCP 连接与 SCTP 关联

顶部是 TCP 连接。每个主机包括一个网络接口;在每个客户端和服务器上的单个接口之间创建连接。建立后,连接绑定到每个接口。

在图的底部,您可以看到一个包含每个主机两个网络接口的体系结构。通过独立网络提供两条路径,一条从接口 C0 到 S0,另一条从 C1 到 S1。在 SCTP 中,这两个路径将收集到关联中。

SCTP 使用内置检测信号监视关联路径;检测到路径故障时,协议通过备用路径发送流量。应用程序甚至不需要知道发生了故障转移恢复。

故障转移还可用于维护网络应用程序连接。例如,考虑包含无线 802.11 接口和以太网接口的笔记本电脑。当笔记本电脑位于其坞站中时,将首选高速以太网接口(在 SCTP 中,称为主地址);但在此连接丢失(从坞站中删除)后,连接将故障通过无线接口。返回坞站后,将检测到以太网连接,并在此接口上恢复通信。这是一种强大的机制,用于提供高可用性和更高的可靠性。

多流

在某些方面,SCTP 关联就像 TCP 连接,只是 SCTP 支持关联中的多个流。关联中的所有流都是独立的,但与关联相关。

image

图5.SCTP 关联与流的关系

每个流都得到一个流号,该流号在流经关联流的 SCTP 数据包中编码。多流很重要,因为阻塞的流(例如,由于数据包丢失而等待重新传输的流)不会影响关联中的其他流。此问题通常称为线头阻塞。TCP 容易出现这种阻塞。

多个流如何在传输数据时提供更好的响应能力?例如,HTTP 协议在同一套接字上共享控制和数据。Web 客户端从服务器请求文件,服务器通过同一连接发送文件。多流 HTTP 服务器将提供更好的交互性,因为可以在关联中的独立流上处理多个请求。此功能将并行化响应,虽然速度可能更快,但同时加载 HTML 和图形图像,从而提供更好的响应能力。

多流是SCTP的一个重要功能,尤其是当你在协议设计中考虑一些控制和数据问题时。在 TCP 中,控制和数据通常共享相同的连接,这可能有问题,因为控制数据包可能会延迟在数据包后面。如果将控制和数据拆分为独立的流,就可以更及时地处理控制数据,从而更好地利用可用资源。

启动保护

在 TCP 和 SCTP 中启动新连接时,数据包握手将发生。在 TCP 中,它称为三向握手。客户端发送一个数据包(用于同步的短),服务器会响应该数据包(同步确认)。最后,客户端用数据包确认接收(参见图 6)。SYN``SYN-ACK``ACK

image

图6.TCP 和 STCP 握手的数据包交换

TCP 可能发生的问题是,当恶意客户端使用虚假源地址伪造 IP 数据包,然后用 TCP 数据包充用服务器时。服务器在收到 时为连接分配资源,然后在数据包洪流下,最终将用完,无法为新请求提供服务。这称为拒绝服务(DoS) 攻击。SYN``SYN``SYN

SCTP 通过四向握手和引入 Cookie 来防止此类攻击。在 SCTP 中,客户端启动与数据包的连接。服务器响应 的 包含 Cookie(标识此建议连接的唯一上下文)。然后,客户端使用 响应,其中包含服务器发送的 Cookie。此时,服务器为连接分配资源,并通过向客户端发送 一个来确认这一点。INIT``INIT-ACK``COOKIE-ECHO``COOKIE-ACK

为了解决使用四向握手延迟数据移动的问题,SCTP 允许将数据包含在 和 数据包中。COOKIE-ECHO``COOKIE-ACK

消息框架

使用消息框架时,将保留通过套接字传递消息的边界;这意味着,如果客户端向服务器发送 100 个字节,后跟 50 个字节,则服务器将分别读取 100 字节和 50 字节,用于两次读取。UDP 也以这种方式运行,这使得它有利于面向消息的协议。

相比之下,TCP 以字节流方式运行。如果没有框架,对等体可能会收到比发送的多或少(拆分写入或将多个写入聚合到一次读取中)。此行为要求通过 TCP 运行的面向消息的协议在其应用程序层(一项潜在的复杂任务)中提供数据缓冲区和消息框架。

SCTP 在数据传输中提供消息框架。当对等体对套接字执行写入时,可以保证在对等端点读取此大小相同的数据块。

image

图7.UDP/SCTP 中的消息框架与面向字节流的协议

用户数据分段

SCTP 通过对传送通路上最大PMTU(Path Maximum TransmissiON Unit)的检测, 实现在SCTP 层将超大用户数据分片打包,避免在IP 层的多次分片、重组,可以减 少IP 层的数据负担。

在发送端,SCTP 可以对大的用户数据报进行分片以确保SCTP 数据报传递到 低层时适合通路MTU(Maximum Transmission Unit)。

在接收端,SCTP 将分片重组为完整的用户数据报,然后传递给SCTP 用户。

证实和避免拥塞

证实和重传是协议保证传输可靠性的策略,SCTP 也一样。证实机制是SCTP 保证 传输可靠性的基石。避免拥塞沿袭了TCP 的窗口机制,进行合适的流量控制。

SCTP 在将数据(数据分片或未分片的用户数据报)发送给底层之前顺序地为 之分配一个发送顺序号(TSN)。TSN 和SSN(流顺序号)是相互独立的,TSN 用于保证传输的可靠性,SSN 用于保证流内消息的顺序传递。TSN 和SSN 在功能上使可靠传递和顺序传递分开。接收端证实所有收到的 TSNs,即使其中有些尚未收到。包重发功能负责 TSN 的证实,还负责拥塞消除。

消息块绑定

如果长度很短的用户数据被带上很大一个 SCTP 消息头,其传递效率会很低,因此, SCTP 将几个用户数据绑定在一个SCTP 报文里面传输,以提高带宽的利用率。

SCTP 分组由公共分组头和一个/多个信息块组成,信息块可以是用户数据,也 可以是SCTP 控制信息。

SCTP 用户能够可选地使用捆绑功能,决定是否将多个用户数据报捆绑在一个 SCTP 分组中。

为提高效率,拥塞/重发时,捆绑功能可能仍被执行,即使用户已经禁止捆绑。

分组的有效性

分组的有效性是 SCTP 提供无差错传输的基石。SCTP 分组的公共分组头包含一个 验证标签(VerificATIon Tag)和一个可选的32 位校验码(Checksum)。 验证标签的值由关联两端在关联启动时选择。如果收到的分组中如果没有期望的验 证标签值,接收端将丢弃这个分组,以阻止攻击和失效的SCTP 分组。 校验码由 SCTP 分组的发送方设置,以提供附加的保护,用来避免由网络造成的数 据差错。接收端将丢弃包含无效校验码的SCTP 分组。

可配置无需交付

SCTP 中的消息传输可靠,但不一定按所需顺序传输。TCP 保证数据按顺序传递(考虑到 TCP 是流协议,这是一件好事)。但是,您也可以在 SCTP 中配置流以根据需要接受无序消息。

此功能在面向消息的协议中非常有用,在该协议中,请求是独立的,排序并不重要。此外,您可以在关联中按流配置无序传递。

优雅关闭

TCP 和 SCTP 是基于连接的协议,而 UDP 是无连接协议。TCP 和 SCTP 都需要连接设置和对等体之间的拆解。在SCTP中,套接字关闭的不同情况是TCP的半关闭的删除

image

图8.TCP 和 SCTP 连接终止序列

在 TCP 中,对等体可以关闭其套接字的末尾(导致发送数据包),但随后可以继续接收数据。表示此终结点不再发送数据,但直到对等体关闭套接字的末尾,它才能继续传输数据。应用程序很少使用此半封闭状态,因此 SCTP 设计人员选择将其删除,并将其替换为更简洁的终止序列。当对等体关闭其套接字(导致发出基元)时,需要关闭两个终结点,并且不允许在任一方向上进一步移动数据。FIN``FIN``SHUTDOWN

分组管理

发送端的 SCTP 用户能够使用一组传送地址作为SCTP 分组的目的地。SCTP 管理 功能可以根据SCTP 用户的指令和当前合格的目的地集合的可达性状态,为每个发 送的SCTP 分组选择一个目的地传送地址。当其他分组业务量不能完全表明可达性 时,通路管理功能可以通过心跳消息来监视到某个目的地地址的可达性,并当任何 对端传送地址的可达性发生变化时,向SCTP 用户提供指示。通路功能也用来在偶 联建立时,向对端报告合格的本端传送地址集合,并把从对端返回的传送地址报告 给本地的SCTP 用户。 在关联建立时,为每个 SCTP 端点定义一个首选通路,用来正常情况下发送SCTP 分组。

基本信令流程

关联的建立和发送流程

SCTP 端点A 启动建立关联,并向端点B 发送一个用户消息,随后端点B 向A 发送 两个用户消息。(假定这些消息没有捆绑和分段)。信令流程如图1所示。

image

图9 关联建立过程消息交互图

  1. 端点A 创建一个数据结构TCB(传输控制块)来描述即将发起的这个关联(包 含关联的基本信息),然后向端点B 发送INIT 数据块。INIT 数据块中主要包 括如下参数:
  • 启动标签(Initiate Tag):对端验证标签,如设为Tag_A。Tag_A 是从1 到 4294967295 中的一个随机数。
  • 输出流数量(OS):本端点期望的最大出局流的数量。
  • 输入流数量(MIS):本端点允许入局流的最大数量。
  1. 端点B 收到INIT 消息后,立即用INIT ACK 数据块响应。INIT ACK 数据块中 必须带有如下参数:
  • 目的地 IP 地址:设置成INIT 数据块的起源IP 地址。
  • 启动标签(Initiate Tag):设置成Tag_B。
  • 状态 COOKIE(STATE COOKIE):根据关联的基本信息生成一个TCB,不 过这个TCB 是一个临时TCB。这个TCB 生成以后,将其中的必要信息(包含 一个COOKIE 生成的时间戳、COOKIE 的生命期)和一个本端的密钥通过 RFC2401 描述的算法计算成一个32 位的摘要MAC(这种计算是不可逆的)。 必要信息和MAC 组合成STATE COOKIE 参数。
  • 本端点传送地址。
  • 最大入局流的数量。
  • 最大出局流的数量。
  1. 端点A 收到INIT ACK 后,首先停止INIT 定时器离开COOKIE-WAIT 状态, 然后发送COOKIE ECHO 数据块,将收到INIT ACK 数据块中的STATE COOKIE 参数原封带回。最后端点A 启动COOKIE 定时器并进入 COOKIE-ECHOED 状态。
  2. 端点B收到COOKIE ECHO数据块后,进行COOKIE验证。将STATE COOKIE 中的TCB 部分和本端密钥根据RFC2401 的MAC 算法进行计算,得出的MAC 和STATE COOKIE 中携带的MAC 进行比较。如果不同则丢弃这个消息;如 果相同,则取出TCB 部分的时间戳,和当前时间比较,看时间是否已经超过 了COOKIE 的生命期。如果是,同样丢弃。否则根据TCB 中的信息建立一个 和端A 的关联。端点B 将状态迁入ESTABLISHED,并发出COOKIE ACK 数 据块。端点B 向SCTP 用户发送SCOMMUNCIATION UP 通知。
  3. 端点A 向端点B 发送一个DATA 数据块,启动T3-RTS 定时器。DATA 数据 块中必须带有如下参数:
  • TSN:DATA 数据块的初始TSN。
  • 流标识符(Stream Identifier):用户数据属于的流,假设流标识符为0。
  • 流顺序码(Stream Sequence Number):所在流中的用户数据的顺序号码。 该字段从0 到65535。
  • 用户数据(User Data):携带用户数据净荷。
  1. 端点B 收到DATA 数据块后,返回SACK 数据块。SACK 数据块中必须带有 如下参数:
  • 累积证实 TSN 标签(Cumulative TSN Ack):端点A 的初始TSN。
  • 间隔块(Gap Ack Block):此值为0。 端点 A 收到SACK 数据块后,停止T3-RTX 定时器。
  1. 端点B 向端点A 发送第一个DATA 数据块。DATA 数据块中必须带有如下参 数:
  • TSN:端点B 发出DATA 数据块的初始TSN。
  • 流标识符(Stream Identifier):用户数据属于的流,假设流标识符为0。
  • 流顺序码(Stream Sequence Number):所在流中的用户数据的顺序号码。 假设流顺序码为0。
  • 用户数据(User Data):携带用户数据净荷。
  1. 端点B 向端点A 发送第二个DATA 数据块。DATA 数据块中必须带有如下参 数:
  • TSN:端点B 发出DATA 数据块的初始TSN+1。
  • 流标识符(Stream Identifier):用户数据属于的流,假设流标识符为0。
  • 流顺序码(Stream Sequence Number):所在流中的用户数据的顺序号码。 此时流顺序码为1。
  • 用户数据(User Data):携带用户数据净荷。
  1. 端点A 收到DATA 数据块后,返回SACK 数据块。SACK 数据块中必须带有 如下参数:
  • 累积证实 TSN 标签(Cumulative TSN Ack):端点B 的初始TSN。
  • 间隔块(Gap Ack Block):此值为0。

关联关闭流程

一个端点退出服务时,需要停止它的关联。关联的停止使用两种流程:关联的中止 流程(非正常关闭)和关联的正常关闭流程。 关联的中止(非正常关闭)可以在任何未完成期间进行,关联的两端都舍弃数据并 且不提交到对端。此种方法不考虑数据的安全。关联的中止步骤比较简单:发起端 点向对端端点发送ABORT 数据块,发送的SCTP 分组中必须填上对端端点的验证 标签,而且不在ABORT 数据块中捆绑任何DATA 数据;接收端点收到ABORT 数 据块后,进行验证标签的检查。如果验证标签与本端验证标签相同,接收端点从记 录上清除该关联,并向SCTP 用户报告关联的停止。

关联的正常关闭:任何一个端点执行正常关闭程序时,关联的两端将停止接受从其 SCTP 用户发来的新数据,并且在发送或接收到SHUTDOWN 数据块时,把分组中 的数据递交给SCTP 用户。关联的关闭可以保证所有两端的未发送、发送未证实数 据得到发送和证实后再终止关联。

image

图10 关联正常关闭消息交互图

关联的正常关闭步骤如下:

  1. 关联关闭发起端点A 的SCTP 用户向SCTP 发送请求SHUTDOWN 原因。 SCTP 关联从ESTABLISHED 状态迁入SHUTDOWN-PENDING 状态。在这 个状态,SCTP 不接受SCTP 用户在这个关联上的任何数据发送请求。同时等待端点A 所有发送未证实的数据得到端点B 的证实。当所有端点A 发送未证 实数据得到证实,则向端点B 发送SHUTDOWN 数据块。端点A 启动 T2-shutdown 定时器进入SHUTDOWN-SENT 状态。启动T2-shutdown 定时 器的目的是等待端点B 发回的SHUTDOWN-ACK 数据块,如果定时器超时, 则端点A 必须重新发送SHUTDOWN 数据块。
  2. 端点B 收到SHUTDOWN 消息后,进入SHOUTDOWN-RECEIVED 状态, 不再接收从SCTP 用户发来的的新数据,并且检查数据块的累积TSN ACK 字 段,验证所有未完成的DATA 数据块已经被SHUTDOWN 的发送方接收。当 端点B 所有未发送数据和发送未证实数据得到发送和证实后, 发送 SHUTDOWN ACK 数据块并启动本端T2-SHUTDOWN 定时器,并且进入 SHUTDOWN-ACK-SENT 状态。如果定时器超时了,端点B 则重新发送 SHUTDOWN ACK 数据块。
  3. 端点A 收到SHUTDOWN ACK 消息后,停止T2-shutdown 定时器,并且向端 点B 发送SHUTDOWN COMPLETE 数据块,并清除关联的所有记录。端点B 收到SHUTDOWN COMPLETE 数据块后, 验证是否处于 SHUTDOWN-ACK-SENT 状态。如果不是处于该状态,则丢弃该数据块;如 果端点处于SHUTDOWN-ACK-SENT 状态,端点B 则停止T2-shutdown 定时 器并清除关联的所有记录,进入CLOSED 状态。

示例

本文提供了一个用 C 编程语言编写的示例服务器和客户端,并演示 SCTP 的多流功能。此示例演示实现SCTP协议形式的服务器。此传统服务器将当前时间发出到连接的客户端,但对于 SCTP,我发出流 0 上的本地时间和流 1 上的格林威治标准时间 (GMT)。这个简单的示例允许我演示流通信的 API。

![image](https://upload-images.jianshu.io/upload_images/2844443-0bd6491c9fe45314.gif?imageMogr2/auto-orient/strip "image")

图11.多流服务器和客户端中使用的套接字功能

这些应用程序是在具有 2.6.11 内核和 Linux 内核 SCTP 项目 (lksctp) 的 GNU/Linux 操作系统上开发的。

服务端

int main()
{
  int listenSock, connSock, ret;
  struct sockaddr_in servaddr;
  char buffer[MAX_BUFFER+1];
  time_t currentTime;
 
  /* Create SCTP TCP-Style Socket */
  listenSock = socket( AF_INET, SOCK_STREAM, IPPROTO_SCTP );
 
  /* Accept connections from any interface */
  bzero( (void *)&servaddr, sizeof(servaddr) );
  servaddr.sin_family = AF_INET;
  servaddr.sin_addr.s_addr = htonl( INADDR_ANY );
  servaddr.sin_port = htons(MY_PORT_NUM);
 
  /* Bind to the wildcard address (all) and MY_PORT_NUM */
  ret = bind( listenSock,
               (struct sockaddr *)&servaddr, sizeof(servaddr) );
 
  /* Place the server socket into the listening state */
  listen( listenSock, 5 );
 
  /* Server loop... */
  while( 1 ) {
 
    /* Await a new client connection */
    connSock = accept( listenSock,
                        (struct sockaddr *)NULL, (int *)NULL );
 
    /* New client socket has connected */
 
    /* Grab the current time */
    currentTime = time(NULL);
 
    /* Send local time on stream 0 (local time stream) */
    snprintf( buffer, MAX_BUFFER, "%s\n", ctime(&currentTime) );
 
    ret = sctp_sendmsg( connSock,
                          (void *)buffer, (size_t)strlen(buffer),
                          NULL, 0, 0, 0, LOCALTIME_STREAM, 0, 0 );
 
    /* Send GMT on stream 1 (GMT stream) */
    snprintf( buffer, MAX_BUFFER, "%s\n",
               asctime( gmtime( &currentTime ) ) );
 
    ret = sctp_sendmsg( connSock,
                          (void *)buffer, (size_t)strlen(buffer),
                          NULL, 0, 0, 0, GMT_STREAM, 0, 0 );
 
    /* Close the client connection */
    close( connSock );
 
  }
 
  return 0;
}

首先创建服务器套接字,允许从任何本地接口(使用通配符地址)进行连接。将此描述符绑定到套接字,然后将服务器套接字放置到侦听状态。此时,传入连接是可以被接收的。IPPROTO_SCTP``sockaddr``INADDR_ANY``sockaddr``bind

请注意,SCTP 使用许多与 TCP 和 UDP 相同的套接字 API。

服务端循环等待新的客户端连接。从函数返回后,套接字将标识新的客户端连接。接着使用函数获取当前时间,然后将其转换为特定的字符串。使用函数(非标准套接字调用),可以将字符串发送到客户端,指定特定的流 ()。发送本地时间字符串后,我在 GMT 中将当前时间打包为字符串,然后在流上发送此时间。accept``connSock``time``snprintf``sctp_sendmsg``LOCALTIME_STREAM``GMT_STREAM

至此服务器已完成其职责,因此关闭套接字并等待新的客户端连接。

客户端

int main()
{
  int connSock, in, i, flags;
  struct sockaddr_in servaddr;
  struct sctp_sndrcvinfo sndrcvinfo;
  struct sctp_event_subscribe events;
  char buffer[MAX_BUFFER+1];
 
  /* Create an SCTP TCP-Style Socket */
  connSock = socket( AF_INET, SOCK_STREAM, IPPROTO_SCTP );
 
  /* Specify the peer endpoint to which we'll connect */
  bzero( (void *)&servaddr, sizeof(servaddr) );
  servaddr.sin_family = AF_INET;
  servaddr.sin_port = htons(MY_PORT_NUM);
  servaddr.sin_addr.s_addr = inet_addr( "127.0.0.1" );
 
  /* Connect to the server */
  connect( connSock, (struct sockaddr *)&servaddr, sizeof(servaddr) );
 
  /* Enable receipt of SCTP Snd/Rcv Data via sctp_recvmsg */
  memset( (void *)&events, 0, sizeof(events) );
  events.sctp_data_io_event = 1;
  setsockopt( connSock, SOL_SCTP, SCTP_EVENTS,
               (const void *)&events, sizeof(events) );
 
  /* Expect two messages from the peer */
  for (i = 0 ; i < 2 ; i++) {
 
    in = sctp_recvmsg( connSock, (void *)buffer, sizeof(buffer),
                        (struct sockaddr *)NULL, 0,
                        &sndrcvinfo, &flags );
 
    /* Null terminate the incoming string */
    buffer[in] = 0;
 
    if        (sndrcvinfo.sinfo_stream == LOCALTIME_STREAM) {
      printf("(Local) %s\n", buffer);
    } else if (sndrcvinfo.sinfo_stream == GMT_STREAM) {
      printf("(GMT  ) %s\n", buffer);
    }
 
  }
 
  /* Close our socket and exit */
  close(connSock);
 
  return 0;
}

SCTP的未来

SCTP 是一个相对较新的协议,因为它在 2000 年 10 月成为 RFC。自那时起,它进入所有主要操作系统,包括GNU/Linux、BSD和S solaris和windows。

除了可用性,应用程序还将开始使用 SCTP 作为其主要传输。FTP 和 HTTP 等传统应用程序是基于 SCTP 的功能构建的。其他协议正在使用 SCTP,例如会话启动协议 (SIP) 和通用信道信令系统 7 号 (SS7)。在商业上,您可以在思科的 IOS 中找到 SCTP。

随着SCTP加入2.6 Linux内核,现在可以构建和部署高可用和可靠的网络应用程序。作为基于 IP 的协议,SCTP 是 TCP 和 UDP 的无缝替代,但也扩展了新服务,如多宿主、多流和更高的安全性。现在您已经看到了SCTP的一些高级功能,请探索它的其他功能。Linux 内核 SCTP 项目 (lksctp) 提供 API 扩展和文档,可帮助您在路上。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值