TCP连接的建立与终止

来源:互联网 发布:水晶古筝知乎 编辑:程序博客网 时间:2024/05/21 00:45

TCP 是一种面向连接的单播协议。我们知道,一个TCP连接是由一个四元组构成的(两个IP地址和两个端口号)。一个TCP连接通常分为三个阶段:启动、数据传输和退出。关于TCP连接的建立与终止有关的一些基础的概念我们在这里不再赘述,首先我们先来看一下TCP正常连接与退出时的情况:


三次握手:

在图中我们可以看到,在一个普通的TCP连接的建立过程中,客户端利用SYN报文段来交换彼此的初始序列号(记为ISN)通常,客户端还会借此发送一个或多个选项(比较常见的TCP选项有最大段大小等,这里就先不多说了)。为了确认客户端的SYN,服务器将他自己包含的ISN(s)的数值加1作为返回的ACK数值。因此,每次发送一个SYN,序列号就会自动的加1。这样的话如果出现丢失的情况,该SYN段将会被重传。

 通过三个报文段就能完成一个TCP的连接,这个过程被我们成为“三次握手”。

三次握手的目的不仅在于让通信双方了解到一个TCP的连接正在建立,更为重要的是利于数据包的选项来承载一些特殊的信息以及交换序列号。



四次挥手:

连接的任意一方都可以发起一个关闭的操作。并且该过程还支持双方同时关闭连接的操作,但是这种情况很少见,我们一会在后面来讨论同时开启与同事关闭的情况。

连接的主动关闭者通过发送一个FIN报文段来发起关闭操作,指明自己当前的序列号(记为K)。FIN 报文段还包含一个ACK报文段用来确认对方最近一次发来的数据(记为L)。

为了保证连接的关闭,最后发送的报文段还要包含一个ACK报文段用来确认上一个FIN。同样,如果出现了FIN丢失的情况,那发送方将重新传输直到接收到一个ACK确认为止。


综上,一个连接的建立需要三个报文段,而一个连接的关闭则需要四个报文段。这7个报文段是一个TCP连接在正常的建立以及关闭的基本开销(一些特殊的情况一会下面再来介绍)。因此当只需要交换少量数据时,一些应用程序更愿意使用不需要建立连接的UDP协议。当然了,与此同时,也会面临一些拥塞管理、流量控制等一些其他的问题。



TCP协议还支持连接处于半开启,这种情况不多见。这种情况一般发生在通信的一方的主机崩溃的情况下。只要不通过半开连接传输数据,正常工作的另一端是不会察觉到另一端已经奔溃的。(事实上TCP连接的另一方可以利用TCP的keepaliive选项来发现另一端已经消失了)。

 

TCP的半关闭

TCP的半关闭操作是指仅仅关闭数据流一个方向上的传输(我们知道TCP通信是双向的),而两个半关闭操作可以完整的关闭整个连接。虽然这个情况并不常见,但也确实有需要使用他的情况。比如说,一个应用程序表示:我已经完成了我数据的发送任务,并且发送了一个FIN报文段给对方,但是我还希望继续接收来自对方发送的数据直至他发来一个FIN给我。

因此API提供了半关闭的操作,只需要调用shutdown()函数来替代close()函数即可。


同时打开

接下来我们来讨论一下同时打开的情况,虽然说这种情况几乎不可能,但是在特定的安排下也是有可能的。

通信的双方在接收来自对方的SYN之前先发送一个SYN;两个SYN必须经过网路送达对方。该场景下还要求通信的双方都拥有一个IP地址和端口号,并且将其告知对方。这种情况很少见,一旦发生了,我们可以将其成为同时打开。

举个栗子,A通过6666端口向B的9999端口发送了一个主动打开的请求,与此同时B也通过9999端口向A的6666端口提出了一个主动打开的请求,此时就会发送同时打开的情况

我们可以发现,在这种情况下,服务器始终是连接的被动打开者而非主动打开者,而他们各自的客户端也会选择不同的端口号。因此他们可以被区分为两个不同的TCP连接。



从图中我们发现,同时打开与正常的连接相比,需要增加一个报文段,这可以被成为四次握手



同时关闭




从图中我们可以看到它与正常关闭很相似,只是报文段是交叉的。因此我们可以得出一个结论,正常关闭与同时关闭真正的区别在于报文段序列是交叉的还是顺序的。

原创粉丝点击