哈尔滨优化网站方法,青海最好的网站建设公司,怀化同城网站,哪里的郑州网站建设一、tcp链接中的正常四次挥手过程#xff1f; 刚开始双方都处于 ESTABLISHED 状态#xff0c;假如是客户端先发起关闭请求。四次挥手的过程如下#xff1a;
1、客户端打算关闭连接#xff0c;此时会发送一个 TCP 首部 FIN 标志位被置为 1 的报文#xff0c;也即 FIN 报文…一、tcp链接中的正常四次挥手过程 刚开始双方都处于 ESTABLISHED 状态假如是客户端先发起关闭请求。四次挥手的过程如下
1、客户端打算关闭连接此时会发送一个 TCP 首部 FIN 标志位被置为 1 的报文也即 FIN 报文之后客户端进入 FIN_WAIT_1 状态。2、接着当服务端在 read 数据的时候最后⾃然就会读到 EOF接着 read() 就会返回 0这时服务端应⽤程序如果有数据要发送的话就发完数据后才调⽤关闭连接的函数如果服务端应⽤程序没有数据要发送的话可以直接调⽤关闭连接的函数这时服务端就会发⼀个 FIN 包这个 FIN 报⽂代表服务端不会再发送数据了之后处于 LAST_ACK 状态。 3、客户端收到服务端的 ACK 应答报文后之后进入 FIN_WAIT_2 状态。 4、等待服务端处理完数据后也向客户端发送 FIN 报文之后服务端进入 LAST_ACK 状态。 5、客户端收到服务端的 FIN 报文后回一个 ACK 应答报文之后进入 TIME_WAIT 状态 6、服务端收到了 ACK 应答报文后就进入了 CLOSE 状态至此服务端已经完成连接的关闭。 7、客户端在经过 2MSL 一段时间后自动进入 CLOSE 状态至此客户端也完成连接的关闭。 你可以看到每个方向都需要一个 FIN 和一个 ACK因此通常被称为四次挥手。
这里一点需要注意是主动关闭连接的才有 TIME_WAIT 状态。
二、为什么挥手需要四次
服务器收到客户端的 FIN 报⽂时内核会⻢上回⼀个 ACK 应答报⽂但是服务端应⽤程序可能还有数据要发送所以并不能⻢上发送 FIN 报⽂⽽是将发送 FIN 报⽂的控制权交给服务端应⽤程序
1、关闭连接时客户端向服务端发送 FIN 时仅仅表示客户端不再发送数据了但是还能接收数据。 2、服务端收到客户端的 FIN 报文时先回一个 ACK 应答报文而服务端可能还有数据需要处理和发送等服务端不再发送数据时才发送 FIN 报文给客户端来表示同意现在关闭连接。
从上⾯过程可知是否要发送第三次挥⼿的控制权不在内核⽽是在被动关闭⽅上图的服务端的应⽤程序因为应⽤程序可能还有数据要发送由应⽤程序决定什么时候调⽤关闭连接的函数当调⽤了关闭连接的函数内核就会发送 FIN 报⽂了所以服务端的 ACK 和 FIN ⼀般都会分开发送。 FIN 报⽂⼀定得调⽤关闭连接的函数才会发送吗不一定 如果进程退出了不管是不是正常退出还是异常退出如进程崩溃内核都会发送 FIN 报⽂与对⽅完成四次挥⼿。
三、粗暴关闭 vs 优雅关闭
前⾯介绍 TCP 四次挥⼿的时候并没有详细介绍关闭连接的函数其实关闭的连接的函数有两种函数
close 函数同时 socket 关闭发送⽅向和读取⽅向也就是 socket 不再有发送和接收数据的能⼒。如果有多进程/多线程共享同⼀个 socket如果有⼀个进程调⽤了 close 关闭只是让 socket 引⽤计数-1并不会导致 socket 不可⽤同时也不会发出 FIN 报⽂其他进程还是可以正常读写该 socket 直到引⽤计数变为 0才会发出 FIN 报⽂。shutdown 函数可以指定 socket 只关闭发送⽅向⽽不关闭读取⽅向也就是 socket 不再有发送数据的能⼒但是还是具有接收数据的能⼒。如果有多进程/多线程共享同⼀个 socketshutdown 则不 管引⽤计数直接使得该socket 不可⽤然后发出 FIN 报⽂如果有别的进程企图使⽤该 socket 将会受到影响。
如果客户端是⽤ close 函数来关闭连接那么在 TCP 四次挥⼿过程中如果收到了服务端发送的数据由于客户端已经不再具有发送和接收数据的能⼒所以客户端的内核会回 RST 报⽂给服务端然后内核会释放连接这时就不会经历完成的 TCP 四次挥⼿所以我们常说调⽤ close 是粗暴的关闭。 当服务端收到 RST 后内核就会释放连接当服务端应⽤程序再次发起读操作或者写操作时就能感知到连接已经被释放了
如果是读操作则会返回 RST 的报错也就是我们常⻅的Connection reset by peer。如果是写操作那么程序会产⽣ SIGPIPE 信号应⽤层代码可以捕获并处理信号如果不处理则默 认情况下进程会终⽌异常退出。
相对的shutdown 函数因为可以指定只关闭发送⽅向⽽不关闭读取⽅向所以即使在 TCP 四次挥⼿过程中如果收到了服务端发送的数据客户端也是可以正常读取到该数据的然后就会经历完整的 TCP 四次挥⼿所以我们常说调⽤ shutdown 是优雅的关闭。 但是注意shutdown 函数也可以指定「只关闭读取⽅向⽽不关闭发送⽅向」但是这时候内核是不会发送 FIN 报⽂的因为发送 FIN 报⽂是意味着我⽅将不再发送任何数据⽽ shutdown 如果指定「不关闭发送⽅向」就意味着 socket 还有发送数据的能⼒所以内核就不会发送 FIN。
四、什么情况会出现三次挥⼿
当被动关闭⽅上图的服务端在 TCP 挥⼿过程中「没有数据要发送」并且「开启了 TCP 延迟确认机制」那么第⼆和第三次挥⼿就会合并传输这样就出现了三次挥⼿。 然后因为 TCP 延迟确认机制是默认开启的所以导致我们抓包时看⻅三次挥⼿的次数⽐四次挥⼿还多。 什么是 TCP 延迟确认机制 当发送没有携带数据的 ACK它的⽹络效率也是很低的因为它也有 40 个字节的 IP 头 和 TCP 头但却没有携带数据报⽂。为了解决 ACK 传输效率低问题所以就衍⽣出了 TCP 延迟确认。
TCP 延迟确认的策略
当有响应数据要发送时ACK 会随着响应数据⼀起⽴刻发送给对⽅当没有响应数据要发送时ACK 将会延迟⼀段时间以等待是否有响应数据可以⼀起发送如果在延迟等待发送 ACK 期间对⽅的第⼆个数据报⽂⼜到达了这时就会⽴刻发送 ACK