首页 > 编程知识 正文

网络请求协议,三次握手和四次挥手通俗举例

时间:2023-05-04 04:47:35 阅读:33390 作者:332

TCP次挥手过程与状态变迁

客户端尝试关闭连接时,发送TCP报头中的FIN标志位设置为1的消息,即FIN消息,然后客户端进入FIN_WAIT_1状态。

服务器接收到该消息后,向客户端发送ACK应答消息,接着服务器变为CLOSED_WAIT状态。

客户端从服务端收到ACK回复消息后,进入FIN_WAIT_2状态。

等待服务端处理数据后,也会向客户端发送FIN消息,然后服务端进入LAST_ACK状态。

客户端在从服务端接收到FIN消息后,返回ACK回复消息,然后进入TIME_WAIT状态

服务在收到ACK响应消息后进入关闭状态,这样,服务端就完成了连接的关闭。

客户端在经过2MSL的时间后自动进入关闭状态,这样客户端也就完成了连接的关闭。

因为每个方向都需要FIN和ACK,所以通常被称为挥手4次。 这里需要注意的是,主动关闭连接,然后进入TIME_WAIT状态。

回顾为什么挥手4次后接下来的4次挥手双方发送FIN包的过程,可以理解为什么需要4次。

关闭连接时,客户端向服务端发送FIN时,客户端不再发送数据,但只表示可以接收数据。

服务器在从客户端接收到FIN消息时,首先返回ACK回复消息,服务端可能还需要处理数据并发送,但在服务端不再发送数据时才将FIN消息发送到客户端,直到

从上述步骤可以看出,由于服务端通常需要等待数据的发送和处理完成,所以服务端的ACK和FIN通常是分开发送的,比三次握手多一次。

为什么TIME_WAIT的等待时间是2MSL? MSL是最大段寿命,是消息的最大生存时间,也是网络上任何消息存在的最长时间,超过此时间将丢弃消息。 因为TCP消息基于IP协议,所以IP标头中包含TTL字段。 这是IP数据报可以通过的最大路由数,每次处理时路由器的此值将减少1,如果此值为0,则丢弃数据报,并将ICMP消息通知源主机。

MSL和TTL的区别: MSL的单位是时间,TTL是经由跳数。 因此,为了确认消息已自然消失,MSL必须消耗TTL大于或等于0的时间。

认为TIME_WAIT等待两倍的MSL是合理的,因为在网络上存在来自发送端的分组,并且在这些发送端的分组被接收端处理之后向对方发送响应,所以每次需要两倍的时间。

例如,如果被动关闭端未收到断开的最后一个ACK消息,则发生超时并重新发送Fin消息,另一个接收到Fin,然后向被动关闭端重新发送ACK,正好是两个MSL

在客户端接收到FIN并发送ACK之后,2MSL的时间开始计数。 在等待时间内,如果客户端的ACK未传输到服务端,并且客户端收到服务端重新发送的FIN消息,则将重新测量2MSL时间。

在Linux系统上,2MSL默认为60秒,一个MSL为30秒。 Linux系统在TIME_WAIT停留的时间为固定的60秒。

为Linux内核代码定义的名称是TCP_TIMEWAIT_LEN。

#变更#defineTCP_timewait_len(60*Hz )/howlongtowaittodestroytime-wait state,about60seconds*/time_wait的时间长度时

为什么TIME_WAIT状态必须主动开始关闭连接的一侧? 有时间等待状态吗?

需要时间等待状态主要有两个原因。

防止接收相同“四组”的“旧”分组; 确保“被动关闭连接”侧正确关闭。 即,确保最后的ACK被被动的关机侧接收。 这样就可以正常关机。 第一,防止旧连接的数据包

如果时间等待没有等待时间或时间太短,延迟的数据包到达后会发生什么呢?

服务器在关闭连接之前在上图的黄色框中发送的SEQ=301信息被网络延迟了。

此时,复用具有相同端口的TCP连接,当延迟的SEQ=301到达客户机时,客户机有可能不能正常接收该过期的消息,产生数据丢失等严重的问题。

因此,TCP提出了一种机制,即随着2MSL的时间过去,两个方向的分组都被丢弃,原本连接的分组在网络上自然地消失,再次出现的分组一定是新建立连接而生成的。

原因2 :确保连接正确关闭

时间等待的作用是,最后的ACK

被动关闭方接收,从而帮助其正常关闭。

假设 TIME-WAIT 没有等待时间或时间过短,断开连接会造成什么问题呢?

如上图红色框框客户端四次挥手的最后一个 ACK 报文如果在网络中被丢失了,此时如果客户端 TIME-WAIT 过短或没有,则就直接进入了 CLOSE 状态了,那么服务端则会一直处在 LASE-ACK 状态。

当客户端发起建立连接的 SYN 请求报文后,服务端会发送 RST 报文给客户端,连接建立的过程就会被终止。

如果 TIME-WAIT 等待足够长的情况就会遇到两种情况:

服务端正常收到四次挥手的最后一个 ACK 报文,则服务端正常关闭连接。

服- 务端没有收到四次挥手的最后一个 ACK 报文时,则会重发 FIN 关闭连接报文并等待新的 ACK 报文。

所以客户端在 TIME-WAIT 状态等待 2MSL 时间后,就可以保证双方的连接都可以正常的关闭。

TIME_WAIT 过多有什么危害?

如果服务器有处于 TIME-WAIT 状态的 TCP,则说明是由服务器方主动发起的断开请求。

过多的 TIME-WAIT 状态主要的危害有两种:

第一是内存资源占用;

是对端口资源的占用,一个 TCP 连接至少消耗一个本地端口;

第二个危害是会造成严重的后果的,要知道,端口资源也是有限的,一般可以开启的端口为 32768~61000,也可以通过如下参数设置指定

net.ipv4.ip_local_port_range

如果服务端 TIME_WAIT 状态过多,占满了所有端口资源,则会导致无法创建新连接。

如何优化 TIME_WAIT?

这里给出优化 TIME-WAIT 的几个方式,都是有利有弊:

打开 net.ipv4.tcp_tw_reuse 和 net.ipv4.tcp_timestamps 选项;

net.ipv4.tcp_max_tw_buckets

程序中使用 SO_LINGER ,应用强制使用 RST 关闭。

方式一:net.ipv4.tcp_tw_reuse 和 tcp_timestamps

如下的 Linux 内核参数开启后,则可以复用处于 TIME_WAIT 的 socket 为新的连接所用。

net.ipv4.tcp_tw_reuse = 1

使用这个选项,还有一个前提,需要打开对 TCP 时间戳的支持,即

net.ipv4.tcp_timestamps=1(默认即为 1)

这个时间戳的字段是在 TCP 头部的「选项」里,用于记录 TCP 发送方的当前时间戳和从对端接收到的最新时间戳。

由于引入了时间戳,我们在前面提到的 2MSL 问题就不复存在了,因为重复的数据包会因为时间戳过期被自然丢弃。

温馨提醒:net.ipv4.tcp_tw_reuse要慎用,因为使用了它就必然要打开时间戳的支持 net.ipv4.tcp_timestamps,当客户端与服务端主机时间不同步时,客户端的发送的消息会被直接拒绝掉。

方式二:net.ipv4.tcp_max_tw_buckets

这个值默认为 18000,当系统中处于 TIME_WAIT 的连接一旦超过这个值时,系统就会将所有的 TIME_WAIT 连接状态重置。

这个方法过于暴力,而且治标不治本,带来的问题远比解决的问题多,不推荐使用。

方式三:程序中使用 SO_LINGER

我们可以通过设置 socket 选项,来设置调用 close 关闭连接行为。

struct linger so_linger;so_linger.l_onoff = 1;so_linger.l_linger = 0;setsockopt(s, SOL_SOCKET, SO_LINGER, &so_linger,sizeof(so_linger));

如果l_onoff为非 0, 且l_linger值为 0,那么调用close后,会立该发送一个RST标志给对端,该 TCP 连接将跳过四次挥手,也就跳过了TIME_WAIT状态,直接关闭。

但这为跨越TIME_WAIT状态提供了一个可能,不过是一个非常危险的行为,不值得提倡。

如果已经建立了连接,但是客户端突然出现故障了怎么办?

TCP 有一个机制是保活机制。这个机制的原理是这样的:

定义一个时间段,在这个时间段内,如果没有任何连接相关的活动,TCP 保活机制会开始作用,每隔一个时间间隔,发送一个探测报文,该探测报文包含的数据非常少,如果连续几个探测报文都没有得到响应,则认为当前的 TCP 连接已经死亡,系统内核将错误信息通知给上层应用程序。

在 Linux 内核可以有对应的参数可以设置保活时间、保活探测的次数、保活探测的时间间隔,以下都为默认值:

net.ipv4.tcp_keepalive_time=7200net.ipv4.tcp_keepalive_intvl=75 net.ipv4.tcp_keepalive_probes=9

tcp_keepalive_time=7200:表示保活时间是 7200 秒(2小时),也就 2 小时内如果没有任何连接相关的活动,则会启动保活机制

tcp_keepalive_intvl=75:表示每次检测间隔 75 秒;

tcp_keepalive_probes=9:表示检测 9 次无响应,认为对方是不可达的,从而中断本次的连接。

也就是说在 Linux 系统中,最少需要经过 2 小时 11 分 15 秒才可以发现一个「死亡」连接。

这个时间是有点长的,我们也可以根据实际的需求,对以上的保活相关的参数进行设置。

如果开启了 TCP 保活,需要考虑以下几种情况:

第一种,对端程序是正常工作的。当 TCP 保活的探测报文发送给对端, 对端会正常响应,这样 TCP 保活时间会被重置,等待下一个 TCP 保活时间的到来。

第二种,对端程序崩溃并重启。当 TCP 保活的探测报文发送给对端后,对端是可以响应的,但由于没有该连接的有效信息,会产生一个 RST 报文,这样很快就会发现 TCP 连接已经被重置。

第三种,是对端程序崩溃,或对端由于其他原因导致报文不可达。当 TCP 保活的探测报文发送给对端后,石沉大海,没有响应,连续几次,达到保活探测次数后,TCP 会报告该 TCP 连接已经死亡。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。