《TCP/IP详解 卷1》 笔记: TCP连接的建立与终止

来源:互联网 发布:啤酒配方软件中文版 编辑:程序博客网 时间:2024/05/17 06:23

引言

    TCP是一个面向连接的协议。使用TCP的应用在交换数据前必须先建立一个连接。

建立连接

    建立TCP连接的过程如下图所示:


        1. 客户TCP发送一个 SYN报文段(报文段1)给服务器。其中包含服务器端口号以及初始序号(它是一个随机值,在这个例子中为1415531521)。
        2. 服务器TCP发回包含服务器的初始序号(这个例子中为1823083521)的SYN报文段(报文段2)作为应答。同时,将确认序号设置为客户的ISN加1(1415531522)以对客户的SYN报文段进行确认。
        3. 客户TCP将确认序号设置为服务器的ISN加1(1823083522)以对服务器的SYN报文段进行确认(报文段3)。
    这三个报文段完成连接的建立。这个过程也称为三次握手(three-way handshake)
    发送第一个SYN报文段的一端将执行主动打开(active open)。接收这个SYN报文段并发回下一个SYN报文段的另一端执行被动打开(passive open)
终止连接

    终止连接的过程如下:

        1. 客户应用程序关闭连接,导致客户TCP发送一个FIN报文段(报文段4)。

        2. 服务器TCP收到客户的FIN报文段后,返回一个确认(ACK),确认序号为收到的序号加1(报文段5)。同时服务器TCP还向应用程序传送一个文件结束符。

        3. 服务器应用程序关闭连接,导致服务器TCP发送一个FIN报文段(报文段6)。

        4. 客户TCP收到服务器的FIN报文段后,返回一个确认,确认序号为收到的序号加1(报文段7)。

    首先执行关闭的一方(即发送第一个FIN报文段的一方,通常是客户)将执行主动关闭,而另一方(收到这个FIN报文段的一方,通常是服务器)执行被动关闭。   

    建立一个连接需要三次握手,而终止一个连接要经过四次握手。这由TCP的半关闭(half-close)造成的。既然一个TCP连接是全双工(即数据在两个方向上同时传递)的,因此每个方向必须单独地进行关闭。这原则就是当一方完成它的数据发送后就能发送一个FIN报文段来终止这个方向连接。收到一个FIN报文段只意味着不能接收数据,但仍能发送数据。TCP半关闭的一个例子如下图所示:


TCP的状态变迁图

    下图是TCP的状态变迁图:


    在这个图中要注意如下两点:

        1. 一个状态变迁的子集是“典型的”。我们用粗的实线箭头表示正常的客户状态变迁,用粗的虚线箭头表示正常的服务器状态变迁。

        2. 两个导致进入ESTABLISHED状态的变迁对应打开一个连接,而两个导致从ESTABLISHED状态离开的变迁
对应关闭一个连接。ESTABLISHED状态是连接双方能够进行双向数据传递的状态。

    上图中左下角的两个虚线框内分别表示TCP执行主动关闭和被动关闭的状态变迁。十一个状态的名称(CLOSED,LISTEN,SYN_SENT等)与netstat命令显示的状态名称一致。

    其中CLOSED状态不是一个真正的状态,而是这个状态图的假想起点和终点。

    TCP正常建立连接和终止连接对应的状态如下图所示:


2MSL等待状态

    TIME_WAIT状态也称为2MSL等待状态。每个具体TCP实现必须选择一个报文段最大生存时间MSL(Maximum Segment Life time)。它是任何报文段被丢弃前在网络内存在的最长时间。我们知道这个时间是有限的,因为TCP报文段以IP数据报在网络内传输,而IP数据报则有限制其生存时间的TTL字段。

    对一个具体实现所给定的MSL值,处理的原则是:当TCP执行一个主动关闭,并发回最后一个ACK,该连接必须在TIME_WAIT状态停留的时间为2倍的MSL。这样可让TCP再次发送最后的ACK以防这个ACK丢失。在连接处于2MSL等待时,任何迟到的报文段将被丢弃。
    这种2MSL等待的另一个结果是:定义这个连接的插口对(客户的IP地址和端口号,服务器的IP地址和端口号)不能再被使用。
    遗憾的是,大多数TCP实现(如伯克利版)强加了更为严格的限制。在2MSL等待期间,插口中使用的本地端口在默认情况下不能再被使用。这对客户程序没有什么影响,因为客户使用随机的端口。然而,对于服务器,情况就有所不同,因为服务器使用知名端口号。如果我们终止一个已经建立连接的服务器程序,并试图立即重新启动这个服务器程序,服务器程序将不能把这个知名端口和它的套接字绑定,因为这个端口号是处于2MSL连接的一部分。在重新启动服务器程序前,需要等待1~4分钟。
FIN_WAIT_2状态

    在FIN_WAIT_2状态我们已经发出了FIN报文段,并且另一端也已对它进行确认。只有当另一端的进程完成这个关闭(发送FIN报文段),我们这端才会从FIN_WAIT_2状态进入TIME_WAIT状态。这意味着我们这端可能永远保持这个状态。另一端也将永远处于CLOSE_WAIT状态直到应用层决定进行关闭。

    许多伯克利的TCP实现为防止在FIN_WAIT_2状态无限等待,采用如下违背协议规范的方法:如果执行主动关闭的应用层进行全关闭,就设置一个10分钟75秒的定时器。定时器超时后TCP将进入CLOSED状态。

复位报文段

    我们已经介绍了TCP首部中的RST标志位是用于复位连接的。以下几种情况,TCP会发出复位报文段。

        1. 当连接请求到达(收到SYN报文段),而没有进程在监听目的端口。对于UDP,它将产生一个ICMP端口不可达差错。而TCP则发出一个复位报文段。

        2. 异常终止一个连接。我们从上文中看到终止一个连接的正常方式是一方发送FIN报文段。有时这也称为有序释放(orderly release),因为在所有排队的数据都已发送之后才发送FIN报文段,正常情况下没有任何数据丢失。但也有可能发送一个复位报文段而不是FIN报文段来中途释放一个连接。有时称这为异常释放(abortive release)异常终止一个连接对应用程序来说有两个优点:(1)丢弃任何待发数据并立即发送复位报文段;(2)复位报文段的接收方会区分对端执行的是异常关闭还是正常关闭。收到复位报文段的一端不会对复位报文段进行确认,它仅通知应用程序连接复位。

        3. 检测半打开的连接。如果一方已经关闭或异常终止连接而另一方却还不知道,我们将这样的TCP连接称为半打开(Half-Open)的。半打开连接的另一个常见原因是服务器主机突然掉电。在服务器重启后,由于TCP已经丢失所有的连接信息,在收到客户的报文段后会立即发送复位报文段。

TCP选项

    常见的TCP选项格式如下图所示:


    每个选项的开始是1字节kind字段,说明选项的类型。kind字段为0和1的选项仅占1个字节。其他的选项在kind字段后还有1字节的len字段,它说明该选项的总长度。

    设置无操作选项的原因在于使整个选项的长度为4字节的倍数。

处理连接请求

    伯克利的TCP实现中采用如下规则处理连接请求:

        1. 正等待连接请求的一端(服务端)有一个固定长度的连接队列,该队列中的连接已被TCP接受(即三次握手已经完成),但还没有被应用层接受。TCP接受一个连接是将其放入这个队列,而应用层接受一个连接是将其从该队列中移出。

        2. 应用层指明该队列的最大长度,这个值通常称为积压值(backlog)。它的取值范围是0~5之间的整数,包括0和5(大多数的应用程序都将这个值说明为5)。
        3. 当一个连接请求(即SYN报文段)到达时,TCP使用与积压值相关的一个算法,根据当前连接队列中的连接数来确定是否接收这个连接。注意,积压值说明的是TCP监听的套接字已被TCP接受而等待应用层接受的最大连接数。这个积压值对系统所允许的最大连接数或者并发服务器所能并发处理的客户数无影响。
        4. 如果对于新的连接请求,该TCP监听的套接字的连接队列中还有空间,TCP将对SYN报文段进行确认并完成连接的建立。但应用层只有在三次握手中的第三个报文段收到后才会知道这个新连接。
        5. 如果对于新的连接请求,连接队列中已没有空间,TCP将不理会收到的SYN报文段。它也不发回任何报文段(即不发回复位报文段)。如果应用层不能及时接受已被TCP接受的连接,这些连接可能占满整个连接队列,客户的主动打开最终将超时。
阅读全文
0 0
原创粉丝点击