4. 传输协议 (TRANSPORT PROTOCOLS)
4.1 用户数据报协议 -- UDP (USER DATAGRAM PROTOCOL)
4.1.1 简介 (INTRODUCTION)
用户数据报协议 (User Datagram Protocol, UDP) [UDP:1] 仅提供最小的传输服务 -- 非保证的数据报传递 -- 并为应用程序提供对IP层数据报服务的直接访问。UDP被那些不需要TCP服务级别的应用程序使用,或者被那些希望使用TCP不可用的通信服务(例如,组播或广播传递)的应用程序使用。
UDP几乎是一个空协议; 它在IP之上提供的唯一服务是数据的校验和以及按端口号进行的多路复用。因此,运行在UDP上的应用程序必须直接处理面向连接的协议本应处理的端到端通信问题 -- 例如,可靠传递的重传、分组和重组、流控制、拥塞避免等(当需要这些功能时)。IP和TCP之间相当复杂的耦合将在UDP和许多使用UDP的应用程序之间的耦合中得到反映。
4.1.2 协议遍历 (PROTOCOL WALK-THROUGH)
UDP规范中没有已知的错误。
4.1.3 具体问题 (SPECIFIC ISSUES)
4.1.3.1 端口 (Ports)
UDP知名端口遵循与TCP知名端口相同的规则; 请参见下面的第4.2.2.1节。
如果数据报到达寻址到UDP端口但该端口没有挂起的LISTEN调用,UDP 应该 (SHOULD) 发送ICMP端口不可达消息。
4.1.3.2 IP选项 (IP Options)
UDP 必须 (MUST) 将从IP层接收的任何IP选项透明地传递到应用层。
应用程序 必须 (MUST) 能够指定要在其UDP数据报中发送的IP选项,UDP 必须 (MUST) 将这些选项传递到IP层。
讨论 (DISCUSSION):
目前,需要通过UDP传递的唯一选项是源路由 (Source Route)、记录路由 (Record Route) 和时间戳 (Time Stamp)。然而,将来可能会定义新的选项,UDP不需要也不应该对它传递到应用程序或从应用程序传递过来的选项的格式或内容做任何假设; 一个例外可能是IP层安全选项。
基于UDP的应用程序需要从请求数据报中获取源路由,并提供反向路由以发送相应的回复。
4.1.3.3 ICMP消息 (ICMP Messages)
UDP 必须 (MUST) 将从IP层接收的所有ICMP错误消息传递到应用层。从概念上讲,至少可以通过对ERROR_REPORT例程的上调用来实现这一点(参见第4.2.4.1节)。
讨论 (DISCUSSION):
请注意,由发送UDP数据报导致的ICMP错误消息是异步接收的。希望接收ICMP错误消息的基于UDP的应用程序负责维护必要的状态,以便在这些消息到达时对其进行解复用; 例如,应用程序可以为此目的保留一个挂起的接收操作。应用程序还负责避免因较早使用相同端口而导致的延迟ICMP错误消息造成的混淆。
4.1.3.4 UDP校验和 (UDP Checksums)
主机 必须 (MUST) 实现生成和验证UDP校验和的功能。应用程序 可以 (MAY) 可选地能够控制是否生成UDP校验和,但它 必须 (MUST) 默认启用校验和。
如果接收到校验和非零但无效的UDP数据报,UDP 必须 (MUST) 静默丢弃该数据报。应用程序 可以 (MAY) 可选地能够控制是否应丢弃没有校验和的UDP数据报或将其传递给应用程序。
讨论 (DISCUSSION):
一些通常仅在局域网上运行的应用程序选择为了效率而关闭UDP校验和。结果,已经报告了大量未检测到的错误案例。是否应该关闭UDP校验和一直是非常有争议的。
实现 (IMPLEMENTATION):
UDP校验和中存在一个常见的实现错误。与TCP校验和不同,UDP校验和是可选的; 在UDP头的校验和字段中传输值零表示不存在校验和。如果发送器实际计算的UDP校验和为零,它必须将校验和传输为全1(65535)。接收器不需要特殊操作,因为在1的补码算术中零和65535是等效的。
4.1.3.5 UDP多宿主 (UDP Multihoming)
当接收到UDP数据报时,其特定目标地址 必须 (MUST) 传递到应用层。
应用程序 必须 (MUST) 能够指定用于发送UDP数据报的IP源地址,或将其保持未指定(在这种情况下,网络软件将选择适当的源地址)。应该 (SHOULD) 有一种方法将选择的源地址传递到应用层(例如,以便应用程序稍后可以仅从相应的接口接收回复数据报)。
讨论 (DISCUSSION):
使用UDP的请求/响应应用程序应该使用与请求的特定目标地址相同的源地址作为响应。请参见 [INTRO:1] 的"一般问题"部分。
4.1.3.6 无效地址 (Invalid Addresses)
具有无效IP源地址(例如,广播或组播地址)的UDP数据报必须被UDP或IP层丢弃(参见第3.2.1.3节)。
当主机发送UDP数据报时,源地址 必须 (MUST) 是主机的IP地址之一。
4.1.4 UDP/应用层接口 (UDP/APPLICATION LAYER INTERFACE)
UDP的应用程序接口 必须 (MUST) 提供本文档第3.4节中描述的IP/传输接口的完整服务。因此,使用UDP的应用程序需要第3.4节中描述的GET_SRCADDR()、GET_MAXSIZES()、ADVISE_DELIVPROB() 和 RECV_ICMP() 调用的功能。例如,GET_MAXSIZES() 可用于了解特定 {接口, 远程主机, TOS} 三元组的有效最大UDP数据报大小。
应用层程序 必须 (MUST) 能够设置TTL和TOS值以及用于发送UDP数据报的IP选项,并且这些值必须透明地传递到IP层。UDP 可以 (MAY) 将接收到的TOS传递到应用层。
4.1.5 UDP要求总结 (UDP REQUIREMENTS SUMMARY)
| 功能 | 章节 | MUST | SHOULD | MAY | SHOULD NOT | MUST NOT |
|---|---|---|---|---|---|---|
| UDP | ||||||
| 发送端口不可达消息 | 4.1.3.1 | x | ||||
| UDP中的IP选项 | ||||||
| - 将接收到的IP选项传递到应用层 | 4.1.3.2 | x | ||||
| - 应用层可以在发送时指定IP选项 | 4.1.3.2 | x | ||||
| - UDP将IP选项向下传递到IP层 | 4.1.3.2 | x | ||||
| 将ICMP消息传递到应用层 | 4.1.3.3 | x | ||||
| UDP校验和 | ||||||
| - 能够生成/检查校验和 | 4.1.3.4 | x | ||||
| - 静默丢弃错误校验和 | 4.1.3.4 | x | ||||
| - 发送方可选不生成校验和 | 4.1.3.4 | x | ||||
| - 默认启用校验和 | 4.1.3.4 | x | ||||
| - 接收方可选要求校验和 | 4.1.3.4 | x | ||||
| UDP多宿主 | ||||||
| - 将特定目标地址传递到应用程序 | 4.1.3.5 | x | ||||
| - 应用层可以指定本地IP地址 | 4.1.3.5 | x | ||||
| - 应用层指定通配符本地IP地址 | 4.1.3.5 | x | ||||
| - 应用层收到使用的本地IP地址通知 | 4.1.3.5 | x | ||||
| UDP/IP静默丢弃错误的IP源地址 | 4.1.3.6 | x | ||||
| 仅发送有效的IP源地址 | 4.1.3.6 | x | ||||
| UDP应用接口服务 | ||||||
| 为应用程序提供3.4的完整IP接口 | 4.1.4 | x | ||||
| - 发送数据报时能够指定TTL、TOS、IP选项 | 4.1.4 | x | ||||
| - 将接收到的TOS传递到应用层 | 4.1.4 | x |
4.2 传输控制协议 -- TCP (TRANSMISSION CONTROL PROTOCOL)
4.2.1 简介 (INTRODUCTION)
传输控制协议 (Transmission Control Protocol, TCP) [TCP:1] 是互联网套件的主要虚拟电路传输协议。TCP提供可靠的、按顺序传递的全双工八位字节流(8位字节)。TCP被那些需要可靠的、面向连接的传输服务的应用程序使用,例如,邮件 (SMTP)、文件传输 (FTP) 和虚拟终端服务 (Telnet); 这些应用层协议的要求在 [INTRO:1] 中描述。
[注:由于第4.2节TCP部分内容极长(约1400行),包含大量技术细节,完整翻译正在进行中。当前版本已完成UDP部分的完整翻译。]
4.2.2 协议遍历 (PROTOCOL WALK-THROUGH)
4.2.2.1 知名端口 (Well-Known Ports): RFC-793 第2.7节
讨论 (DISCUSSION):
TCP保留端口号范围0-255用于"知名"端口,用于访问在互联网上标准化的服务。端口空间的其余部分可以自由分配给应用程序进程。当前的知名端口定义在标题为"已分配编号"的RFC [INTRO:6] 中列出。定义新知名端口的先决条件是一个RFC文档,该文档要足够详细地记录所提议的服务以允许新的实现。
一些系统通过添加TCP端口空间的第三个细分来扩展这一概念:保留端口 (reserved ports),这些端口通常用于操作系统特定的服务。例如,保留端口可能介于256和某个系统相关的上限之间。一些系统进一步选择通过仅允许特权用户打开具有这些端口值的TCP连接来保护知名端口和保留端口。只要主机不假定所有主机都以这种方式保护其低编号端口,这是完全合理的。
4.2.2.2 Push的使用 (Use of Push): RFC-793 第2.8节
当应用程序发出一系列SEND调用而不设置PUSH标志时,TCP 可以 (MAY) 在内部聚合数据而不发送它。类似地,当接收到一系列没有PSH位的段时,TCP 可以 (MAY) 在内部排队数据而不将其传递给接收应用程序。
PSH位不是记录标记,并且独立于段边界。发送器 应该 (SHOULD) 在对数据进行分组时合并连续的PSH位,以发送尽可能大的段。
TCP 可以 (MAY) 在SEND调用上实现PUSH标志。如果未实现PUSH标志,则发送TCP:(1) 不得无限期地缓冲数据,以及 (2) 必须 (MUST) 在最后一个缓冲段中设置PSH位(即,当没有更多排队数据要发送时)。
RFC-793在第48、50和74页的讨论错误地暗示接收到的PSH标志必须传递到应用层。将接收到的PSH标志传递到应用层现在是 可选的 (OPTIONAL)。
应用程序在逻辑上需要在SEND调用中设置PUSH标志,每当它需要强制传递数据以避免通信死锁时。然而,TCP 应该 (SHOULD) 尽可能发送最大大小的段,以提高性能(参见第4.2.3.4节)。
讨论 (DISCUSSION):
当SEND调用上未实现PUSH标志时,即当应用程序/TCP接口使用纯流模型时,聚合任何小数据片段以形成合理大小的段的责任部分由应用层承担。
通常,交互式应用程序协议必须至少在每个命令或响应序列的最后一个SEND调用中设置PUSH标志。像FTP这样的批量传输协议应该在文件的最后一个段上设置PUSH标志,或者在必要时防止缓冲区死锁时设置。
在接收器端,PSH位强制将缓冲的数据传递给应用程序(即使接收到的数据少于完整缓冲区)。相反,缺少PSH位可用于避免对应用程序进程的不必要的唤醒调用; 这对于大型分时主机来说可能是重要的性能优化。将PSH位传递给接收应用程序允许在应用程序内进行类似的优化。
4.2.2.3 窗口大小 (Window Size): RFC-793 第3.1节
窗口大小 必须 (MUST) 被视为无符号数,否则大窗口大小将看起来像负窗口,TCP将无法工作。建议 (RECOMMENDED) 实现在连接记录中为发送和接收窗口大小保留32位字段,并用32位进行所有窗口计算。
讨论 (DISCUSSION):
已知TCP头中的窗口字段对于高速、长延迟路径来说太小了。已经定义了实验性的TCP选项来扩展窗口大小; 例如参见 [TCP:11]。为了预期采用这样的扩展,TCP实现者应该将窗口视为32位。
4.2.2.4 紧急指针 (Urgent Pointer): RFC-793 第3.1节
第二句话有错误:紧急指针指向紧急数据序列中最后一个八位字节的序列号(而不是LAST+1)。第56页(最后一句)的描述是正确的。
TCP 必须 (MUST) 支持任意长度的紧急数据序列。
TCP 必须 (MUST) 在接收到紧急指针且之前没有挂起的紧急数据时,或者每当紧急指针在数据流中前进时,异步通知应用层。必须 (MUST) 有一种方法让应用程序了解从连接中还有多少紧急数据要读取,或者至少确定是否还有更多紧急数据要读取。
讨论 (DISCUSSION):
虽然紧急机制可用于任何应用程序,但它通常用于向Telnet程序发送"中断"类型的命令(参见 [INTRO:1] 中的"使用Telnet同步序列"部分)。
异步或"带外"通知将允许应用程序进入"紧急模式",从TCP连接读取数据。这允许将控制命令发送到其正常输入缓冲区充满未处理数据的应用程序。
实现 (IMPLEMENTATION):
第4.2.4.1节中描述的通用ERROR-REPORT()上调用是通知应用程序紧急数据到达的一种可能机制。
4.2.2.5 TCP选项 (TCP Options): RFC-793 第3.1节
TCP 必须 (MUST) 能够在任何段中接收TCP选项。TCP 必须 (MUST) 忽略它不实现的任何TCP选项而不出错,假设该选项有长度字段(将来定义的所有TCP选项都将有长度字段)。TCP 必须 (MUST) 准备好处理非法选项长度(例如,零)而不崩溃; 建议的程序是重置连接并记录原因。
4.2.2.6 最大段大小选项 (Maximum Segment Size Option): RFC-793 第3.1节
TCP 必须 (MUST) 实现发送和接收最大段大小选项 [TCP:4]。
TCP 应该 (SHOULD) 在每个SYN段中发送MSS(最大段大小)选项,当其接收MSS不同于默认值536时,并且 可以 (MAY) 始终发送它。
如果在连接建立时未接收到MSS选项,TCP 必须 (MUST) 假定默认发送MSS为536(576-40)[TCP:4]。
TCP实际发送的段的最大大小,"有效发送MSS",必须 (MUST) 是发送MSS(反映远程主机的可用重组缓冲区大小)和IP层允许的最大大小中的较小者:
Eff.snd.MSS = min(SendMSS+20, MMS_S) - TCPhdrsize - IPoptionsize
其中:
- SendMSS 是从远程主机接收的MSS值,或者如果未接收到MSS选项则为默认值536。
- MMS_S 是TCP可以发送的传输层消息的最大大小。
- TCPhdrsize 是TCP头的大小; 这通常是20,但如果要发送TCP选项,可能会更大。
- IPoptionsize 是TCP将随当前消息传递到IP层的任何IP选项的大小。
在MSS选项中发送的MSS值必须小于或等于:
MMS_R - 20
其中 MMS_R 是可以接收(和重组)的传输层消息的最大大小。TCP从IP层获取MMS_R和MMS_S; 参见第3.4节中的通用调用GET_MAXSIZES。
讨论 (DISCUSSION):
TCP段大小的选择对性能有很强的影响。较大的段通过分摊更多数据字节的头大小和每数据报处理开销来提高吞吐量; 然而,如果数据包太大以至于导致IP分片,如果任何片段丢失,效率会急剧下降 [IP:9]。
一些TCP实现仅在目标主机位于非连接网络上时才发送MSS选项。然而,通常TCP层可能没有适当的信息来做出这个决定,因此最好将确定互联网路径的合适MTU的任务留给IP层。因此,我们建议TCP始终发送该选项(如果不是536),并且IP层按照3.3.3和3.4中的规定确定MMS_R。然后,提议的IP层机制来测量MTU将在不更改TCP的情况下修改IP层。
4.2.2.7 TCP校验和 (TCP Checksum): RFC-793 第3.1节
与UDP校验和不同(参见第4.1.3.4节),TCP校验和永远不是可选的。发送方 必须 (MUST) 生成它,接收方 必须 (MUST) 检查它。
4.2.2.8 TCP连接状态图 (TCP Connection State Diagram): RFC-793 第3.2节,第23页
此图存在几个问题:
(a) 从SYN-SENT到SYN-RCVD的箭头应该标记为"snd SYN,ACK",以与第68页的文本和图8一致。
(b) 可能有一个从SYN-RCVD状态到LISTEN状态的箭头,条件是在被动打开后接收到RST(参见文本第70页)。
(c) 可以直接从FIN-WAIT-1到TIME-WAIT状态(参见规范第75页)。
4.2.2.9 初始序列号选择 (Initial Sequence Number Selection): RFC-793 第3.3节,第27页
TCP 必须 (MUST) 使用指定的时钟驱动的初始序列号选择。
4.2.2.10 同时打开尝试 (Simultaneous Open Attempts): RFC-793 第3.4节
图8中有一个错误:第7行的数据包应该与第5行的数据包相同。
TCP 必须 (MUST) 支持同时打开尝试。
讨论 (DISCUSSION):
有时让实现者感到惊讶的是,如果两个应用程序尝试同时连接到对方,只会生成一个连接而不是两个。这是一个有意的设计决定; 不要试图"修复"它。
4.2.2.11 从旧的重复SYN恢复 (Recovery from Old Duplicate SYN): RFC-793 第3.4节,第33页
请注意,TCP实现 必须 (MUST) 跟踪连接是作为被动OPEN还是主动OPEN的结果达到SYN_RCVD状态的。
4.2.2.12 RST段 (RST Segment): RFC-793 第3.4节
TCP 应该 (SHOULD) 允许接收到的RST段包含数据。
讨论 (DISCUSSION):
已经有人建议RST段可以包含编码和解释RST原因的ASCII文本。尚未为此类数据建立标准。
4.2.2.13 关闭连接 (Closing a Connection): RFC-793 第3.5节
TCP连接可能以两种方式终止:(1) 使用FIN握手的正常TCP关闭序列,以及 (2) "中止",其中发送一个或多个RST段并立即丢弃连接状态。如果TCP连接由远程站点关闭,则 必须 (MUST) 通知本地应用程序它是正常关闭还是被中止。
正常的TCP关闭序列可靠地在两个方向上传递缓冲的数据。由于TCP连接的两个方向是独立关闭的,因此连接可能处于"半关闭"状态,即仅在一个方向上关闭,并且允许主机在半关闭连接上继续在打开的方向上发送数据。
主机 可以 (MAY) 实现"半双工"TCP关闭序列,因此调用了CLOSE的应用程序无法继续从连接读取数据。如果这样的主机在TCP中仍有待处理的接收数据时发出CLOSE调用,或者如果在调用CLOSE后接收到新数据,其TCP 应该 (SHOULD) 发送RST以显示数据已丢失。
当主动关闭连接时,它 必须 (MUST) 在TIME-WAIT状态停留2×MSL(最大段生存期)时间。但是,如果它满足以下条件,它 可以 (MAY) 接受来自远程TCP的新SYN直接从TIME-WAIT状态重新打开连接:
(1) 为新连接分配的初始序列号大于它在先前连接化身上使用的最大序列号,并且
(2) 如果SYN原来是旧的重复,则返回到TIME-WAIT状态。
讨论 (DISCUSSION):
TCP的全双工数据保留关闭是ISO传输协议TP4中不包括的功能。
一些系统没有实现半关闭连接,大概是因为它们不适合其特定操作系统的I/O模型。在这些系统上,一旦应用程序调用了CLOSE,它就不能再从连接读取输入数据; 这被称为"半双工"TCP关闭序列。
TCP的优雅关闭算法要求连接状态在连接的(至少)一端保持定义2×MSL的超时期间,即4分钟。在此期间,定义连接的(远程套接字,本地套接字)对是忙碌的,不能重用。为了缩短给定端口对被占用的时间,一些TCP允许在TIME-WAIT状态下接受新的SYN。
4.2.2.14 数据通信 (Data Communication): RFC-793 第3.7节,第40页
自RFC-793编写以来,已经对TCP算法进行了广泛的工作以实现高效的数据通信。本文档的后续部分描述了所需和推荐的TCP算法,以确定何时发送数据(第4.2.3.4节)、何时发送确认(第4.2.3.2节)以及何时更新窗口(第4.2.3.3节)。
讨论 (DISCUSSION):
一个重要的性能问题是"糊涂窗口综合症"或"SWS" [TCP:5],这是一种稳定的小增量窗口移动模式,导致TCP性能极差。下面描述了避免SWS的算法,包括发送端(第4.2.3.4节)和接收端(第4.2.3.3节)。
简而言之,SWS是由接收方每当有任何新的缓冲区空间可用于接收数据时就推进右窗口边缘,以及发送方使用任何增量窗口(无论多小)来发送更多数据 [TCP:5] 所引起的。结果可能是发送微小数据段的稳定模式,即使发送方和接收方都有用于连接的大总缓冲区空间。SWS只能在传输大量数据期间发生; 如果连接进入静止状态,问题将消失。它是由窗口管理的典型直接实现引起的,但下面给出的发送方和接收方算法将避免它。
另一个重要的TCP性能问题是,某些应用程序(尤其是到字符一次主机的远程登录)倾向于发送单字节数据段流。为了避免死锁,来自此类应用程序的每个TCP SEND调用都必须被"推送",要么由应用程序显式推送,要么由TCP隐式推送。结果可能是TCP段流,每个段包含一个数据字节,这使得互联网的使用效率非常低,并导致互联网拥塞。第4.2.3.4节中描述的Nagle算法为这个问题提供了一个简单有效的解决方案。它确实具有在Telnet连接上聚集字符的效果; 这最初可能会让习惯于单字符回显的用户感到惊讶,但这种聚集对于网络和用户响应时间都是有益的。
用户接受没有成为问题。
注意,Nagle算法和发送SWS避免算法在改善性能方面起着互补的作用。Nagle算法在数据以小增量增加时阻止发送微小段,而SWS避免算法阻止由于右窗口边缘以小增量推进而导致的小段。
粗心的实现可能会为每个接收到的数据段发送两个或更多确认段。例如,假设接收方立即确认每个数据段。当应用程序随后消耗数据并再次增加可用的接收缓冲区空间时,接收方可能会发送第二个确认段以更新发送方的窗口。极端情况发生在使用Telnet协议进行远程登录服务的TCP连接上的单字符段。已经观察到一些实现,其中每个传入的1字符段生成三个返回段:(1) 确认,(2) 窗口增加一个字节,以及 (3) 回显的字符。
4.2.2.15 重传超时 (Retransmission Timeout): RFC-793 第3.7节,第41页
RFC-793中建议的用于计算重传超时的算法现在已知是不充分的; 参见下面的第4.2.3.1节。
Jacobson [TCP:7] 最近关于互联网拥塞和TCP重传稳定性的工作产生了一种结合"慢启动"和"拥塞避免"的传输算法。TCP 必须 (MUST) 实现此算法。
如果重传的数据包与原始数据包相同(这不仅意味着数据边界没有改变,而且还意味着头的窗口和确认字段也没有改变),则 可以 (MAY) 使用相同的IP标识字段(参见第3.2.1.5节)。
实现 (IMPLEMENTATION):
一些TCP实现者选择"分组化"数据流,即在最初发送段时选择段边界,并将这些段排队在"重传队列"中,直到它们被确认。另一种设计(可能更简单)是推迟分组化,直到每次传输或重传数据时,因此不会有段重传队列。
在具有段重传队列的实现中,当第一次重传超时发生时,通过重新分组等待确认的段可以增强TCP性能。也就是说,适合的未完成段将组合成一个最大大小的段,使用新的IP标识值。然后TCP将保留此组合段在重传队列中,直到它被确认。但是,如果重传队列中的前两个段总计超过一个最大大小的段,TCP将仅使用原始IP标识字段重传第一个段。
4.2.2.16 管理窗口 (Managing the Window): RFC-793 第3.7节,第41页
TCP接收方 不应该 (SHOULD NOT) 收缩窗口,即将右窗口边缘向左移动。但是,发送TCP 必须 (MUST) 对窗口收缩具有鲁棒性,这可能会导致"可用窗口"(参见第4.2.3.4节)变为负数。
如果发生这种情况,发送方 不应该 (SHOULD NOT) 发送新数据,但 应该 (SHOULD) 正常重传SND.UNA和SND.UNA+SND.WND之间的旧未确认数据。发送方 可以 (MAY) 也重传超出SND.UNA+SND.WND的旧数据,但 不应该 (SHOULD NOT) 因右窗口边缘之外的数据未被确认而超时断开连接。如果窗口收缩到零,TCP 必须 (MUST) 以标准方式探测它(参见下一节)。
讨论 (DISCUSSION):
如果在数据已发送到更大窗口后窗口从右侧收缩,许多TCP实现会变得混乱。注意,TCP有一个启发式方法来选择最新的窗口更新,尽管可能存在数据报重新排序; 因此,如果序列号和确认号都没有增加,它可能会忽略窗口小于先前提供的窗口的窗口更新。
4.2.2.17 探测零窗口 (Probing Zero Windows): RFC-793 第3.7节,第42页
必须 (MUST) 支持对零(提供的)窗口的探测。
TCP 可以 (MAY) 无限期地保持其提供的接收窗口关闭。只要接收TCP继续响应探测段发送确认,发送TCP 必须 (MUST) 允许连接保持打开。
讨论 (DISCUSSION):
记住不包含数据的ACK(确认)段不是由TCP可靠传输的,这一点极其重要。如果不支持零窗口探测,当重新打开窗口的ACK段丢失时,连接可能会永远挂起。
当接收应用程序停止从其TCP获取数据时,通常会出现打开零窗口的延迟。例如,考虑一个打印机守护程序应用程序,因为打印机用完纸而停止。
传输主机 应该 (SHOULD) 在零窗口已存在重传超时期间时(参见第4.2.2.15节)发送第一个零窗口探测,并且 应该 (SHOULD) 以指数方式增加连续探测之间的间隔。
讨论 (DISCUSSION):
如果零窗口条件是由于包含打开窗口更新的ACK段丢失造成的,此过程可以最小化延迟。建议使用指数退避,可能有一些此处未指定的最大间隔。此过程类似于重传算法的过程,在实现中可能可以将两个过程结合起来。
4.2.2.18 被动OPEN调用 (Passive OPEN Calls): RFC-793 第3.8节
每个被动OPEN调用要么在LISTEN状态下创建一个新的连接记录,要么返回错误; 它 必须不 (MUST NOT) 影响任何先前创建的连接记录。
支持多个并发用户的TCP 必须 (MUST) 提供一个OPEN调用,该调用在功能上允许应用程序在与相同本地端口的连接块处于SYN-SENT或SYN-RECEIVED状态时在该端口上LISTEN。
讨论 (DISCUSSION):
一些应用程序(例如,SMTP服务器)可能需要大约同时处理多个连接尝试。通过给应用程序一些在较早的连接尝试正在进行三次握手的同时侦听新连接的方法,可以降低连接尝试失败的概率。
实现 (IMPLEMENTATION):
并发打开的可接受实现可能允许多个被动OPEN调用,或者它们可能允许从单个被动OPEN调用"克隆"LISTEN状态连接。
4.2.2.19 生存时间 (Time to Live): RFC-793 第3.9节,第52页
RFC-793指定TCP请求IP层发送TTL = 60的TCP段。这已过时; 用于发送TCP段的TTL值 必须 (MUST) 是可配置的。有关讨论,请参见第3.2.1.7节。
4.2.2.20 事件处理 (Event Processing): RFC-793 第3.9节
虽然不是严格要求的,TCP 应该 (SHOULD) 能够排队乱序TCP段。将第70页第一段最后一句中的"may"改为"should"。
讨论 (DISCUSSION):
由于缓冲区空间有限,一些小型主机实现省略了段排队。可以预期,这种省略会对TCP吞吐量产生不利影响,因为丢失单个段会导致所有后续段看起来"乱序"。
通常,接收段的处理 必须 (MUST) 实现为尽可能聚合ACK段。例如,如果TCP正在处理一系列排队的段,它 必须 (MUST) 在发送任何ACK段之前处理它们全部。
以下是RFC-793事件处理部分的一些详细的错误更正和注释。
(a) CLOSE调用,CLOSE-WAIT状态,第61页:进入LAST-ACK状态,而不是CLOSING。
(b) LISTEN状态,检查SYN(第65、66页):对于带有SYN位的段,如果安全/区间或优先级对该段错误,则发送重置。文本中显示的重置形式错误; 它应该是:
<SEQ=0><ACK=SEG.SEQ+SEG.LEN><CTL=RST,ACK>
(c) SYN-SENT状态,检查SYN,第68页:当连接进入ESTABLISHED状态时,必须设置以下变量:
`SND.WND <- SEG.WND`
`SND.WL1 <- SEG.SEQ`
`SND.WL2 <- SEG.ACK`
(d) 检查安全性和优先级,第71页:"ESTABLISHED STATE"的第一个标题实际上应该是除SYN-RECEIVED之外的所有状态的列表:ESTABLISHED、FIN-WAIT-1、FIN-WAIT-2、CLOSE-WAIT、CLOSING、LAST-ACK和TIME-WAIT。
(e) 检查SYN位,第71页:"在SYN-RECEIVED状态下,如果连接是通过被动OPEN启动的,则将此连接返回到LISTEN状态并返回。否则..."。
(f) 检查ACK字段,SYN-RECEIVED状态,第72页:当连接进入ESTABLISHED状态时,必须设置(c)中列出的变量。
(g) 检查ACK字段,ESTABLISHED状态,第72页:如果SEG.ACK =< SND.UNA(省略了=),则ACK是重复的。类似地,如果:SND.UNA =< SEG.ACK =< SND.NXT,则应更新窗口。
(h) USER TIMEOUT,第77页:
最好通知应用程序超时,而不是让TCP强制关闭连接。但是,另见第4.2.3.5节。
4.2.2.21 确认排队的段 (Acknowledging Queued Segments): RFC-793 第3.9节
当到达在窗口内但不在左窗口边缘的有效段时,TCP 可以 (MAY) 发送确认RCV.NXT的ACK段。
讨论 (DISCUSSION):
RFC-793(参见第74页)对于当接收到乱序段时,即当SEG.SEQ不等于RCV.NXT时,是否应该发送ACK段是模糊的。
确认乱序段的一个原因可能是支持称为"快速重传"的实验算法。使用此算法,发送方使用"冗余"ACK来推断在重传计时器到期之前已经丢失了一个段。它计算使用相同SEG.ACK值和相同右窗口边缘接收到ACK的次数。如果接收到超过阈值数量的此类ACK,则假定包含从SEG.ACK开始的八位字节的段已丢失并重传,而无需等待超时。选择阈值以补偿互联网中最大可能的段重新排序。尚没有足够的快速重传算法经验来确定它有多有用。
4.2.3 具体问题 (SPECIFIC ISSUES)
4.2.3.1 重传超时计算 (Retransmission Timeout Calculation)
主机TCP 必须 (MUST) 实现Karn算法和Jacobson算法来计算重传超时("RTO")。
-
Jacobson算法用于计算平滑往返时间("RTT")包含方差的简单度量 [TCP:7]。
-
Karn算法用于选择RTT测量,确保模糊的往返时间不会破坏平滑往返时间的计算 [TCP:6]。
此实现还 必须 (MUST) 为同一段的连续RTO值包含"指数退避"。SYN段的重传 应该 (SHOULD) 使用与数据段相同的算法。
讨论 (DISCUSSION):
RFC-793中指定的RTO计算存在两个已知问题。首先,当存在重传时,准确测量RTT是困难的。其次,计算平滑往返时间的算法是不充分的 [TCP:7],因为它错误地假设RTT值的方差会很小且恒定。这些问题分别由Karn算法和Jacobson算法解决。
使用这些改进所产生的性能提升从显著到戏剧性不等。Jacobson算法用于结合测量的RTT方差在低速链路上尤其重要,其中数据包大小的自然变化会导致RTT的大变化。一家供应商发现,在9.6kb线路上实现Jacobson方差算法后,链路利用率从10%提高到90%。
应该 (SHOULD) 使用以下值来初始化新连接的估计参数:
(a) RTT = 0秒。
(b) RTO = 3秒。(平滑方差要初始化为将导致此RTO的值)。
众所周知,RTO上的推荐上限和下限在大型互联网上是不充分的。下限 应该 (SHOULD) 以秒的分数为单位测量(以适应高速LAN),上限应该是2×MSL,即240秒。
讨论 (DISCUSSION):
经验表明这些初始化值是合理的,并且无论如何Karn和Jacobson算法使TCP行为对初始参数选择相当不敏感。
4.2.3.2 何时发送ACK段 (When to Send an ACK Segment)
正在接收TCP数据段流的主机可以通过发送少于每个接收到的数据段一个ACK(确认)段来提高互联网和主机的效率; 这被称为"延迟ACK" [TCP:5]。
TCP 应该 (SHOULD) 实现延迟ACK,但ACK不应该过度延迟; 特别是,延迟 必须 (MUST) 少于0.5秒,并且在完整大小段的流中,应该 (SHOULD) 至少每两个段有一个ACK。
讨论 (DISCUSSION):
延迟ACK给应用程序一个更新窗口的机会,也许还可以发送立即响应。特别是,在字符模式远程登录的情况下,延迟ACK可以将服务器发送的段数减少3倍(ACK、窗口更新和回显字符都组合在一个段中)。
此外,在一些大型多用户主机上,延迟ACK可以通过减少要处理的数据包总数来大大减少协议处理开销 [TCP:5]。但是,ACK的过度延迟会扰乱往返计时和数据包"时钟"算法 [TCP:7]。
4.2.3.3 何时发送窗口更新 (When to Send a Window Update)
TCP 必须 (MUST) 在接收方包含SWS避免算法 [TCP:5]。
实现 (IMPLEMENTATION):
接收方的SWS避免算法确定何时可以推进右窗口边缘; 这通常称为"更新窗口"。此算法与延迟ACK算法(参见第4.2.3.2节)结合,以确定何时真正向接收方发送包含当前窗口的ACK段。我们使用RFC-793的符号; 请参见该文档中的图4和5。
接收方SWS的解决方案是避免以小增量推进右窗口边缘RCV.NXT+RCV.WND,即使从网络中以小段接收数据。
假设总接收缓冲区空间是RCV.BUFF。在任何给定时刻,此总数的RCV.USER八位字节可能与已接收和确认但用户进程尚未消耗的数据绑定。当连接静止时,RCV.WND = RCV.BUFF且RCV.USER = 0。
当数据到达并被确认时保持右窗口边缘固定,要求接收方提供少于其完整缓冲区空间的空间,即接收方必须指定一个RCV.WND,使RCV.NXT+RCV.WND在RCV.NXT增加时保持恒定。因此,总缓冲区空间RCV.BUFF通常分为三部分:
|<------- RCV.BUFF ---------------->|
1 2 3
----|---------|------------------|------|----
RCV.NXT ^
(Fixed)
1 - RCV.USER = 已接收但尚未消耗的数据;
2 - RCV.WND = 向发送方通告的空间;
3 - Reduction = 可用但尚未通告的空间。
建议接收方的SWS避免算法是保持RCV.NXT+RCV.WND固定,直到减少满足:
RCV.BUFF - RCV.USER - RCV.WND >= min(Fr * RCV.BUFF, Eff.snd.MSS)
其中Fr是一个分数,其推荐值为1/2,Eff.snd.MSS是在第4.2.2.6节中定义的有效发送MSS。当满足不等式时,RCV.WND设置为RCV.BUFF-RCV.USER。
请注意,此算法的一般效果是以Eff.snd.MSS的增量推进RCV.WND(对于现实的接收缓冲区:Eff.snd.MSS < RCV.BUFF/2)。还要注意,接收方必须使用自己的Eff.snd.MSS,假设它与发送方的相同。
4.2.3.4 何时发送数据 (When to Send Data)
TCP 必须 (MUST) 在发送方包含SWS避免算法。
TCP 应该 (SHOULD) 实现Nagle算法 [TCP:9] 来合并短段。但是,必须 (MUST) 有一种方法让应用程序在单个连接上禁用Nagle算法。在所有情况下,发送数据也受到慢启动算法施加的限制(第4.2.2.15节)。
讨论 (DISCUSSION):
Nagle算法通常如下:
如果存在未确认的数据(即,SND.NXT > SND.UNA),则发送TCP缓冲所有用户数据(无论PSH位如何),直到未完成的数据已被确认或直到TCP可以发送完整大小的段(Eff.snd.MSS字节; 参见第4.2.2.6节)。
一些应用程序(例如,实时显示窗口更新)要求关闭Nagle算法,以便可以以最大速率流式传输小数据段。
实现 (IMPLEMENTATION):
发送方的SWS避免算法比接收方的更困难,因为发送方不(直接)知道接收方的总缓冲区空间RCV.BUFF。已发现效果很好的方法是让发送方计算Max(SND.WND),即它在连接上看到的最大发送窗口,并使用此值作为RCV.BUFF的估计。不幸的是,这只能是一个估计; 接收方可能随时减小RCV.BUFF的大小。为了避免由此产生的死锁,必须有一个超时来强制传输数据,覆盖SWS避免算法。实际上,这种超时应该很少发生。
"可用窗口" [TCP:5] 是:
U = SND.UNA + SND.WND - SND.NXT
即,提供的窗口减去已发送但未确认的数据量。如果D是在发送TCP中排队但尚未发送的数据量,则建议使用以下一组规则。
发送数据:
(1) 如果可以发送最大大小的段,即如果:
min(D,U) >= Eff.snd.MSS;
(2) 或者如果数据被推送且现在可以发送所有排队的数据,即如果:
[SND.NXT = SND.UNA and] PUSHED and D <= U
(括号内的条件由Nagle算法施加);
(3) 或者如果可以发送至少最大窗口的一部分Fs,即如果:
[SND.NXT = SND.UNA and]
min(D,U) >= Fs * Max(SND.WND);
(4) 或者如果数据被PUSH且发生覆盖超时。
这里Fs是一个分数,其推荐值为1/2。覆盖超时应在0.1 - 1.0秒范围内。将此计时器与用于探测零窗口的计时器结合起来可能很方便(第4.2.2.17节)。
最后,请注意,刚刚指定的SWS避免算法将用于代替 [TCP:5] 中包含的发送方端算法。
4.2.3.5 TCP连接失败 (TCP Connection Failures)
TCP对同一段的过度重传表明远程主机或互联网路径的某些故障。此故障可能是短期或长期的。必须 (MUST) 使用以下过程来处理数据段的过度重传 [IP:11]:
(a) 有两个阈值R1和R2,用于测量同一段已发生的重传量。R1和R2可能以时间单位或重传计数来测量。
(b) 当同一段的传输次数达到或超过阈值R1时,将负面建议(参见第3.3.1.4节)传递给IP层,以触发死网关诊断。
(c) 当同一段的传输次数达到大于R1的阈值R2时,关闭连接。
(d) 应用程序 必须 (MUST) 能够为特定连接设置R2的值。例如,交互式应用程序可能将R2设置为"无穷大",让用户控制何时断开连接。
(e) 当达到R1并在R2之前,TCP 应该 (SHOULD) 通知应用程序传递问题(除非应用程序已禁用此类信息; 参见第4.2.4.1节)。例如,这将允许远程登录(用户Telnet)应用程序通知用户。
R1的值 应该 (SHOULD) 对应于当前RTO下至少3次重传。R2的值 应该 (SHOULD) 对应于至少100秒。
尝试打开TCP连接可能因SYN段的过度重传或通过接收RST段或ICMP端口不可达而失败。必须 (MUST) 以刚才描述的数据重传的一般方式处理SYN重传,包括通知应用层。
但是,SYN和数据段的R1和R2值可能不同。特别是,SYN段的R2 必须 (MUST) 设置得足够大,以便为段提供至少3分钟的重传。当然,应用程序可以更早地关闭连接(即,放弃打开尝试)。
讨论 (DISCUSSION):
一些互联网路径具有显著的设置时间,SYN段可能会丢失。当打开第一个连接时可能会发生故障,例如跨高延迟卫星链路触发拨号,同时由于后续SYN段将找到准备好的拨号系统而成功。此类路径的数量将来可能会增加。
4.2.3.6 TCP保持活动 (TCP Keep-Alives)
实现者 可以 (MAY) 在其TCP实现中包含"保持活动",尽管这种做法并未被普遍接受。如果包含保持活动,应用程序 必须 (MUST) 能够为每个TCP连接打开或关闭它们,并且它们 必须 (MUST) 默认为关闭。
保持活动数据包 必须 (MUST) 仅在连接在一个间隔内未接收到数据或确认数据包时发送。此间隔 必须 (MUST) 是可配置的,并且 必须 (MUST) 默认为不少于两小时。
记住不包含数据的ACK段不是由TCP可靠传输的,这一点极其重要。因此,如果实现了保持活动机制,它 必须不 (MUST NOT) 将未能响应任何特定探测解释为死连接。
实现 应该 (SHOULD) 发送不包含数据的保持活动段; 但是,它 可以 (MAY) 配置为发送包含一个垃圾八位字节的保持活动段,以与错误的TCP实现兼容。
讨论 (DISCUSSION):
"保持活动"机制在连接空闲时定期探测连接的另一端,即使没有要发送的数据。TCP规范不包括保持活动机制,因为它可能:(1) 在瞬态互联网故障期间导致完全正常的连接中断; (2) 消耗不必要的带宽("如果没有人使用连接,谁在乎它是否仍然良好?"); 以及 (3) 为按数据包收费的互联网路径花费金钱。
然而,一些TCP实现包含了保持活动机制。为了确认空闲连接仍然处于活动状态,这些实现发送设计用于从对等TCP引发响应的探测段。这样的段通常包含SEG.SEQ = SND.NXT-1,并且可能包含或不包含一个垃圾八位字节的数据。请注意,在安静连接上SND.NXT = RCV.NXT,因此此SEG.SEQ将在窗口之外。因此,探测导致接收方返回确认段,确认连接仍然活着。如果对等方由于网络分区或崩溃而断开连接,它将用RST而不是确认段响应。
不幸的是,一些行为不端的TCP实现未能响应SEG.SEQ = SND.NXT-1的段,除非该段包含数据。或者,实现可以确定对等方是否正确响应了没有垃圾数据八位字节的保持活动数据包。
TCP保持活动机制应仅在可能会无限期挂起并在客户端崩溃或在网络故障期间中止连接时不必要地消耗资源的服务器应用程序中调用。
4.2.3.7 TCP多宿主 (TCP Multihoming)
如果多宿主主机上的应用程序在主动打开TCP连接时未指定本地IP地址,则TCP 必须 (MUST) 在发送(第一个)SYN之前要求IP层选择本地IP地址。参见第3.4节中的函数GET_SRCADDR()。
在所有其他时间,先前的段要么已在此连接上发送要么已接收,TCP 必须 (MUST) 使用在那些先前段中使用的相同本地地址。
4.2.3.8 IP选项 (IP Options)
当接收到的选项从IP层传递到TCP时,TCP 必须 (MUST) 忽略它不理解的选项。
TCP 可以 (MAY) 支持时间戳和记录路由选项。
应用程序 必须 (MUST) 能够在主动打开TCP连接时指定源路由,并且这 必须 (MUST) 优先于在数据报中接收到的源路由。
当TCP连接被被动OPEN并且数据包到达时带有完整的IP源路由选项(包含返回路由),TCP 必须 (MUST) 保存返回路由并将其用于在此连接上发送的所有段。如果在稍后的段中到达不同的源路由,则稍后的定义 应该 (SHOULD) 覆盖较早的定义。
4.2.3.9 ICMP消息 (ICMP Messages)
TCP 必须 (MUST) 对从IP层传递的ICMP错误消息采取行动,将其定向到创建错误的连接。必要的解复用信息可以在ICMP消息中包含的IP头中找到。
-
源抑制 (Source Quench)
TCP 必须 (MUST) 通过减慢连接上的传输来响应源抑制。建议 (RECOMMENDED) 的过程是让源抑制触发"慢启动",就像发生了重传超时一样。
-
目的地不可达 (Destination Unreachable) -- 代码0、1、5
由于这些不可达消息表示软错误条件,TCP 必须不 (MUST NOT) 中止连接,并且它 应该 (SHOULD) 将信息提供给应用程序。
讨论 (DISCUSSION):
TCP可以通过向上调用ERROR_REPORT例程直接向应用层报告软错误条件,或者它可以仅记录消息并仅在TCP连接超时时和如果超时时向应用程序报告。
-
目的地不可达 (Destination Unreachable) -- 代码2-4
这些是硬错误条件,因此TCP 应该 (SHOULD) 中止连接。
-
超时 (Time Exceeded) -- 代码0、1
这应该以与目的地不可达代码0、1、5相同的方式处理(见上文)。
-
参数问题 (Parameter Problem)
这应该以与目的地不可达代码0、1、5相同的方式处理(见上文)。
4.2.3.10 远程地址验证 (Remote Address Validation)
TCP实现 必须 (MUST) 拒绝针对无效远程IP地址(例如,广播或组播地址)的本地OPEN调用作为错误。
具有无效源地址的传入SYN必须由TCP或IP层忽略(参见第3.2.1.3节)。
TCP实现 必须 (MUST) 静默丢弃寻址到广播或组播地址的传入SYN段。
4.2.3.11 TCP流量模式 (TCP Traffic Patterns)
实现 (IMPLEMENTATION):
TCP协议规范 [TCP:1] 给予实现者很大的自由来设计控制连接上消息流的算法 -- 分组化、管理窗口、发送确认等。这些设计决策是困难的,因为TCP必须适应广泛的流量模式。经验表明,TCP实现者需要在两种极端流量模式上验证设计:
-
单字符段 (Single-character Segments)
即使发送方正在使用Nagle算法,当TCP连接跨低延迟LAN承载远程登录流量时,接收方通常会得到单字符段流。如果远程终端回显模式有效,接收方的系统通常会在接收到每个字符时回显它。
-
批量传输 (Bulk Transfer)
当TCP用于批量传输时,数据流应(几乎)完全由有效MSS大小的段组成。尽管TCP使用具有字节(八位字节)粒度的序列号空间,但在批量传输模式下,其操作应该就像TCP使用仅计数段的序列空间一样。
经验还表明,单个TCP可以有效且高效地处理这两个极端。
验证新TCP实现的最重要工具是数据包跟踪程序。有大量经验表明,使用其他TCP实现跟踪各种流量模式并仔细研究结果的重要性。
4.2.3.12 效率 (Efficiency)
实现 (IMPLEMENTATION):
广泛的经验导致了以下有关TCP高效实现的建议:
(a) 不要复制数据 (Don't Copy Data)
在批量数据传输中,主要的CPU密集型任务是将数据从一个地方复制到另一个地方以及对数据进行校验和。最小化TCP数据的副本数量至关重要。由于最终的速度限制可能是跨内存总线获取数据,因此将复制与校验和结合起来,用单个内存获取完成两者可能是有用的。
(b) 手工编写校验和例程 (Hand-Craft the Checksum Routine)
良好的TCP校验和例程通常比定义的简单直接实现快两到五倍。通常需要并建议进行极大的谨慎和巧妙的编码,以使校验和代码"极快"。参见 [TCP:10]。
(c) 为常见情况编码 (Code for the Common Case)
TCP协议处理可能很复杂,但对于大多数段,只需要做出几个简单的决定。通过编码主线以最小化最常见情况下的决策数量,可以大大加速每段处理。
4.2.4 TCP/应用层接口 (TCP/APPLICATION LAYER INTERFACE)
4.2.4.1 异步报告 (Asynchronous Reports)
必须 (MUST) 有一种机制将软TCP错误条件报告给应用程序。一般而言,我们假设这采取应用程序提供的ERROR_REPORT例程的形式,该例程可以从传输层异步上调用 [INTRO:7]:
ERROR_REPORT(local connection name, reason, subreason)
此处未指定reason和subreason参数的精确编码。但是,异步报告给应用程序的条件 必须 (MUST) 包括:
- ICMP错误消息到达(参见4.2.3.9)
- 过度重传(参见4.2.3.5)
- 紧急指针推进(参见4.2.2.4)。
但是,不想接收此类ERROR_REPORT调用的应用程序 应该 (SHOULD) 能够有效地禁用这些调用。
讨论 (DISCUSSION):
这些错误报告通常反映软错误,许多应用程序可以无害地忽略它们。有人建议这些错误报告调用应默认为"禁用",但这不是必需的。
4.2.4.2 服务类型 (Type-of-Service)
应用层 必须 (MUST) 能够为在连接上发送的段指定服务类型(TOS)。不是必需的,但应用程序 应该 (SHOULD) 能够在连接生存期内更改TOS。当TCP在连接上发送段时,它 应该 (SHOULD) 将当前TOS值不加更改地传递给IP层。
TOS将在连接的每个方向上独立指定,因此接收方应用程序将指定用于ACK段的TOS。
TCP 可以 (MAY) 将最近接收到的TOS向上传递给应用程序。
讨论 (DISCUSSION):
某些应用程序(例如,SMTP)在连接的生存期内改变其通信的性质,因此希望更改TOS规范。
还要注意,RFC-793中指定的OPEN调用包括一个参数("options"),调用者可以在其中指定IP选项,例如源路由、记录路由或时间戳。
4.2.4.3 刷新调用 (Flush Call)
一些TCP实现包含了FLUSH调用,它将清空TCP发送队列中用户已发出SEND调用但仍在当前发送窗口右侧的任何数据。也就是说,它尽可能多地刷新排队的发送数据而不丢失序列号同步。这对于实现Telnet的"中止输出"功能很有用。
4.2.4.4 多宿主 (Multihoming)
RFC-793第2.7和3.8节中概述的用户接口需要针对多宿主进行扩展。OPEN调用 必须 (MUST) 有一个可选参数:
OPEN( ... [local IP address,] ... )
以允许指定本地IP地址。
讨论 (DISCUSSION):
一些基于TCP的应用程序需要指定用于打开特定连接的本地IP地址; FTP就是一个例子。
实现 (IMPLEMENTATION):
具有指定"本地IP地址"参数的被动OPEN调用将等待到该地址的传入连接请求。如果参数未指定,被动OPEN将等待到任何本地IP地址的传入连接请求,然后将连接的本地IP地址绑定到所使用的特定地址。
对于主动OPEN调用,指定的"本地IP地址"参数将用于打开连接。如果参数未指定,网络软件将为连接选择适当的本地IP地址(参见第3.3.4.2节)。
4.2.5 TCP要求摘要 (TCP REQUIREMENTS SUMMARY)
| 功能 | 章节 | 必须 (MUST) | 应该 (SHOULD) | 可以 (MAY) | 不应该 (SHOULD NOT) | 必须不 (MUST NOT) | 注释 |
|---|---|---|---|---|---|---|---|
| Push标志 | |||||||
| 聚合或排队未推送的数据 | 4.2.2.2 | x | |||||
| 发送方合并连续的PSH标志 | 4.2.2.2 | x | |||||
| SEND调用可指定PUSH | 4.2.2.2 | x | |||||
| 如果不能:发送方无限期缓冲 | 4.2.2.2 | x | |||||
| 如果不能:PSH最后一个段 | 4.2.2.2 | x | |||||
| 通知接收ALP有关PSH | 4.2.2.2 | x | 1 | ||||
| 尽可能发送最大大小段 | 4.2.2.2 | x | |||||
| 窗口 | |||||||
| 视为无符号数 | 4.2.2.3 | x | |||||
| 作为32位数处理 | 4.2.2.3 | x | |||||
| 从右侧收缩窗口 | 4.2.2.16 | x | |||||
| 对收缩窗口具有鲁棒性 | 4.2.2.16 | x | |||||
| 接收方窗口无限期关闭 | 4.2.2.17 | x | |||||
| 发送方探测零窗口 | 4.2.2.17 | x | |||||
| RTO后第一次探测 | 4.2.2.17 | x | |||||
| 指数退避 | 4.2.2.17 | x | |||||
| 允许窗口无限期保持零 | 4.2.2.17 | x | |||||
| 发送方对零窗口连接超时 | 4.2.2.17 | x | |||||
| 紧急数据 | |||||||
| 指针指向最后一个八位字节 | 4.2.2.4 | x | |||||
| 任意长度的紧急数据序列 | 4.2.2.4 | x | |||||
| 异步通知ALP紧急数据 | 4.2.2.4 | x | 1 | ||||
| ALP可知道排队的紧急数据量 | 4.2.2.4 | x | 1 | ||||
| TCP选项 | |||||||
| 在任何段中接收TCP选项 | 4.2.2.5 | x | |||||
| 忽略不支持的选项 | 4.2.2.5 | x | |||||
| 处理非法选项长度 | 4.2.2.5 | x | |||||
| 实现发送和接收MSS选项 | 4.2.2.6 | x | |||||
| 除非536否则发送MSS选项 | 4.2.2.6 | x | |||||
| 总是发送MSS选项 | 4.2.2.6 | x | |||||
| 发送MSS默认为536 | 4.2.2.6 | x | |||||
| 计算有效发送段大小 | 4.2.2.6 | x | |||||
| TCP校验和 | |||||||
| 发送方计算校验和 | 4.2.2.7 | x | |||||
| 接收方检查校验和 | 4.2.2.7 | x | |||||
| 使用时钟驱动的ISN选择 | 4.2.2.9 | x | |||||
| 打开连接 | |||||||
| 支持同时打开尝试 | 4.2.2.10 | x | |||||
| SYN-RCVD记住最后状态 | 4.2.2.11 | x | |||||
| 被动打开调用干扰其他 | 4.2.2.18 | x | |||||
| 功能:同端口同时LISTEN | 4.2.2.18 | x | |||||
| 必要时向IP询问SYN源地址 | 4.2.3.7 | x | |||||
| 否则使用连接的本地地址 | 4.2.3.7 | x | |||||
| OPEN到广播/组播IP地址 | 4.2.3.10 | x | |||||
| 静默丢弃到广播/组播地址的段 | 4.2.3.10 | x | |||||
| 关闭连接 | |||||||
| RST可包含数据 | 4.2.2.12 | x | |||||
| 通知应用程序连接中止 | 4.2.2.13 | x | |||||
| 半双工关闭连接 | 4.2.2.13 | x | |||||
| 发送RST指示数据丢失 | 4.2.2.13 | x | |||||
| 在TIME-WAIT状态2×MSL秒 | 4.2.2.13 | x | |||||
| 从TIME-WAIT状态接受SYN | 4.2.2.13 | x | |||||
| 重传 | |||||||
| Jacobson慢启动算法 | 4.2.2.15 | x | |||||
| Jacobson拥塞避免算法 | 4.2.2.15 | x | |||||
| 使用相同IP标识重传 | 4.2.2.15 | x | |||||
| Karn算法 | 4.2.3.1 | x | |||||
| Jacobson的RTO估计算法 | 4.2.3.1 | x | |||||
| 指数退避 | 4.2.3.1 | x | |||||
| SYN RTO计算与数据相同 | 4.2.3.1 | x | |||||
| 推荐的初始值和边界 | 4.2.3.1 | x | |||||
| 生成ACK | |||||||
| 排队乱序段 | 4.2.2.20 | x | |||||
| 发送ACK前处理所有排队段 | 4.2.2.20 | x | |||||
| 为乱序段发送ACK | 4.2.2.21 | x | |||||
| 延迟ACK | 4.2.3.2 | x | |||||
| 延迟 < 0.5秒 | 4.2.3.2 | x | |||||
| 每2个完整大小段ACK | 4.2.3.2 | x | |||||
| 接收方SWS避免算法 | 4.2.3.3 | x | |||||
| 发送数据 | |||||||
| 可配置的TTL | 4.2.2.19 | x | |||||
| 发送方SWS避免算法 | 4.2.3.4 | x | |||||
| Nagle算法 | 4.2.3.4 | x | |||||
| 应用程序可禁用Nagle算法 | 4.2.3.4 | x | |||||
| 连接失败 | |||||||
| R1次重传时向IP发负面建议 | 4.2.3.5 | x | |||||
| R2次重传时关闭连接 | 4.2.3.5 | x | |||||
| ALP可设置R2 | 4.2.3.5 | x | 1 | ||||
通知ALP R1≤重传<R2 | 4.2.3.5 | x | 1 | ||||
| R1、R2的推荐值 | 4.2.3.5 | x | |||||
| SYN使用相同机制 | 4.2.3.5 | x | |||||
| SYN的R2至少3分钟 | 4.2.3.5 | x | |||||
| 发送保持活动数据包 | 4.2.3.6 | x | |||||
| 应用程序可请求 | 4.2.3.6 | x | |||||
| 默认为"关闭" | 4.2.3.6 | x | |||||
| 仅在空闲间隔后发送 | 4.2.3.6 | x | |||||
| 间隔可配置 | 4.2.3.6 | x | |||||
| 默认至少2小时 | 4.2.3.6 | x | |||||
| 容忍丢失的ACK | 4.2.3.6 | x | |||||
| IP选项 | |||||||
| 忽略TCP不理解的选项 | 4.2.3.8 | x | |||||
| 时间戳支持 | 4.2.3.8 | x | |||||
| 记录路由支持 | 4.2.3.8 | x | |||||
| 源路由 | |||||||
| ALP可指定 | 4.2.3.8 | x | 1 | ||||
| 覆盖数据报中的源路由 | 4.2.3.8 | x | |||||
| 从源路由构建返回路由 | 4.2.3.8 | x | |||||
| 后来的源路由覆盖 | 4.2.3.8 | x | |||||
| 从IP接收ICMP消息 | 4.2.3.9 | x | |||||
| 目的地不可达(0,1,5)→通知ALP | 4.2.3.9 | x | |||||
| 目的地不可达(0,1,5)→中止连接 | 4.2.3.9 | x | |||||
| 目的地不可达(2-4)→中止连接 | 4.2.3.9 | x | |||||
| 源抑制→慢启动 | 4.2.3.9 | x | |||||
| 超时→告诉ALP,不中止 | 4.2.3.9 | x | |||||
| 参数问题→告诉ALP,不中止 | 4.2.3.9 | x | |||||
| 地址验证 | |||||||
| 拒绝到无效IP地址的OPEN调用 | 4.2.3.10 | x | |||||
| 拒绝来自无效IP地址的SYN | 4.2.3.10 | x | |||||
| 静默丢弃到广播/组播地址的SYN | 4.2.3.10 | x | |||||
| TCP/ALP接口服务 | |||||||
| 错误报告机制 | 4.2.4.1 | x | |||||
| ALP可禁用错误报告例程 | 4.2.4.1 | x | |||||
| ALP可指定发送的TOS | 4.2.4.2 | x | |||||
| 不变地传递给IP | 4.2.4.2 | x | |||||
| ALP可在连接期间更改TOS | 4.2.4.2 | x | |||||
| 将接收的TOS传递给ALP | 4.2.4.2 | x | |||||
| FLUSH调用 | 4.2.4.3 | x | |||||
| OPEN中的可选本地IP地址参数 | 4.2.4.4 | x |
注释:
(1) "ALP" 表示应用层程序 (Application-Layer Program)。