TCP/IP详解之第18章-TCP连接的建立与终止

知识要点

  • TCP是面向连接的协议,任一方在发送数据之前必须先建立连接。
  • TCP建立连接需要三次握手,分别是:
    • 客户端发送客户端的SYN报文,包括目的端口和初始序号ISN
    • 服务端返回服务器的SYN报文,且确认序号ACK=客户端ISN+1
    • 客户端返回确认序号ACK=服务器ISN+1
  • TCP的SYN报文中的初始序号ISN是随时间而变化的,因此每个连接的ISN都不同。RFC 793指出ISN为32比特的计数器,且每4ms加1,以确保服务端能识别因网络延迟而被重传的SYN报文,避免建立错误的连接。
  • TCP终止连接需要四次握手,原因在于TCP连接是双工的,支持半关闭状态。单一方向连接的关闭各需要一个FIN请求和ACK确认。
  • BSD版的TCP建立连接一个新连接的最长时间限制为75秒,超时后则放弃连接。
  • BSD版的TCP第一次超时时间为6秒左右,第二次超时时间则总是24秒,且精确到小数点后两位。原因在于,BSD版的TCP实现采用了500ms(1个时钟滴答)的定时器,定时器计数器在设置后的第一个时钟滴答(500ms)内任意时刻减1。
  • TCP可通过协商来确定最大报文段长度(MSS),如果协商失败则回退到536字节,即对应的IP数据报长度为576字节。以太网中,MSS值可达1460(1500-20-20),IEEE 802.3中,MSS值可达1452字节。
  • MSL(Maximum Segment Lifetime)表示任何报文段在被丢弃前在网路内的最长时间,RFC 793指出MSL为2分钟,现实中常用值为30秒,1分钟或2分钟。
  • TCP有序释放:发送FIN报文
  • TCP异常释放:发送复位报文段
  • TCP允许双方同时打开,需要4个报文,BSD版的TCP实现都不能正确地支持同时打开。
  • TCP允许双方同时关闭,需要4个报文。
  • TCP服务器需要使用本地地址和远端地址组成的4元组:目的IP地址、目的端口、源IP地址和源端口号来处理多个连接请求。

习题解答

  • 在18.2节,我们说初始序号(ISN)正常情况下由1开始,并且每0.5秒增加64000,每次执行一个主动打开。这意味着ISN的最低三位通常总是001。但是图18-3中,为什么两个方向上ISN中最低三位都是521?

    答:ISN是一个uint32_t的计算器,当ISN大于2^32-1时出现回绕,第一次回绕后的值为8704 = 4294976000(4294912000 + 64000)- 2^32。第二次回绕后的值为17408,以此类推,可知ISN的最低位的数字在0、2、4、6和8之间循环。又因为系统引导时ISN是从1开始,因此ISN的最低位数字是一个奇数。

  • 在图18-15中,我们键入12个字符,看到TCP发送了13个字符。在图18-16中,我们键入了8个字符,但TCP发送了10个字符。两种情况分别是为什么?

    答:在第一种情况下,我们使用了sock程序。 默认情况下,它把Unix的换字符(ASCII码为0x0A)原封不动地进行传输。在第二种情况下,我们使用Telnet客户端,它把Unix的换行符转换成两个ASCII字符,即回车符(ASCII码为0x0D)+换行符。

  • 半打开连接和半关闭连接的区别是什么?

    答:一个半关闭连接是一端已经发送了FIN报文,正在等待另一端的数据或FIN报文。一个半打开连接是一端的连接因系统崩溃等异常终止连接,而另外一端并不知情。

  • 如果启动sock程序作为一个服务端程序,然后终止它(还没有客户进程与它建立连接),我们能立即重新启动这个服务端程序。这意味着它没有经历2MSL等待状态。用状态变迁来解释这一切。

    答:一个连接只有经过了已建立状态(Established)才能进入2MSL等待状态。

  • 在18.6中,我们知道如果一个客户端的某个本地端口处于2MSL等待期间,则不能重新使用同一个本地端口。但如果sock程序作为客户程序连续运行两处,并且连接到daytime服务器上,我们就能重新使用同一个本地端口。另外,对一个仍处于2MSL等待的连接,也能为它创建一个替身。这该如何解释?

    答:daytime服务器在将时间和日期返回给客户端之后,会发送一个FIN报文,即主动关闭TCP连接,这也是为什么sock程序会打印“connection closed by peer.”。此时,客户端相对于处于被动关闭的状态,而服务端处于TIME_WAIT状态。而正如18.6.1中所述,大多数伯克利系统的TCP实现都允许一个新的连接请求仍处于TIME_WAIT状态的连接,只要新的序号大于该连接前一个替身的最后序号。

  • 在18.6节的最后,我们介绍了FIN_WAIT_2状态,提到如果应用程序经过11分钟后实行完全关闭(不是半关闭),许多具体的实现都将一个连接由这个状态转移到CLOSED状态。如果另一端(处于CLOSE_WAIT状态)在发送FIN之前等待12分钟,这一端的TCP将如何响应这个FIN?

    答:由于当前端的状态已转移到CLOSED状态,即TCP连接已经关闭,因此此后到达的FIN报文相对于RST报文。

  • 对于一个电话交谈,哪一方是主动打开,哪一方是被动打开?是否允许同时打开?是否允许同时关闭?

    答:拨号一方为主动打开,接听一方为被动打开,不允许同时打开,但允许同时关闭。

  • 在图18-6中,我们没有见到一个ARP请求或一个ARP应答。显然主机svr4的硬件地址一定在bsdi的ARP高速缓存中。如果这个ARP高速缓存不存在,这个图会有什么变化?

    答:由于ARP高速缓存不存在,所以会先发送ARP请求,而不是SYN报文。

  • 为什么图18-4的服务器不将对客户FIN的ACK与自己的FIN合并,从而将报文段数减少为3个。

    答:TCP是双工的,支持半关闭连接。因此,服务端在收到客户的FIN后返回ACK以关闭客户端到服务端的方向连接,但是并不一定需要关闭服务端到客户端的方向连接。

  • 在图18-16中,RST的序号为什么是26368002?

    答:如果发送RST报文段的一端收到过ACK报文段,那么RST报文段的序号就是最近一个ACK报文段的序号。

  • TCP向链路层查询MTU是否违反分层的规则?

    答:违反。原因在于TCP属于传输层,在传输层和链路层之间还有网络层,MTU查询通常在IP层完成。

  • 假定在图14.16中,每个DNS使用TCP而不是UDP进行查询,试问需要交换多少个报文段?

    答:如果使用TCP,一次查询需要11个分组,分别是3个分组建立连接,1个分组用于查询,1个分组用于确认查询,1个用于响应,1个用于确认响应,4个用于终止连接。如果将查询确认和响应结合在一个报文,则可将分组减小到10个。而如果使用UDP,一次查询只需要2个分组,分别用于查询和响应。

  • 假定MSL为120秒,试问系统能够初始化一个新连接然后进行主动关闭的最大速率是多少?

    答:初始化一个新连接然后主动关闭,即进入TIME_WAIT状态,时长为2MSL。因此,最大速率=TCP端口最大数目(忽略知名端口) / 2MSL = (65536 - 1024) / 240 = 268。

  • 阅读RFC 793,分析处于TIME_WAIT状态的主机收到使其进入此状态的重复的FIN时所发生的情况。

    答:重复的FIN会得到确认,重新开始TIME_WAIT状态,即重新开始2MSL等待。

  • 阅读RFC 793,分析处于TIME_WAIT状态的主机收到一个RST时所发生的情况。

    答:RFC 739中提出的应对措施是在TIME_WAIT状态下忽略RST报文段,RFC 1337中仔细讨论了这个现象。

  • 阅读Host Requirements RFC并找出半双工TCP关闭的定义。

    答:当TCP实现不支持半关闭连接时,一端发送了FIN报文段,则不能再从这个连接中读取数据了。

  • 在图1-8中,我们曾提到到来的TCP报文段可根据其目的端口号进行分用,请问这种说法是否正确?

    答:不正确。一个TCP服务器的端口号可同时建立多个连接,无法仅通过目的端口号来确定那个进程接收了一个连接请求,因此需要使用本地地址和远端地址的4元组来处理传入的多个连接请求。

Comments