TCP/IP 简介
TCP/IP 是 Transmission Control Protocol/Internet Protocol 的简写,被译为传输控制协议/因特网互联协议,又名网络通讯协议,是 Internet 最基本的协议,也是 Internet 国际互联网络的基础,由网络层的 IP 协议和传输层的 TCP 协议组成。TCP/IP 定义了电子设备如何连入因特网,以及数据如何在它们之间传输的标准。协议采用了 4 层的层级结构,每一层都呼叫它的下一层所提供的协议来完成自己的需求。通俗而言,TCP 负责发现传输的问题,一旦有问题就发出信号,要求重新传输,直到所有数据安全正确地传输到目的地,而 IP 则给因特网的每一台联网设备规定一个地址。
数据传送过程,可以形象地理解为有两个信封,TCP 和 IP 就像是信封,要传递的信息被划分成若干段,每一段塞入一个 TCP 信封,并在该信封面上记录有分段号的信息,再将 TCP 信封塞入 IP 大信封,发送到网络上。在接收端,一个 TCP 软件包收集信封,抽出数据,按发送前的顺序还原,并加以校验,若发现差错,TCP 将会要求重发。对普通用户来说,并不需要了解网络协议的整个结构,仅需了解 IP 的地址格式,即可与世界各地进行网络通信。
TCP/IP 的分层
如下图所示是 TCP/IP 协议的 4 层结构与 OSI 的 7 层结构的对应关系。
TCP 和 UDP 是两种最为著名的传输层协议,二者都使用 IP 作为网络层协议。虽然 TCP 使用不可靠的 IP 服务,但它却提供一种可靠的传输层服务。
- 物理层:物理层负责在物理媒介上传输原始比特流,包括电压、电流和光信号等。它处理硬件设备和物理连接细节,如网线、光纤和无线电波。
- 链路层:有时也称作数据链路层或网络接口层,通常包括操作系统中的设备驱动程序和计算机中对应的网络接口卡。它们一起处理与电缆(或其他任何传输媒介)相关的物理接口细节。它通常通过物理地址(如MAC地址)来识别和定位物理设备。
- 网络层:有时也称作互联网层,处理分组在网络中的活动,例如分组的选路。在 TCP/IP 协议族中,网络层协议包括 IP 协议(网际协议),ICMP 协议(Internet 互联网控制报文协议),以及 IGMP 协议(Internet 组管理协议)。
- 传输层:主要为两台主机上的应用程序提供端到端的通信。在 TCP/IP 协议族中,有两个不相同的传输协议,TCP(传输控制协议)和 UDP(用户数据报协议)。TCP 提供高可靠性的数据通信,它所做的工作包括把应用程序交给它的数据分成合适的数据块交给下面的网络层,确认接收到的分组,设置发送最后确认分组的超时时钟等。UDP 则为应用层提供一种非常简单的服务。它只是把称作数据报的分组从一台主机发送到另一台主机,但并不保证该数据报能到达另一端。任何必需的可靠性必须由应用层来提供。
- 应用层负责处理特定的应用程序细节,以下是一些通用的应用程序协议:
- FTP 文件传输协议;
- SMTP 简单邮件传输协议;
- SNMP 简单网络管理协议。
在 TCP/IP 协议族中,有很多种协议。如下图所示给出了常用协议。
IP 网际协议(Internet Protocol),是网络层上的主要协议。IP协议通过数据包进行传输,数据包中提供了源和目的地址,以便在网络中正确地传递数据。每个连接到互联网的设备都被分配一个唯一的IP地址,用于标识设备的位置。IP协议使用这些地址来确定数据包的源和目的地,并根据网络路由表来选择适当的路径将数据包从源传送到目的地,IP协议还提供了一些其他的功能,包括分片和重组(将大的数据包分割成较小的片段,并在目的地重新组装)、差错检测(通过校验和检查数据包是否损坏)以及拥塞控制(监测网络拥塞并调整数据传输速率)等。
它同时被 TCP 和 UDP 使用。TCP 和 UDP 的每组数据都通过端系统和每个中间路由器中的 IP 层在互联网中进行传输。
IPv4 版本 4 的网际协议(Internet Protocol version 4)。IPv4(我们通常称之为 IP)自 20 世纪 80 年代早期以来一直是网际协议族的主力协议。它使用 32 位的地址,给 TCP、UDP、ICMP 和 IGMP 提供传送分组的服务。
IPv6 版本 6 的网际协议(Internet Protocol version 6)。IPv6 设计于 20 世纪 90 年代中期,用以替代 IPv4。主要变化是使用了 128 位的地址。
TCP 传输控制协议(Transmission Control Protocol),是一种面向连接的协议。它给用户提供可靠的全双工的字节流。TCP 套接口是流套接口(stream socket)的一种。TCP 关心诸如确认、超时和重传等具体细节。
UDP 用户数据报协议(User Datagram Protocol),是一种无连接协议。UDP 套接口是数据报套接口(datagram socket)的一种。UDP 数据报不能保证最终到达它们的目的地。
ICMP 网际控制协议(Internet Control Message Protocol)。ICMP 处理路由器和主机间的错误和控制消息(例如:检查网络是否连通的 ping 命令就是 ICMP 协议工作的过程)。
IGMP 网际组管理协议(Internet Group Management Protocol)。IGMP 用于多播。它用来把一个 UDP 数据报多播到多个主机。
ARP 地址解析协议(Address Resolution Protocol)。ARP 把 IPv4 地址映射到硬件地址(如以太网地址)。ARP 一般用于广播网络,如以太网、令牌环等,而不用于点到点网络。
RARP 反向地址解析协议(Reverse Address Resolution Protocol)。它把硬件地址映射到 IPv4 地址。它有时用于无盘节点的引导。
如下图列出了运行 FTP 协议客户端——服务器模式所涉及到的所有协议。
IP 地址
互联网上的每个接口必须有一个唯一的 Internet 地址(也称作 IP 地址)。IP 地址长度为 32 位且具有一定的结构,五类不同的互联网地址格式,如下图所示。
这些 32 位的地址通常写成四个十进制的数,其中每个整数对应一个字节。这种表示方法称作“点分十进制表示法(Dotted decimal notation)”。区分各类地址的最简单方法是看它的第一个十进制整数。
需要指出的是,多接口主机具有多个 IP 地址,其中每个接口都对应一个 IP 地址。由于互联网上的每个接口必须有一个唯一的 IP 地址,因此必须要有一个管理机构为接入互联网的网络分配 IP 地址。这个管理机构就是互联网络信息中心(Internet Network Information Center),称作 InterNIC。五类地址范围如下表所示,例如:192.168.1.15 属于 C 类地址。
类型 | 范围 |
---|---|
A 类 | 0.0.0.0 到 127.255.255.255 |
B 类 | 128.0.0.0 到 191.255.255.255 |
C 类 | 192.0.0.0 到 223. 255.255.255 |
D 类 | 224.0.0.0 到 239. 255.255.255 |
E 类 | 240.0.0.0 到 247. 255.255.255 |
数据封装
当应用程序用 TCP 传送数据时,数据被送入协议栈中,然后逐个通过每一层直到被当作一串比特流送入网络。其中每一层对收到的数据都要增加一些首部信息(有时还要增加尾部信息),该过程如下图所示。
图 底部表示了各协议首部典型的长度值,如以太网首部为 14 octet、IP 首部为 20 octet 等,以太网数据帧的物理特性是其长度必须在 46~1500 octet 之间。
TCP 传给 IP 的数据单元称作 TCP 报文段或简称为 TCP 段(TCP segment),IP 传给网络接口层的数据单元称作 IP 数据报(IP datagram),通过以太网传输的比特流称作帧(Frame)。
UDP 数据与 TCP 数据基本一致,唯一的不同是 UDP 传给 IP 的信息单元称作 UDP 数据报(UDP datagram),而且 UDP 的首部长为 8 字节。由于 TCP、UDP、ICMP 和 IGMP 都要向 IP 传送数据,因此 IP 必须在生成的 IP 首部中加入某种标识,以表明数据属于哪一层。为此,IP 在首部中存入一个长度为 8 bit 的数值,称作协议域,1 表示为 ICMP 协议,2 表示为 IGMP 协议,6 表示为 TCP 协议,17 表示为 UDP 协议。
数据分用
当目的主机收到一个以太网数据帧时,数据就开始从协议栈中由底向上升,同时去掉各层协议加上的报文首部。每层协议都要去检查报文首部中的协议标识,以确定接收数据的上层协议,这个过程称为数据分用,如下图所示该过程。
端口号
TCP 和 UDP 采用 16 bit 的端口号来识别应用程序。那么这些端口号是如何选择的呢?服务器一般都是通过知名端口号来识别的。例如,对于每个 TCP/IP 实现来说,FTP 服务器的 TCP 端口号都是 21,每个 Telnet 服务器的 TCP 端口号都是 23,每个 TFTP (简单文件传送协议)服务器的 UDP 端口号都是 69。任何 TCP/IP 实现所提供的服务都用知名的 1~1023 之间的端口号。这些知名端口号由 Internet 号分配机构(Internet Assigned Numbers Authority, IANA)来管理。
链路层
TCP/IP 支持多种不同的链路层协议,这取决于网络所使用的硬件,如以太网、令牌环网、FDDI(光纤分布式数据接口)及 RS-232 串行线路等。
从上图可以看出,在 TCP/IP 协议族中,链路层主要有以下几个目的:
- 为 IP 模块发送和接收 IP 数据报。
- 为 ARP 模块发送 ARP 请求和接收 ARP 应答。
- 为 RARP 发送 RARP 请求和接收 RARP 应答。
其中 802.3 针对整个 CSMA /CD 网络,802.4 针对令牌总线网络,802.5 针对令牌环网络。802.2 和 802.3 定义了一个与以太网不同的帧格式。以太网 IP 数据报的封装是在 RFC 894 中定义的,IEEE 802 网络的 IP 数据报封装是在 RFC 1042 中定义的。封装格式,如下图所示。
SLIP 的全称是 Serial Line IP。它是一种在串行线路上对 IP 数据报进行封装的简单形式,在 RFC 1055 中有详细描述。SLIP 适用于家庭中每台计算机几乎都有的 RS-232 串行端口和高速调制解调器接入 Internet。
SLIP 协议定义的帧格式:
- IP 数据报以一个称作 END(0xC0)的特殊字符结束。同时,为了防止数据报到来之前的线路噪声被当成数据报内容,大多数实现在数据报的开始处也传一个 END 字符(如果有线路噪声,那么 END 字符将结束这份错误的报文。这样当前的报文得以正确地传输,而前一个错误报文交给上层后,会发现其内容毫无意义而被丢弃)。
- 如果 IP 报文中某个字符为 END,那么就要连续传输两个字节 0xDB 和 0xDC 来取代它。0xDB 这个特殊字符被称作 SLIP 的 ESC 字符,但是它的值与 ASCII 码的 ESC 字符(0x1B)不同。
- 如果 IP 报文中某个字符为 SLIP 的 ESC 字符,那么就要连续传输两个字节 0xDB 和 0xDD 来取代它。
如下图所示就是含有一个 END 字符和一个 ESC 字符的 IP 报文。在这个例子中,在串行线路上传输的总字节数是原 IP 报文长度再加 4 个字节。
SLIP 是一种简单的帧封装方法,还有一些值得一提的缺陷:
- 每一端必须知道对方的 IP 地址。没有办法把本端的 IP 地址通知给另一端。
- 数据帧中没有类型字段(类似于以太网中的类型字段)。如果一条串行线路用于 SLIP,那么它不能同时使用其他协议。
- SLIP 没有在数据帧中加上检验和(类似于以太网中的 CRC 字段)。如果 SLIP 传输的报文被线路噪声影响而发生错误,只能通过上层协议来发现(另一种方法是,新型的调制解调器可以检测并纠正错误报文)。这样,上层协议提供某种形式的 CRC 就显得很重要。
PPP(Point-to-point protocol)点对点协议修改了 SLIP 协议中的所有缺陷。PPP 包括以下三个部分:
- 在串行链路上封装 IP 数据报的方法。PPP 既支持数据为 8 位和无奇偶检验的异步模式(如大多数计算机上都普遍存在的串行接口),还支持面向比特的同步链接。
- 建立、配置及测试数据链路的链路控制协议(LCP:Link Control Protocol)。它允许通信双方进行协商,以确定不同的选项。
- 针对不同网络层协议的网络控制协议(NCP:Network Control Protocol)体系。
PPP 格式封装,如下图所示。
由于标志字符的值是 0x7E,因此当该字符出现在信息字段中时,PPP 需要对它进行转义。在同步链路中,该过程是通过一种称作比特填充 (bit stuffing )的硬件技术来完成的。在异步链路中,特殊字符 0x7D 用作转义字符。当它出现在 PPP 数据帧中时,那么紧接着的字符的第 6 个比特要取其补码,具体实现过程如下:
- 当遇到字符 0x7E 时,需连续传送两个字符:0x7D 和 0x5E,以实现标志字符的转义。
- 当遇到转义字符 0x7D 时,需连续传送两个字符:0x7D 和 0x5D,以实现转义字符的转义。
- 默认情况下,如果字符的值小于 0x20(比如,一个 ASCII 控制字符),一般都要进行转义。例如,遇到字符 0x01 时需连续传送 0x7D 和 0x21 两个字符(这时,第 6 个比特取补码后变为 1,而前面两种情况均把它变为 0)。
这样做的原因是防止它们出现在双方主机的串行接口驱动程序或调制解调器中,因为有时它们会把这些控制字符解释成特殊的含义。另一种可能是用链路控制协议来指定是否需要对这 32 个字符中的某一些值进行转义。默认情况下是对所有的 32 个字符都进行转义。
与 SLIP 类似,由于 PPP 经常用于低速的串行链路,因此减少每一帧的字节数可以降低应用程序的交互时延。利用链路控制协议,大多数的产品通过协商可以省略标志符和地址字段,并且把协议字段由 2 个字节减少到 1 个字节。如果我们把 PPP 的帧格式与前面的 SLIP 的帧格式进行比较会发现,PPP 只增加了 3 个额外的字节:1 个字节留给协议字段,另 2 个给 CRC 字段使用。另外,使用 IP 网络控制协议,大多数的产品可以通过协商采用 Van Jacobson 报文首部压缩方法(对应于 CSLIP 压缩),减小 IP 和 TCP 首部长度。
总的来说,PPP 比 SLIP 具有下面这些优点:
- PPP 支持在单根串行线路上运行多种协议,不只是 IP 协议。
- 每一帧都有循环冗余检验。
- 通信双方可以进行 IP 地址的动态协商(使用 IP 网络控制协议)。
- 与 CSLIP 类似,对 TCP 和 IP 报文首部进行压缩。
- 链路控制协议可以对多个数据链路选项进行设置。为这些优点付出的代价是在每一帧的首部增加 3 个字节,当建立链路时要发送几帧协商数据,以及更为复杂的实现。
以太网和 802.3 对数据帧的长度都有一个限制,其最大值分别是 1500 octet 和 1492 octet,链路层的这个特性称作 MTU(最大传输单元)。
如果 IP 层有一个数据报要传,而且数据的长度比链路层的 MTU 还大,那么 IP 层就需要进行分片,把数据报分成若干片,这样每一个都小于 MTU。
当在同一个网络上的两台主机互相进行通信时,该网络的 MTU 是非常重要的。但是如果两台主机之间的通信要通过多个网络,那么每个网络的链路层就可能有不同的 MTU,重要的不是两台主机所在网络的 MTU 值,重要的是两台主机路径的最小 MTU,它被称作路径 MTU。
两台主机之间的路径 MTU 不一定是个常数。它取决于当时所选择的路由。而选路不一定是对称的,因此路径 MTU 在两个方向上不一定是一致的。
IP 网际协议
IP 是 TCP/IP 协议族中最为核心的协议。所有的 TCP、UDP、ICMP 及 IGMP 数据都要以 IP 数据报格式传输。许多刚开始接触 TCP/IP 的人对 IP 提供不可靠、无连接的数据报传送服务感到很奇怪。
不可靠(unreliable)的意思是它不能保证 IP 数据报能成功地到达目的地。IP 仅提供最好的传输服务。如果发生某种错误时,如某个路由器暂时用完了缓冲区,IP 有一个简单的错误处理算法:丢弃该数据报,然后发送 ICMP 消息报给信源端。任何要求的可靠性必须由上层来提供(如 TCP)。
无连接(connectionless)这个术语的意思是 IP 并不维护任何关于后续数据报的状态信息。每个数据报的处理是相互独立的。这也说明,IP 数据报可以不按发送顺序接收。如果一信源向相同的信宿发送两个连续的数据报(先是 A,然后是 B),每个数据报都是独立地进行路由选择,可能选择不同的路线,因此 B 可能在 A 到达之前先到达。
IP 数据报的格式,如下图所示。普通的 IP 首部长为 20 个字节,除非含有选项字段。
最高位在左边,记为 0 bit;最低位在右边,记为 31 bit。4 个字节的 32 bit 值以下面的次序传输:首先是 0~7 bit,其次 8~15 bit,然后 16~23 bit,最后是 24~31 bit。这种传输次序称作 big endian(大端)字节序。由于 TCP/IP 首部中所有的二进制整数在网络中传输时都要求以这种次序,因此它又称作网络字节序。以其他形式存储二进制整数的机器,如 little endian(小端)格式,则必须在传输数据之前把首部转换成网络字节序。
目前的协议版本号是 4,因此 IP 有时也称作 IPv4。首部长度指的是首部占 32 bit 字的数目,包括任何选项。由于它是一个 4 比特字段,因此首部最长为 60 个字节。普通 IP 数据报(没有任何选择项)字段的值是 5。服务类型(TOS)字段包括一个 3 bit 的优先权子字段(现在已被忽略),4 bit 的 TOS 子字段和 1 bit 未用位但必须置 0。4 bit 的 TOS 分别代表:最小时延、最大吞吐量、最高可靠性和最小费用。4 bit 中只能置其中 1 bit。如果所有 4 bit 均为 0,那么就意味着是一般服务。
物理网络层一般要限制每次发送数据帧的最大长度,任何时候 IP 层接收到一份要发送的 IP 数据报时,它要判断向本地哪个接口发送数据(选路),并查询该接口获得其 MTU。IP 把 MTU 与数据报长度进行比较,如果需要则进行分片。分片可以发生在原始发送端主机上,也可以发生在中间路由器上。
把一份 IP 数据报分片后,只有到达目的地址后才进行组装,重新组装由目的端的 IP 层来完成,其目的是使分片和重新组装过程对传输层(TCP 和 UDP)是透明的,除了某些可能的越级操作外,已经分片过的数据报有可能会再次进行分片(可能不止一次)。IP 首部中包含的数据为分片和重新组装提供了足够的信息。
对于发送端发送的每份 IP 数据报来说,其标识字段都包含一个唯一值。该值在数据报分片时被复制到每个片中,标志字段用其中一个比特来表示“更多的片”。除了最后一片外,其他每个组成数据报的片都要把该比特置 1。片偏移字段指的是该片偏移原始数据报开始处的位置。另外,当数据报被分片后,每个片的总长度值要改为该片的长度值。最后,标志字段中有一个比特称作“不分片”位,如果将这一比特置 1,IP 将不对数据报进行分片。
当 IP 数据报被分片后,每一片都成为一个分组,具有自己的 IP 首部,并在选择路由时与其他分组独立。这样,当数据报的这些片到达目的端时有可能会失序,但是在 IP 首部中有足够的信息让接收端能正确地组装这些数据报分片。
ARP 地址解析协议
当一台主机把以太网数据帧发送到位于同一局域网上的另一台主机时,是根据 48 bit 的以太网地址来确定目的接口的。设备驱动程序从不检查 IP 数据报中的目的 IP 地址。地址解析为这两种不同的地址形式(32 bit 的 IP 地址和数据链路层使用的任何类型的地址)提供映射。
在以太网上解析 IP 地址时,ARP 请求和应答分组的格式,如下图所示(ARP 可以用于其他类型的网络,可以解析 IP 地址以外的地址,紧跟着帧类型字段的前四个字段指定了最后四个字段的类型和长度)。
以太网报头中的前两个字段是以太网的目的地址和源地址。目的地址为全 1 的特殊地址是广播地址,电缆上的所有以太网接口都要接收广播的数据帧。两个字节长的以太网帧类型表示后面数据的类型,对于 ARP 请求或应答来说,该字段的值为 0x0806。
硬件类型字段表示硬件地址的类型,它的值为 1 即表示以太网地址,协议类型字段表示要映射的协议地址类型。它的值为 0x0800 即表示 IP 地址。它的值与包含 IP 数据报的以太网数据帧中的类型字段的值相同。
硬件地址长度和协议地址长度分别指出硬件地址和协议地址的长度,以字节为单位。对于以太网上 IP 地址的 ARP 请求或应答来说,它们的值分别为 6 和 4。
操作字段指出四种操作类型,它们是 ARP 请求(值为 1)、ARP 应答(值为 2)、RARP 请求(值为 3)和 RARP 应答(值为 4)。
对于一个 ARP 请求来说,除目的端硬件地址外的所有其他的字段都有填充值,当系统收到一份目的端为本机的 ARP 请求报文后,它就把硬件地址填进去,然后用两个目的端地址分别替换两个发送端地址,并把操作字段置为 2,最后把它发送回去。
ARP 高效运行的关键是由于每个主机上都有一个 ARP 高速缓存。这个高速缓存存放了最近 Internet 地址到硬件地址之间的映射记录。
在 SylixOS 中,可以使用 arp 命令来查看 ARP 缓存表,如下所示:
# arp –a
FACE INET ADDRESS PHYSICAL ADDRESS TYPE
en1 192.168.7.40 00:ff:ff:6f:a7:a0 dynamic
48 bit 的以太网地址用 6 个十六进制的数来表示,中间以冒号分隔。
ICMP 报文控制协议
ICMP 经常被认为是 IP 层的一个组成部分。它传递差错报文以及其他需要注意的信息,ICMP 报文通常被 IP 层或更高层协议(TCP 或 UDP)使用,一些 ICMP 报文把差错报文返回给用户进程。ICMP 报文如下图所示。
各种类型的 ICMP 报文如下表所示,不同类型由报文中的类型字段和代码字段来共同决定。
类型 | 代码 | 描述 | 查询 | 差错 |
---|---|---|---|---|
0 | 0 | 回显应答(ping 应答) | ● | |
3 | 0 | 网络不可达 | ● | |
3 | 1 | 主机不可达 | ● | |
3 | 2 | 协议不可达 | ● | |
3 | 3 | 端口不可达 | ● | |
3 | 4 | 需要进行分片但设置了不分片 bit 位 | ● | |
3 | 5 | 源站选路失败 | ● | |
3 | 6 | 目的网络不认识 | ● | |
3 | 7 | 目的主机不认识 | ● | |
3 | 8 | 源主机被隔离 | ● | |
3 | 9 | 目的网络被强制禁止 | ● | |
3 | 10 | 目的主机被强制禁止 | ● | |
3 | 11 | 由于服务类型 TOS,网络不可达 | ● | |
3 | 12 | 由于服务类型 TOS,主机不可达 | ● | |
3 | 13 | 由于过滤,通信被强制禁止 | ● | |
3 | 14 | 主机越权 | ● | |
3 | 15 | 优先级中止生效 | ● | |
4 | 0 | 源端被关闭(基本流控) | ● | |
5 | 0 | 对网络重定向 | ● | |
5 | 1 | 对主机重定向 | ● | |
5 | 2 | 对服务类型和网络重定向 | ● | |
5 | 3 | 对服务类型和主机重定向 | ● | |
8 | 0 | 请求回显(ping) | ● | |
9 | 0 | 路由器通告 | ● | |
10 | 0 | 路由器请求 | ● | |
11 | 0 | 传输期间生存时间为 0 | ● | |
11 | 1 | 在数据报组装期间生存时间为 0 | ● | |
12 | 0 | 坏的 IP 首部(包括各种差错) | ● | |
12 | 1 | 缺少必须的选项 | ● | |
13 | 0 | 时间戳请求 | ● | |
14 | 0 | 时间戳应答 | ● | |
15 | 0 | 信息请求(不再使用) | ● | |
16 | 0 | 信息应答(不再使用) | ● | |
17 | 0 | 地址掩码请求 | ● | |
18 | 0 | 地址掩码应答 | ● |
下面各种情况都不会导致产生 ICMP 差错报文:
- ICMP 差错报文(但是,ICMP 查询报文可能会产生 ICMP 差错报文)。
- 目的地址是广播地址或多播地址的 IP 数据报。
- 作为链路层广播的数据报。
- 不是 IP 分片的第一片。
- 源地址不是单个主机的数据报。也就是说,源地址不能为零地址、环回地址、广播地址或多播地址。
这些规则是为了防止过去允许 ICMP 差错报文对广播分组响应所带来的广播风暴。
UDP 用户数据报协议
UDP 是一个简单的面向数据报的运输层协议,这与面向流字符的协议不同,如 TCP,应用程序产生的全体数据与真正发送的单个 IP 数据报可能没有什么联系。UDP 不提供可靠性:它把应用程序传给 IP 层的数据发送出去,但是并不保证它们能到达目的地。UDP 数据报封装成一份 IP 数据报的格式,如下图所示。
UDP 长度字段指的是 UDP 首部和 UDP 数据的字节长度。UDP 检验和覆盖 UDP 首部和 UDP 数据。
TCP 传输控制协议
尽管 TCP 和 UDP 都通过相同的网络层(IP)进行传输,TCP 却向应用层提供与 UDP 完全不同的服务。TCP 提供一种面向连接的、可靠的字节流服务。面向连接意味着两个使用 TCP 的应用(通常是一个客户和一个服务器)在彼此交换数据之前必须先建立一个 TCP 连接。这一过程与打电话很相似,先拨号振铃,等待对方摘机说“喂”,然后才说明是谁。在一个 TCP 连接中,仅有两方进行彼此通信。
TCP 通过下列方式来提供可靠性:
- 应用数据被分割成 TCP 认为最适合发送的数据块。这和 UDP 完全不同,应用程序产生的数据报长度将保持不变,由 TCP 传递给 IP 的信息单位称为报文段或段(segment)。
- 当 TCP 发出一个段后,它启动一个定时器,等待目的端确认收到这个报文段。如果不能及时收到一个确认,将重发这个报文段。
- 当 TCP 收到发自 TCP 连接另一端的数据,它将发送一个确认,这个确认不是立即发送,通常将推迟一点时间。
- TCP 将保持它首部和数据的检验和。这是一个端到端的检验和,目的是检测数据在传输过程中的任何变化,如果收到段的检验和有差错,TCP 将丢弃这个报文段和不确认收到此报文段(希望发端超时并重发)。
- 因为 TCP 报文段作为 IP 数据报来传输,而 IP 数据报的到达可能会失序,因此 TCP 报文段的到达也可能会失序,如果必要,TCP 将对收到的数据进行重新排序,将收到的数据以正确的顺序交给应用层。
- 既然 IP 数据报会发生重复,TCP 的接收端必须丢弃重复的数据。
- TCP 还能提供流量控制,TCP 连接的每一方都有固定大小的缓冲空间,TCP 的接收端只允许另一端发送接收端缓冲区所能接纳的数据,这将防止较快主机致使较慢主机的缓冲区溢出。
TCP 数据被封装在一个 IP 数据报中,如下图所示。
每个 TCP 段都包含源端和目的端的端口号,用于寻找发端和收端应用程序。这两个值加上 IP 首部中的源端 IP 地址和目的端 IP 地址唯一确定一个 TCP 连接。有时,一个 IP 地址和一个端口号也称为一个插口(socket),包含客户端的 IP 地址、客户端的端口号、服务器端的 IP 地址和服务器端的端口号的四元组可唯一确定互联网络中每个 TCP 连接的双方。
序号用来标识从 TCP 发端向 TCP 收端发送的数据字节流,它表示在这个报文段中的第一个数据字节。如果将字节流看作在两个应用程序间的单向流动,则 TCP 用序号对每个字节进行计数。序号是 32bit 的无符号数,序号到达最大值后又从 0 开始。
当建立一个新的连接时,SYN 标志变成 1。序号字段包含由这个主机选择的该连接的初始序号 ISN(Initial Sequence Number)。该主机要发送数据的第一个字节序号为这个 ISN 加 1,因为 SYN 标志消耗了一个序号。
既然每个传输的字节都被计数,确认序号包含发送确认的一端所期望收到的下一个序号。因此,确认序号应当是上次已成功收到数据字节序号加 1。只有 ACK 标志为 1 时确认序号字段才有效。发送 ACK 无需任何代价,因为 32bit 的确认序号字段和 ACK 标志一样,总是 TCP 首部的一部分。因此,我们看到一旦一个连接建立起来,这个字段总是被设置,ACK 标志也总是被设置为 1。
TCP 为应用层提供全双工服务,这意味数据能在两个方向上独立地进行传输,因此,连接的每一端必须保持每个方向上的传输数据序号。TCP 可以表述为一个没有选择确认或否认的滑动窗口协议。我们说 TCP 缺少选择确认是因为 TCP 首部中的确认序号表示发方已成功收到字节,但还不包含确认序号所指的字节。当前还无法对数据流中选定的部分进行确认。例如,如果 1~1024 字节已经成功收到,下一报文段中包含序号从 2049~3072 的字节,接收端并不能确认这个新的报文段。它所能做的就是发回一个确认序号为 1025 的 ACK,它也无法对一个报文段进行否认。例如,如果收到包含 1025~2048 字节的报文段,但它的校验和错,TCP 接收端所能做的就是发回一个确认序号为 1025 的 ACK。
首部长度给出首部中 32bit 字的数目,需要这个值是因为任选字段的长度是可变的,这个字段占 4bit,因此 TCP 最多有 60 字节的首部。然而,没有任选字段,正常的长度是 20 字节。在 TCP 首部中有 6 个标志比特,它们中的多个可同时被设置为 1。
TCP 首部中 6 个比特标志:
- URG 紧急指针(urgent pointer)有效。
- ACK 确认序号有效。
- PSH 接收方应该尽快将这个报文段交给应用层。
- RST 重建连接。
- SYN 同步序号用来发起一个连接。
- FIN 发端完成发送任务。
下图显示了建立一条 TCP 连接的过程:
- 请求端(通常称为客户)发送一个 SYN 段指明客户打算连接的服务器的端口,以及初始序号(ISN)。
- 服务器发回包含服务器的初始序号的 SYN 报文段作为应答。同时,将确认序号设置为客户的 ISN 加 1 以对客户的 SYN 报文段进行确认。一个 SYN 将占用一个序号。
- 客户必须将确认序号设置为服务器的 ISN 加 1 以对服务器的 SYN 报文段进行确认。
这个过程也称为三次握手(three-way handshake)。
建立一个连接需要三次握手,而终止一个连接要经过 4 次握手,这由 TCP 的半关闭(half-close)造成的。既然一个 TCP 连接是全双工(即数据在两个方向上能同时传递),那么每个方向必须单独地进行关闭。原则就是,当一方完成它的数据发送任务后就能发送一个 FIN 来终止这个方向连接。当一端收到一个 FIN,它必须通知应用层另一端已经终止了那个方向的数据传送。发送 FIN 通常是应用层进行关闭的结果。
收到一个 FIN 只意味着在这一方向上没有数据流动。一个 TCP 连接在收到一个 FIN 后仍能发送数据,而这对利用半关闭的应用来说是可能的,尽管在实际应用中只有很少的 TCP 应用程序这样做。正常关闭过程如下图所示,首先进行关闭的一方(即发送第一个 FIN)将执行主动关闭,而另一方(收到这个 FIN)执行被动关闭。通常一方完成主动关闭而另一方完成被动关闭。
TIME_WAIT 状态也称为 2MSL 等待状态。每个具体 TCP 实现必须选择一个报文段最大生存时间 MSL(Maximum Segment Lifetime),它是任何报文段被丢弃前在网络内的最长时间。我们知道这个时间是有限的,因为 TCP 报文段以 IP 数据报在网络内传输,而 IP 数据报则有限制其生存时间的 TTL 字段。RFC 793 指出 MSL 为 2 分钟。然而,实现中的常用值是 30 秒、1 分钟或 2 分钟。对 IP 数据报 TTL 的限制是基于跳数,而不是定时器。对一个具体实现所给定的 MSL 值,处理的原则是:当 TCP 执行一个主动关闭,并发回最后一个 ACK,该连接必须在 TIME_WAIT 状态停留的时间为 2 倍的 MSL。这样可让 TCP 再次发送最后的 ACK 以防这个 ACK 丢失(另一端超时并重发最后的 FIN)。这种 2MSL 等待的另一个结果是这个 TCP 连接在 2MSL 等待期间,定义这个连接的插口(客户的 IP 地址和端口号,服务器的 IP 地址和端口号)不能再被使用。这个连接只能在 2MSL 结束后才能再被使用。
SCTP 流控制传输协议
SCTP(Stream Control Transmission Protocol)是一种传输层协议,用于在计算机网络中可靠地传输数据。它是与TCP(Transmission Control Protocol)和 UDP(User Datagram Protocol)并列的第三种传输层协议。
SCTP 最初被设计用于提供可靠的传输服务,以满足一些特定应用对可靠性和传输效率的要求。与TCP不同,SCTP提供了一种多流(Multi-Stream)和多宿主(Multi-Homing)的机制,在一个SCTP连接上可以同时传输多个逻辑流,以及在多个网络接口之间进行冗余和负载均衡。
SCTP 的一些主要特点和功能包括:
- 可靠性:SCTP 提供了错误检测、数据顺序控制、重传机制和拥塞控制等功能,以确保数据的可靠传输。
- 多流复用:SCTP 可以在一个 SCTP 连接上同时传输多个逻辑流,每个流都有独立的序号和传输控制。
- 多宿主支持:SCTP 允许一个 SCTP 端点同时使用多个网络接口进行通信,以提高冗余性、负载均衡和网络容错性。
- 心跳机制:SCTP 支持定期发送心跳包以监测连接的状态,并在连接中断时快速检测和恢复连接。
- 部分可靠性:SCTP 支持部分可靠传输,即发送方可以指定某些数据的重要性和传输要求。
- 有序交付:SCTP 可以按顺序交付数据,保证数据按照发送方的顺序到达接收方。
SCTP 通常用于需要可靠和高效传输的应用,如 VoIP(Voice over IP)、视频流传输、实时游戏和远程桌面等。它的设计目标是在面向连接的可靠传输(如TCP)和无连接的不可靠传输(如UDP)之间提供一种折中的解决方案。
SylixOS 系统需要 sctpdrv 来支持完整的 SCTP 协议功能(sctpdrv 工程可向翼辉公司申请),SCTP 协议套接字类型(type) 包括:SOCK_STREAM 和 SOCK_SEQPACKET。
SCTP 协议的编程过程如下:
- 创建SCTP套接字:使用 socket 函数创建一个SCTP套接字。指定协议参数为 IPPROTO_SCTP,并指定套接字类型,如 SOCK_STREAM 或 SOCK_SEQPACKET。
- 绑定套接字:使用 bind 函数将套接字绑定到一个本地地址和端口上。可以使用 struct sockaddr_in 或 struct sockaddr_in6 结构指定地址信息。
- 设置SCTP选项(可选):根据需要,可以使用 setsockopt 函数设置SCTP套接字的选项,如设置多宿主、流控制等。
- 监听连接请求(可选):如果需要作为服务器接受连接,可以使用 listen 函数开始监听连接请求。
- 接受连接或建立连接(可选):如果是服务器,可以使用 accept 函数接受客户端的连接请求。如果是客户端,可以使用 connect 函数与服务器建立连接。
- 数据传输:使用 send 和 recv 函数进行数据的发送和接收。根据需要,可以使用多个流进行并行传输。
- 关闭连接:使用 close 函数关闭SCTP连接。
SCTP 协议的 socket 创建方法如下:
#include <netinet/sctp.h>
int sock;
sock = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);