一口Linux
认证:优质创作者
所在专题目录 查看专题
教你如何抓取网络中的数据包!黑客必备技能
1万字30张图说清TCP协议
TCP/IP协议漏洞如此之多?
TCP/IP协议栈在Linux内核中的运行时序分析
linux服务器编程之网络连接断掉之后,究竟会发生什么···
两分钟,帮你搞懂光纤接头
作者动态 更多
多线程时如何使用CPU缓存?
2天前
国内IT行业58家外包公司,有多少程序员在里面待过?
2天前
高质量C语言的开发技巧
2天前
高质量嵌入式软件的开发技巧
5天前
ZYNQ QSPI flash分区设置&启动配置
1星期前

linux服务器编程之网络连接断掉之后,究竟会发生什么···

连接正常结束:四次挥手,好好告别

1)序号(sequence number):Seq序号,占32位,用来标识从TCP源端向目的端发送的字节流,发起方发送数据时对此进行标记。

2)确认号(acknowledgement number):Ack序号,占32位,只有ACK标志位为1时,确认序号字段才有效,Ack=Seq+1。

3)标志位(Flags):共6个,即URG、ACK、PSH、RST、SYN、FIN。具体含义如下:

ACK:确认序号有效。

RST:重置连接。

SYN:发起一个新连接。

FIN:释放一个连接。

为何建立连接时一起传输,释放连接时却要分开传输?

建立连接时,被动方服务器端结束CLOSED阶段进入“握手”阶段并不需要任何准备,可以直接返回SYN和ACK报文,开始建立连接。释放连接时,被动方服务器,突然收到主动方客户端释放连接的请求时并不能立即释放连接,因为还有必要的数据需要处理,所以服务器先返回ACK确认收到报文,经过CLOSE-WAIT阶段准备好释放连接之后,才能返回FIN释放连接报文。

为什么客户端在TIME-WAIT阶段要等2MSL?

为的是确认服务器端是否收到客户端发出的ACK确认报文

当客户端发出最后的ACK确认报文时,并不能确定服务器端能够收到该段报文。所以客户端在发送完ACK确认报文之后,会设置一个时长为2MSL的计时器。MSL指的是Maximum Segment Lifetime:一段TCP报文在传输过程中的最大生命周期。2MSL即是服务器端发出为FIN报文和客户端发出的ACK确认报文所能保持有效的最大时长。

服务器端在1MSL内没有收到客户端发出的ACK确认报文,就会再次向客户端发出FIN报文;

如果客户端在2MSL内,再次收到了来自服务器端的FIN报文,说明服务器端由于各种原因没有接收到客户端发出的ACK确认报文。客户端再次向服务器端发出ACK确认报文,计时器重置,重新开始2MSL的计时;否则客户端在2MSL内没有再次收到来自服务器端的FIN报文,说明服务器端正常接收了ACK确认报文,客户端可以进入CLOSED阶段,完成“四次挥手”。

所以,客户端要经历时长为2SML的TIME-WAIT阶段;这也是为什么客户端比服务器端晚进入CLOSED阶段的原因。

这些东西毕竟都是停留在理论层面的,实际的场景可比这要错综复杂的多了。

故障模式

网络中断

如果网络发生了中断,那就不用提什么“主动关闭”,什么“FIN”包了。TCP程序也并不能感应到连接异常,除非路由器发出一条ICMP报文,说明目的网络或主机不可达;或者说通过read或write调用才会返回UNreachable的错误。

可惜大多数时候并不是如此,在没有 ICMP 报文的情况下,TCP 程序并不能理解感应到连接异常。如果程序是阻塞在 read 调用上,那么很不幸,程序无法从异常中恢复。

如果程序先调用了 write 操作发送了一段数据流,接下来阻塞在 read 调用上,结果会非常不同。Linux 系统的 TCP 协议栈会不断尝试将发送缓冲区的数据发送出去,大概在重传 12 次、合计时间约为 9 分钟之后,协议栈会标识该连接异常,这时,阻塞的 read 调用会返回一条 TIMEOUT 的错误信息。如果此时程序还执着地往这条连接写数据,写操作会立即失败,返回一个 SIGPIPE 信号给应用程序。

而一旦返回了这种信号,进程就会被终止掉了。也就是我们常说的,程序崩了。

对端有 FIN 包发出

这种情况呢,是比较常见的了,至少在我这里是比较常见的,一般不会造成太恶劣的影响,除非在同一时间内有大批量的连接断开,那会占用很多的资源的。

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

阻塞的 read 操作在完成正常接收的数据读取之后,FIN 包会通过返回一个 EOF 来完成通知,此时,read 调用返回值为 0。这里强调一点,收到 FIN 包之后 read 操作不会立即返回。你可以这样理解,收到 FIN 包相当于往接收缓冲区里放置了一个 EOF 符号,之前已经在接收缓冲区的有效数据不会受到影响。

服务器断开

注意如果我们的速度不够快,导致服务器端从睡眠中苏醒,并成功将报文发送出来后,客户端会正常显示,此时我们停留,等待标准输入。如果不继续通过 read 或 write 操作对套接字进行读写,是无法感知服务器端已经关闭套接字这个事实的。

声明:本内容为作者独立观点,不代表电子星球立场。未经允许不得转载。授权事宜与稿件投诉,请联系:editor@netbroad.com
觉得内容不错的朋友,别忘了一键三连哦!
赞 3
收藏 2
关注 172
成为作者 赚取收益
全部留言
0/200
成为第一个和作者交流的人吧