TCP并不总是“可靠”的?

TCP 是可靠的?

发送端通过调用send函数之后,数据流并没有传输出去,数据会先存储到套接字的发送缓冲区中,通过网络协议栈决定何时发送、如何发送。当对应的数据发送给接收端,接收端回应ACK,这时存储到发送缓冲区的数据可以删除了,但发送端无法获取对应数据流的ACK情况(无法判断对端是否接收到数据流),如果想知道,必须在应用层添加处理逻辑,例如显示的报文确认机制。

从接收端来看,也不能保证ACK过的数据被应用程序处理,因为数据需要从接收端拷贝,可能发生接收过程中程序突然崩溃。

所以,TCP协议没有提供给上层应用程序过多的异常处理细节,反映链路异常的能力弱。(无人值守,自我恢复)

TCP连接之后,能感知链路方式只有read和write操作。

故障模式总结

2大类

1.网络中断造成的对端无FIN包

网络中断,TCP程序不能及时感到异常信息,除非路由器发出ICMP报文,说明目的网络或主机不可达,这个时候通过read或write调用就会返回Unereachable错误

如果没有ICMP报文的情况下,TCP程序不能理解应到连接异常,如果程序阻塞到read调用上,程序将无法恢复正常。不过可以给read操作设置超时来解决。

如果先调用write发送数据流,接下来阻塞在read调用上。TCP协议栈将发送缓冲区的数据发出去,大概重传12次、合计时间为9分钟,协议栈标识会连接异常,这是阻塞的read调用会返回TIMEOUT错误信息,如果程序还往这条连接写数据,写操作会立即失败,返回一个SIGPIPE信号给应用程序。

系统崩溃造成对端无FIN包

系统崩溃,比如断电,网络连接上来不及发出任何东西。这个和通过系统杀死应用程序不同的是,没有FIN包发出来。

情况1:没有ICMP报文情况下,TCP程序只能通过read和write调用得到网络连接异常信息,常见的是超时错误。

情况2:系统崩溃之后又重启,当重传的TCP分组到达重启后的系统,由于没有TCP分组对应的连接数据,系统会返回一个RST重置分节,TCP程序通过read和write调用可以对RST进行错误处理。

如果是阻塞read调用,会立即返回一个错误,错误为连接重置(Connection Reset)

如果是一次write操作,会立即失败,应用程序会返回一个SIGPIPE信号

对端有FIN包发出

如果有FIN包发出,可能场景是对端调用了close或shutdown显示关闭连接,也可能是对端应用程序崩溃,操作系统内核代为清理所发出的,从应用程序角度来看,无法区分是那种情形。

阻塞的read操作完成数据读取之后,FIN包会通过一个EOF来完成通知,此时,read调用返回值为0。read收到FIN包之后不会立即返回,他会往接收缓冲区放置一个EOF符号,之前已经在接收缓冲区的有效数据不会受到影响。

向一个已关闭连接连续写,最终导致 SIGPIPE

如果在服务端读取数据并处理过程中,突然杀死服务器进程,我们会看到客户端很快也会退出,并在屏幕上打印出“Connection reset by peer”的提示。

总结

TCP异常分两大类:一类是对端无FIN包,需要通过巡检或超时来发现;
另一类是对端无FIN包,需要通过巡检或超时来发现,另一类是对端有FIN包发出,需要通过增强read或write操作异常处理,帮助发现异常。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值