第2章 传输层:TCP、UDP和SCTP

2.6  TCP连接的建立和终止

 为帮助大家理解connect、accept和close函数并使用netstat调试TCP应用程序,我们必须了解TCP连接如何建立和终止以及TCP的状态转换图。

 

三路握手

    下述步骤建立一个TCP连接:
    1.服务器必须准备好接受外来的连接。这通过调用socket、bind和listen函数来完成,称为被动打开(passive open)。
  2.客户通过调用connect进行主动打开(active open)。这引起客户TCP发送一个SYN( 表示同步)分节,它告诉服务器客户将在(待建立的)连接中发送的数据的初始序列号。一般情况下SYN分节不携带数据,它只含有一个IP头部、一个TCP头部及可能有的TCP选项。
    3.服务器必须确认客户的SYN,同时自己也得发送一个SYN分节,它含有服务器将在同一连接中发送的数据的初始序列号。服务器以单个分节向客户发送SYN和对客户SYN的ACK(表示确认)。
    4. 客户必须确认服务器的SYN。连接建立过程至少需要交换三个分组,因此称之为TCP的三路握手(threeway handshake)。图2.2中展示了这三个分节。


图2.2TCP的三路握手


    图2.2给出的客户的初始序列号为J,而服务器的初始序列号为K。在ACK里的确认号为发送这个ACK的一端所期待的对端的下一个序列号。因为SYN只占一个字节的序列号空间,所以每一个SYN的ACK中的确认号都是相应的初始序列号加1。类似地,每一个FIN(表示结束)的 ACK中的确认号为FIN的序列号加1。

    建立TCP连接的日常系统类比是电话系统[Nemeth 1997]。socket函数等同于有电话可用。bind用于告诉其他人你的电话号码,让他们可以向你打电话。listen是打开电话振铃,它使你可以听到一个外来的电话。connect要求你知道对方的电话号码并拨打它。accept是被呼叫回电话。从accept返回客户的标识(即客户的IP地址和端口号)类似于让电话机的呼叫者ID 功能部件显示打电话人的电话号码。然而有点不同的地方是:从accept返回客户的标识是在建立连接以后,而呼叫者ID功能部件显示打电话人的电话号码是在我们选择接或不接电话之前。如果使用域名系统(第11章),那么提供了一种类似于电话簿的服务。getaddrinfo类似于在电话簿查找个人的电话号码。
getnameinfo则类似于有一本按照电话号码而不是用户名排序的电话簿。

   
TCP选项

    每一个SYN可以含有若干个TCP选项。通常使用的选项有:
    ·MSS选项。TCP发送的SYN中带有这个选项是通知对端它的最大分节大小MSS(maximum segment size),即它能接受的每个TCP分节中的最大数据量。发送端TCP使用接收端的MSS 值作为所发送分节的最大大小。我们会看到如何使用TCP_MAXSEG套接口选项获取与设置这个TCP选项(7.9节)。
    ·窗口规模选项。TCP两端能够通知对端的最大窗口大小是65535,因为TCP头部相应的字段只占16位。但是当今因特网上业已普及的高速连接(每秒45兆位或更快,见RFC1323 [Jacobson,Braden,and Borman 1992])或长延迟的路径(卫星链路)要求有更大的窗口以获得尽可能最大的吞吐量。这个新选项指定TCP头部的通告窗口必须扩大(即左移)的位数 (0~14),因此所提供的最大窗口几乎是1G字节(65535×214)。两个端系统必须都支持这个选项,否则不具备扩大窗口规模能力。在7.5节我们将看到套接口选项SO_RCVBUF如何影响该选项。

    为提供与不支持这个选项的较早实现间的互操作性,应用如下的规则。TCP可以作为主动打开的一部分内容随它的SYN发送该选项,但只有对端也随它的SYN发送该选项时,它才能扩大窗口的规模。类似地,服务器的TCP只有接收到随客户的SYN来的这个选项时,它才能发送该选项。本逻辑假定实现会忽略它们不理解的选项。这是要求的,而且相当普遍,然而不幸的是无法保证所有实现都是这样。

    ·时间戳选项。这个选项对高速连接是必要的,它可以防止由失而复得的分组可能造成的数据损坏。因为它是新选项,所以其处理类似于窗口规模选项。作为网络编程人员,对于这个选项我们没有必要担心。
    TCP的大多数实现都支持这些选项。其中后两个选项有时也称为“RFC 1323选项”,因为它们是在RFC1323[Jacobson,Braden,and Borman 1992]中说明的。它们也称为“长胖管道 ”选项,因为高带宽或长延迟的网络被称为“长胖管道(long fat pipe)”。TCPv1的第24章对这些新选项有详细的叙述。

TCP连接终止

    TCP建立一个连接需三个分节,终止一个连接则需四个分节。
    1.某个应用进程首先调用close,我们称这一端执行主动关闭(active close)。这一端的TCP于是发送一个FIN分节,表示数据发送完毕。
    2.接收到FIN的另一端执行被动关闭(passive close)。这个FIN由TCP确认。它的接 收也作为文件结束符传递给接收端应用进程(放在已排队等候该应用进程接收的任何其他数 据之后),因为FIN的接收意味着应用进程在相应连接上再也接收不到额外数据。
    3.一段时间后,接收到文件结束符的应用进程将调用close关闭它的套接口。这导致它的TCP也发送一个FIN。  4.接收到这个FIN的原发送端TCP(即执行主动关闭的那一端)对它进行确认。因为每个方向都需要有一个FIN和一个ACK,所以一般需要四个分节。我们使用限定词“一般 ”是因为:有时步骤1的FIN随数据一起发送;另外,执行被动关闭那一端的TCP在步骤2和3 发出的ACK与FIN也可以合并成一个分节。图2.3说明了这些分组的交换过程。
FIN占据1个字节的序列号空间,这与SYN相同。所以每个FIN的ACK确认号是这个FIN的序列号加1。


图2.3TCP连接关闭时的分组交换

    在步骤2与步骤3之间可以有从执行被动关闭端到执行主动关闭端的数据流。这称为半关闭(h alfclose),我们将在6.6节随shutdown函数再详细介绍。套接口关闭时,每一端TCP都要发送一个FIN。这种情况在应用进程调用close时会发生,然而在进程终止时,所有打开的描述字将自愿(调用exit或从main函数返回)或不自愿(进程收到一个终止本进程的信号)地关闭,此时仍然打开的TCP连接上也会发出一个FIN。
    图2.3指出客户执行主动关闭,然而不管是客户还是服务器都可以执行主动关闭。通常情况是客户执行主动关闭,但某些协议如HTTP(超文本传送协议)则是服务器执行主动关闭。 

TCP状态转换图

    TCP连接的建立和终止可以用状态转换图(state transition diagram)来说明,见图2.4。
    TCP为一个连接定义了11种状态,并且TCP规则规定如何基于当前状态及在该状态下所接收的分节从一个状态转换到另一个状态。举例来说,当应用进程在 CLOSED状态下执行一个主动打开时,TCP将发送一个SYN并从CLOSED状态转换成SYN_SENT状态。如果该TCP接着接收到一个捎带ACK的SYN,它将发送一个ACK并转换成ESTABLISHED状态。这个最终状态是绝大多数数据传送发生的状态。
    有两个外向箭头引出自ESTABLISHED状态的连接终止处理。如果应用进程在接收到文件结束符前调用close(主动关闭),则转换成FIN_WAIT_1状态。如果在ESTABLISHED状态下应用进程接收到FIN,则转换成CLOSE_WAIT态。  
    我们用实线表示客户的状态转换,虚线表示服务器的状态转换。注意我们没有提到的两个转换:一个为同时打开(当两端几乎同时发送SYN并且这两个SYN在网络中彼此交错时),另一个为同时关闭(当两端同时发送FIN时)。
TCPv1的第18章将讨论这两种情况,它们是可能发生的,不过非常罕见。
    展示状态转换图的理由之一是给出11种TCP状态的名称。netstat命令的输出包括这些状态,它是调试客户/服务器应用程序的有用的工具。在第5章中我们将使用netstat去监视这些状态。 

观察分组

    图2.5说明一个完整的TCP连接所发生的实际分组交换情况:建立连接、传送数据和终止连接。图中展示了每个端点所历经的TCP状态。


图 2.4  TCP状体转换图

    本例中客户通告的MSS(最大分节大小)值是536(表明该客户只实现了最小重组缓冲区大小),而服务器通告的MSS值为1460(以太网上IPv4的典型值)。不同方向的MSS可以不相同(见习题2.5)。
    一旦连接建立,客户就构造一个请求并发送给服务器。这里我们假设该请求适合于单个TCP分节(即请求大小小于服务器通告的1460字节的MSS)。服务器处理该请求并发送应答,我们假设应答也适合于单个分节(本例即小于536)。这两个数据分节在图中使用粗箭头表示。注意,服务器对客户请求的确认是伴随其应答发送的。这种做法称为捎带(piggybacking),它通常在服务器处理请求并产生应答的时间少于200毫秒时发生。如果服务器耗用更长时间,例如1秒钟,那么我们将看到先是确认后是应答。(TCP数据流机理在TCPv1的第19章和第20章中详细叙述)


图 2.5  TCP连接中的分组交换

    以后4个分节终止连接。注意:执行主动关闭的那一端(客户端)进入TIME_WAIT状态,我们将在下一节讨论这种情况。
    图2.5中值得注意的是,如果连接的整个目的仅仅是发送一个单一分节的请求和接收一个单一分节的应答,那么使用TCP有8个分节的额外开销。如果改用UDP,那么只需交换两个分组:请求和应答。然而从TCP切换到UDP将丧失TCP提供给应用进程的全部可靠性,迫使可靠服务的一大堆细节从传输层(TCP)转移到UDP应用进程。TCP提供的另一个重要特性即拥塞控制也得由UDP应用进程处理。尽管如此,许多网络应用还是使用UDP,因为它们需要交换的数据量较少,而UDP避免了TCP连接建立和终止的额外开销。 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值