本文共 2970 字,大约阅读时间需要 9 分钟。
在握手正式开始之前,服务器必须准备好接收外来的连接。这通常通过调用socket, bind, listen这3个函数来完成,称之为被动打开。
注:通常SYN分节不携带数据,其所在IP数据报只含有一个IP首部,一个TCP首部及可能有的TCP选项。
进行三次握手的主要作用就是为了确认双方的接收能力和发送能力是否正常、指定自己的初始化序列号为后面的可靠性传送做准备。实质上其实就是连接服务器指定端口,建立TCP连接,并同步连接双方的序列号和确认号,交换TCP窗口大小信息。
MSS: 发送SYN的TCP一端使用本选项通告对端它的最大分节大小也就是它在本连接的每个TCP分节中愿意接收的最大数据量。服务器第一次收到客户端的 SYN 之后,就会处于 SYN_RCVD 状态,此时双方还没有完全建立其连接,服务器会把此种状态下请求连接放在一个队列里,我们把这种队列称之为半连接队列。
已经完成三次握手,建立起连接的就会放在全连接队列中。如果队列满了有可能会出现丢包现象。
当一端为建立连接而发送它的SYN时,它为连接选择一个初始序号。ISN随时间而变化,因此每个连接都将具有不同的ISN。
这样选择序号的目的在于防止在网络中被延迟的分组在以后又被传送,而导致某个连接的一方对它做错误的解释。三次握手的其中一个重要功能是客户端和服务端交换 ISN,以便让对方知道接下来接收数据的时候如何按序列号组装数据。 如果 ISN 是固定的,攻击者很容易猜出后续的确认号,因此 ISN 是动态生成的。
第一次,第二次握手不可以,第三次握手可以。
假如第一次握手可以携带数据的话,如果有人要恶意攻击服务器,那他每次都在第一次握手中的 SYN 报文中放入大量的数据。因为攻击者根本就不理服务器的接收、发送能力是否正常,然后疯狂着重复发 SYN 报文,这会让服务器花费很多时间、内存空间来接收这些报文。第三次握手的话,此时客户端已经处于 ESTABLISHED 状态。对于客户端来说,已经建立起连接了,并且也已经知道服务器的接收、发送能力是正常的,所以携带数据也是可以的了。
注:无论是客户还是服务器,任何一端都可以执行主动关闭。只不过通常情况都是客户端执行主动关闭
因为每个方向都需要一个 FIN 和一个 ACK,因此通常需要4个分节。
但是也有一些特殊情况:比如某些情况下第一次挥手的 FIN 随数据一起发送了;还有,第二次和第三次挥手发送的分节都出自同一端,有可能会被合并成一个分节。当对端收到发送端的 SYN 请求连接报文后,可以直接发送 ACK+SYN 报文。其中 ACK 报文是用来应答的,SYN 报文是用来同步的。但是关闭连接时,当对端端收到 FIN 报文时,可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文。只有等到该端所有的报文都发送完毕,才能发送 FIN 报文,因此不能一起发送。故需要四次挥手。
该端点(执行主动关闭的一端)停留在这个状态的持续时间是最长分节生命期(Maximum Segment Lifetime,MSL)的两倍,有时候称之为2MSL。
MSL(Maximum Segment Lifetime):是任何数据报能够在因特网中存活的最长时间,超过这个时间报文将被丢弃。
TIME_WAIT状态存在的理由:
假设最终的ACK丢失了。服务器将重新发送它的最终那个FIN,因此客户必须维护状态信息,以允许它重新发送最终那个ACK。要是客户不维护状态信息,它将响应以一个RST (另外一种类型的TCP分节),该分节将被服务器解释成一个错误。如果TCP打算执行所有必要的工作以彻底终止某个连接上两个方向的数据流(即全双工关闭),那么它必须正确处理连接终止序列4个分节中任何一个分节丢失的情况。这就说明了为什么执行主动关闭的那一端是处于TIME WAIT状态的那一端:因为可能不得不重传最终那个ACK的就是那一端。
假设现在有一个TCP连接,我们关闭这个连接,过一段时间后在相同的IP地址和端口之间建立另一个连接。后一个连接称为前一个 连接的化身( incarmation),因为它们的IP地址和端口号都相同。TCP必须防止来自某个连接的老的重复分组在该连接已终止后再现,从而被误解成属于同一连接的某个新的化身。为做到这一点, TCP将不给处于TIME WAIT状态的连接发起新的化身。既然TIME_ WAIT状态的持续时间是MSL的2倍,这就足以让某个方向上的分组最多存活MSL秒即被丢弃,另一个方向上的应答最多存活MSL秒也被丢弃。通过实施这个规则,我们就能保证每成功建立一个TCP连接时, 来自该连接先前化身的老的重复分组都已在网络中消逝了。
转载地址:http://hjqwi.baihongyu.com/