A、B机器正常TCP连接后,B突然断网,A处于什么状态?

TCP异常断开连接场景?几个思考点:

  • 是否开启keepalive?

  • 是否存在数据交互?

  • 进程崩溃;

  • 客户端主机宕机(客户端网络不可用 是同种情况);

keepalive开启,服务器会探测客户端,不会出现问题。

keepalive未开启,存在以下情况:

  1. 客户端进程崩溃

    使用 kill -9 来模拟进程崩溃的情况,发现在 kill 掉进程后,服务端会发送 FIN 报文,与客户端进行四次挥手。

    所以,即使没有开启 TCP keepalive,且双方也没有数据交互的情况下,如果其中一方的进程发生了崩溃,这个过程操作系统是可以感知的到的,于是就会发送 FIN 报文给对方,然后与对方进行 TCP 四次挥手。

  2. 存在数据交互,客户端主机宕机

    第一种,客户端主机宕机,又迅速重启,会发生什么?

    第二种,客户端主机宕机,一直没有重启,会发生什么?

    Ⅰ. 客户端主机宕机,又迅速重启

    在客户端主机宕机后,服务端向客户端发送的报文会得不到任何的响应,在一定时长后,服务端就会触发超时重传机制,重传未得到响应的报文。服务端重传报文的过程中,刚好客户端主机重启完成,这时客户端的内核就会接收重传的报文,这时:

    • 如果客户端主机上没有进程监听该 TCP 报文的目标端口号,由于找不到目标端口,客户端内核就会回复 RST 报文,重置该 TCP 连接;

    • 如果客户端主机上有进程监听该 TCP 报文的目标端口号,由于客户端主机重启后,之前的 TCP 连接的数据结构已经丢失了,客户端内核里协议栈会发现找不到该 TCP 连接的 socket 结构体,于是就会回复 RST 报文,重置该 TCP 连接。

    • 所以,只要有一方重启完成后,收到之前 TCP 连接的报文,都会回复 RST 报文,以断开连接。


    Ⅱ. 客户端主机宕机,一直没有重启

    这种情况,服务端超时重传报文的次数达到一定阈值后,内核就会判定出该 TCP 有问题,然后通过 Socket 接口告诉应用程序该 TCP 连接出问题了。那具体重传几次呢?

    在 Linux 系统中,提供了一个叫 tcp_retries2 配置项,默认值是 15,如下:

    [root@node01 ~]# cat /proc/sys/net/ipv4/tcp_retries2
    15
    

    这个内核参数是控制,在 TCP 连接建立的情况下,超时重传的最大次数

    不过 tcp_retries2 设置了 15 次,并不代表 TCP 超时重传了 15 次才会通知应用程序终止该 TCP 连接,内核还会基于「最大超时时间」来判定

    每一轮的超时时间都是倍数增长的,比如第一次触发超时重传是在 2s 后,第二次则是在 4s 后,第三次则是 8s 后,以此类推。内核会根据 tcp_retries2 设置的值,计算出一个最大超时时间。

    在重传报文且一直没有收到对方响应的情况时,先达到「最大重传次数」或者「最大超时时间」这两个的其中一个条件后,就会停止重传

  3. 不存在数据交互,客户端主机宕机

    如果客户端主机崩溃了,服务端是无法感知到的,在加上服务端没有开启 TCP keepalive,又没有数据交互的情况下,服务端的 TCP 连接将会一直处于 ESTABLISHED 连接状态,直到服务端重启进程

    没有使用 TCP 保活机制,且双方不传输数据的情况下,一方的 TCP 连接处在 ESTABLISHED 状态时,并不代表另一方的 TCP 连接还一定是正常的。


TCP重置报文段(RST)

通常当发现一个到达的报文段对于相关连接而言是不正确的时,TCP就会发送一个重置报文段。总体上来说,重置报文段主要有以下几种场景:

1.针对不存端口的连接请求

当一个连接请求到达本地却没有相关进程在目的端口侦听时就会产生一个重置报文段。

2.终止一条连接

通常终止一条连接的正常方法是由通信一方发送一个FIN。这种方法有时也被称为有序释放。(因为FIN是在之前所有排队数据都已经发送后才被发送出去,通常不会出现丢失数据的情况)

而在任何时刻,我们都可以通过发送一个重置报文段RST替代FIN来终止一条连接。这种方式一般被称为终止释放。

终止一条连接的特点:

1)任何排队的数据都将被抛弃,一个重置报文段会被立即发送出去;

2)重置报文段的接收方会说明通信另一端采用了终止的方式而不是一次正常关闭

需要注意的是重置报文段不会令通信令一端做出任何响应,即它不会被确认。接收重置报文段的一端会终止连接并提供“连接被另一端重置”的错误提示。

3.半开(半关闭)连接,服务器重启后接收到命令

一般造成半开状态的情景有:1)通信一方的主机崩溃;2)某一台主机的电源被切断而不是被正常关闭。

在连接处于半开或半关闭状态时,服务器异常崩溃后重启,重新连接以太网并尝试从客户端向服务器发送新命令,由于重启之后服务器的TCP会丢失之前所有连接的记忆,此时TCP规定接收者将回复一个RST重置报文段作为响应。

4.时间等待错误(TIME-WAIT Assassination)

在关闭连接流程,主动发起关闭者在发送了ACK之后,会进入TIME_WAIT状态。在这段时期,等待的TCP通常不需要做任何操作,它只需要维持当前状态直到2MSL的倒计时结束。然而,如果它在这段时期内接收到来自于这条连接的一些报文段,或是更加特殊的重置报文段,它将会被破坏(例如客户端收到某个报文,回复ACK,而此时服务器收到后没有关于该连接的任何信息,则会发送RST)。这即是时间等待错误。一般可以设置在TIME_WAIT状态时忽略重置报文段一阻止这一问题。


TCP保活机制

如果两端的 TCP 连接一直没有数据交互,达到了触发 TCP 保活机制的条件,那么内核里的 TCP 协议栈就会发送探测报文

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

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

所以,TCP 保活机制可以在双方没有数据交互的情况,通过探测报文,来确定对方的 TCP 连接是否存活


心跳包

心跳包

很多应用层协议都有HeartBeat机制,通常是客户端每隔一小段时间向服务器发送一个数据包,通知服务器自己仍然在线,并传输一些可能必要的数据。使用心跳包的典型协议是IM,比如QQ/MSN/飞信等协议。

心跳包之所以叫心跳包是因为:它像心跳一样每隔固定时间发一次,以此来告诉服务器,这个客户端还活着。事实上这是为了保持长连接,至于这个包的内容,是没有什么特别规定的,不过一般都是很小的包,或者只包含包头的一个空包

在TCP的机制里面,本身是存在有心跳包的机制的,也就是TCP的选项:SO_KEEPALIVE。系统默认是设置的2小时的心跳频率。但是它检查不到机器断电、网线拔出、防火墙这些断线。而且逻辑层处理断线可能也不是那么好处理。一般,如果只是用于保活还是可以的。

心跳包一般来说都是在**逻辑层(应用层)**发送空的echo包来实现的。下一个定时器,在一定时间间隔下发送一个空包给客户端,然后客户端反馈一个同样的空包回来,服务器如果在一定时间内收不到客户端发送过来的反馈包,那就只有认定说掉线了

其实,要判定掉线,只需要send或者recv一下,如果结果为零,则为掉线。但是,在长连接下,有可能很长一段时间都没有数据往来。理论上说,这个连接是一直保持连接的,但是实际情况中,如果中间节点出现什么故障是难以知道的。更要命的是,有的节点(防火墙)会自动把一定时间之内没有数据交互的连接给断掉在这个时候,就需要我们的心跳包了,用于维持长连接,保活

在获知了断线之后,服务器逻辑可能需要做一些事情,比如断线后的数据清理呀,重新连接呀……当然,这个自然是要由逻辑层根据需求去做了。

总的来说,心跳包主要也就是用于长连接的保活和断线处理。一般的应用下,判定时间在30-40秒比较不错。如果实在要求高,那就在6-9秒。

心跳包和TCP协议的KeepAlive机制对比(存疑)

学过TCP/IP的同学应该都知道,传输层的两个主要协议是UDP和TCP,其中UDP是无连接的、面向packet的,而TCP协议是有连接、面向流的协议。

所以非常容易理解,使用UDP协议的客户端需要定时向服务器发送心跳包,告诉服务器自己在线。然而,MSN和现在的QQ往往使用的是TCP连接了,尽管TCP/IP底层提供了可选的KeepAlive(ACK-ACK包)机制,但是它们也还是实现了更高层的心跳包。似乎既浪费流量又浪费CPU,有点莫名其妙。

很多网络设备,尤其是NAT路由器,由于其硬件的限制(例如内存、CPU处理能力),无法保持其上的所有连接,因此在必要的时候,会在连接池中选择一些不活跃的连接踢掉。典型做法是LRU,把最久没有数据的连接给T掉。通过使用TCP的KeepAlive机制(修改那个time参数),可以让连接每隔一小段时间就产生一些ack包,以降低被T掉的风险,当然,这样的代价是额外的网络和CPU负担。

前面说到,许多IM协议实现了自己的心跳机制,而不是直接依赖于底层的机制,不知道真正的原因是什么。

就我看来,一些简单的协议,直接使用底层机制就可以了,对上层完全透明,降低了开发难度,不用管理连接对应的状态。而那些自己实现心跳机制的协议,应该是期望通过发送心跳包的同时来传输一些数据,这样服务端可以获知更多的状态。例如某些客户端很喜欢收集用户的信息……反正是要发个包,不如再塞点数据,否则包头又浪费了

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: TCP连接是一种可靠的连接,它可以保证数据的可靠传输。当a和b建立TCP连接时,MSS为1KB,这意味着每次传输的数据包大小为1KB。在传输过程中,如果发生数据包丢失或损坏,TCP会自动重传数据包,以确保数据的完整性和可靠性。此外,TCP还可以进行流量控制和拥塞控制,以避免网络拥塞和数据丢失。因此,TCP连接是一种非常可靠的连接方式,适用于需要高可靠性和稳定性的应用场景。 ### 回答2: TCP连接指的是在计算机网络中利用TCP协议来进行通信的一种机制。其中,TCP协议是一种传输层协议,它可以确保所传输的数据能够被成功地发送和接收,并且在发送过程中数据能够被切分成多个包进行传输,比如MSS为1KB的数据包。 建立TCP连接时,通常采用TCP三次握手的方式。首先,客户端a先向服务器b发送一个SYN包,请求建立连接。服务器b收到这个包后,向a回复一个SYN+ACK包,表示已经收到了请求,并且可以建立连接。最后,a再向b发送一个ACK包,表示已经准备好进行通信了。 在建立连接时,MSS是非常重要的一个参数。MSS的意思是Maximum Segment Size,即最大分段大小。在TCP协议中,数据会被分成多个段进行传输,而每个段传输的最大大小就是MSS。MSS的默认值是536字节,但是由于网络状况等原因,有时候需要调整MSS的大小。 如果MSS的值为1KB,那么每个数据包的最大传输量就是1KB。这样,就可以有效地减少数据包的数量,提高传输效率。但是,在网络状况不佳的情况下,大的MSS值可能会导致数据包的丢失或延迟,从而影响通信质量。 总之,在建立TCP连接时,需要注意MSS的大小,以保证数据能够成功地传输。同时,在实际应用中,还需要根据具体的网络状况和需求,适当地调整MSS的大小。 ### 回答3: TCP(传输控制协议)是一种计算机网络协议,它实现了可靠性、错误恢复和数据流控制等功能。建立TCP连接的过程包括三次握手和四次挥手,而建立的连接能够为数据传输提供可靠的保障,保证数据的完整性和可靠性。在此基础上,对于数据的分段传输,TCP采用了MSS(最大有效载荷大小)机制来限制数据段的大小,以避免数据在网络传输过程中的碎片化。 对于题目中给定的情境,a和b建立TCP连接,MSS为1kb。这里的1kb表示了TCP数据段的最大大小,也就是MSS的值。在这种情况下,数据的分段传输就会被限制在1kb的大小内,以避免数据在网络传输过程中的碎片化。 当a向b发送数据时,数据将被划分为多个由TCP头部和数据组成的1kb的数据段。然后,这些数据段会按照TCP的流量控制机制进行传输,确保数据的完整性和可靠性。在两个端点之间,TCP会建立一个虚拟的通道,该通道能够控制数据的传输速率,并避免网络拥塞。 可以结合TCP协议的传输控制功能,理解题目中的情境。在实际应用中,MSS的大小也会根据网络带宽、延迟和拥塞程度等因素进行优化,以提高TCP传输的效率和可靠性,从而保证更好的用户体验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

狱典司

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值