
TCP的断开就是经过四次挥手: 这是正常的情况,客户端主动tcp
连接断开的过程。客户端先是发送一个FIN为一的
报文,然后进入FIN_WAIT_1的状态。
服务器收到FIN报文后,发送一个ACK报文,然后进入CLOSED_WAIT状态。 客户端收到服务器的ACK报文进入FIN_WAIT_2状态。 等到服务器觉得他数据处理好了,可以关闭的时候,会发送一个FIN报文,然后进入LAST_ACK。等待最后一个应答。 让客户端收到服务器FIN报文,就进入TIME_WAIT状态了,随后发送最后一个ACK报文,然后close。 客户端再等待2msl后也自己主动关闭。而只有主动关闭的情况下,才会有TIME_WAIT。 那么为什么四次挥手需要四次呢? 三次握手其实就是在第二次把ACK和SYN两个报文合并成一个发,但是断开的过程可能还有一方需要处理下数据,需要延长点时间,等处理好再发FIN,所以就比三次握手多了一次。 这里还有一个问题,为什么需要TIME_WAIT,然后到close需要2msl的时间呢? 先说下什么是MSL,也就是报文的最长生存时间,超过这个时间的报文就要被丢弃掉。tcp是基于ip的,ip上有个生存时间TTL,是ip报文可以经过的最大路由数量,每经过一个路由就减1,减到0,ip报文就丢弃掉,然后通过ICMP通知源主机,我们的ping也算是经过这个。当然msl和ttl还是有区别的,msl是时间,ttl是路由数量,msl也是大于等于ttl的。在linux中,2msl默认是60秒。 前文也说了,只有主动发起断开连接的进程才会有time wait状态。time wait+2msl有两个原因: 1.防止旧连接的数据包 像这个seq 301的包,如果因为网络的原因被延迟了,而没有time wait或者很短,那么连接断开后,又建立新的连接,这个时候这个包到了,可能就导致数据紊乱了。而2msl可以保证两个方向的包在断开前丢弃掉。 2.保证正确的断开连接 2msl的时间也是保证第四个报文的ack可以被被动关闭方接收到。 如图,假设time wait比较短或者没有,当最后的ack报文丢失的时候。客户端已经close了,而服务器一直处于last ack的状态。这样连接就不能正常断开了。而如果有time wait +2msl这个情况就可以避免。假设服务器没有收到最后一个ack报文,服务器会重发FIN等待客户端的ack。 这样就可以保证不会出现一端断开,另外一端没有断开的情况了。 有时候我们在服务器上会看到很多time wait。time wait一般就是服务器主动发起的断开请求才会产生的状态。所以time wait过多,第一个是系统资源会大量消耗,还有是端口如果占的太多,会导致没办法创建新连接。这个时候可以把linux的net.ipv4.tcp_tw_reuse开启,置为1,可以复用time wait超过1秒的连接。 这边再说说tcp的保活机制。也就是怎么长期维持客户端和服务端的连接。 在一个时间段内,如果没有连接等相关活动,tcp的保活机制会定期发探测报文,如果连续几个探测报文就没有回应,就将错误信息报告给系统,系统通知上层应用。 在 Linux 内核可以有对应的参数可以设置保活时间、保活探测的次数、保活探测的时间间隔,以下都为 默认值: tcp_keepalive_time=7200:表示保活时间是 7200 秒(2⼩时),也就 2 小时内如果没有任何连接 相关的活动,则会启动保活机制 tcp_keepalive_intvl=75:表示每次检测间隔 75 秒; tcp_keepalive_probes=9:表示检测 9 次无响应,认为对⽅方是不不可达的,从⽽而中断本次的连接。 也就是说在 Linux 系统中,最少需要经过 2 小时 11 分 15 秒才可以发现一个「死亡」连接。 当然这个时间也可以自己配置。TCP连接中断检测时间
这个问题得分情况来说:
1、双方只建立了一个连接,然后就再也没有任何数据通信,这完全是可能的。这时,tcp有一个保活定时器,它的作用就是确认对端是否存活,通常它没2个小时发送一个数据包给对方,以查看是否有响应。
2、tcp中断,此时发送端发送数据,但是由于收不到ACK,它会一直尝试,通常的时间间隔为1s, 3s, 6s, 12s ..... 64s,这个间隔被称为"指数退避",到最后,通常在9分钟后放弃(这个值看实现有可能不同)。
3、tcp中断,在这个过程中,路由器检测到主机不可达,当发送数据后会返回一个icmp信息,显示主机不可达,这个通常很快就能检测出来。
75秒,但还是要看具体情况:如下client向server发起连接,server接受client连接,双方建立连接。Client与server完成一次读写之后,它们之间的连接并不会主动关闭,后续的读写 *** 作会继续使用这个连接。首先说一下TCP/IP详解上讲到的TCP保活功能,保活功能主要为服务器应用提供,服务器应用希望知道客户主机是否崩溃,从而可以代表客户使用资 源。如果客户已经消失,使得服务器上保留一个半开放的连接,而服务器又在等待来自客户端的数据,则服务器将应远等待客户端的数据,保活功能就是试图在服务 器端检测到这种半开放的连接。如果一个给定的连接在两小时内没有任何的动作,则服务器就向客户发一个探测报文段,客户主机必须处于以下4个状态之一:客户主机依然正常运行,并从服务器可达。客户的TCP响应正常,而服务器也知道对方是正常的,服务器在两小时后将保活定时器复位。 客户主机已经崩溃,并且关闭或者正在重新启动。在任何一种情况下,客户的TCP都没有响应。服务端将不能收到对探测的响应,并在75秒后超时。服务器总共发送10个这样的探测 ,每个间隔75秒。如果服务器没有收到一个响应,它就认为客户主机已经关闭并终止连接。 客户主机崩溃并已经重新启动。服务器将收到一个对其保活探测的响应,这个响应是一个复位,使得服务器终止这个连接。 客户机正常运行,但是服务器不可达,这种情况与2类似,TCP能发现的就是没有收到探查的响应。 从上面可以看出,TCP保活功能主要为探测长连接的存活状况,不过这里存在一个问题,存活功能的探测周期太长,还有就是它只是探测TCP连接的存活,属于比较斯文的做法,遇到恶意的连接时,保活功能就不够使了。在长连接的应用场景下,client端一般不会主动关闭它们之间的连接,Client与server之间的连接如果一直不关闭的话,会存在一个问 题,随着客户端连接越来越多,server早晚有扛不住的时候,这时候server端需要采取一些策略,如关闭一些长时间没有读写事件发生的连接,这样可 以避免一些恶意连接导致server端服务受损;如果条件再允许就可以以客户端机器为颗粒度,限制每个客户端的最大长连接数,这样可以完全避免某个蛋疼的 客户端连累后端服务。
评论列表(0条)