学习笔记:从TCP的挥手角度看shutdown函数

TCP断开连接的过程被称为“挥手”。

 

不管是服务端还是客户端,都可以主动发起关闭连接的过程(响应的另一端就是被动关闭连接)。

正常的主动关闭连接的过程如下:

A应用程序调用shutdown(socket, SD_SEND); 此函数是说:我要发送的数据已经全部提交给socket系统了,请关闭此socket连接。如果我脑子糊涂了,继续发send()函数,请打我脸。但是A应用程序还应当继续调用recv(),一个目的是把B应用程序发过来或将要发过来的数据收取下来。另一个目的是收取EOF标志,表示B应用程序已经正常的关闭了TCP连接。那么在我调用shutdown(socket, SD_SEND);和recv()函数(假设是阻塞的,recv还未返回)之间的时间,系统发生了什么事件呢?A系统尝试把发送缓冲区的数据发给B端,然后发送FIN报文给B,通知B尽快关闭连接。A系统进入FIN_WATI_1状态,顾名思义,是等待B的FIN报文。B系统瞬间就收到发自A系统的FIN报文。B系统毫不犹豫的回复ACK,A系统瞬间收到ACK报文,进入FIN_WAIT_2状态。然后B系统拖拖沓沓的业务数据来到A系统,这些都被A的recv()拿到,但是只要不是EOF,A就继续调用recv()函数。然后终于B发送了FIN报文,A瞬间收到,recv()函数返回EOF。A松了一口气,心想总算把B的最后哪些迟到的数据收干净了,然后发个ACK给B系统,告诉B我收到FIN了,拜拜了。然后A系统没有进入CLOSED状态,而是进入了让人胆战心惊的TIME_WAIT状态。设置这个状态的原因是:万一最后一个ACK消息,B没有收到。B可能会重发FIN或者RST,这些消息将直接影响相同端口号的socket状态机。TIME_WAIT就是等待超时(2MSL秒),这是时间是A系统认为的一个TCP消息在网络上流浪的最大时间,超过此时间,则流浪的消息会消失。TIME_WAIT状态会临时占用一些端口号为不可用状态,这是个好设计。不好的地方在于,当今网络2MSL秒数大幅减小,而业务量猛增,系统(特别是安装了http服务程序的)将出现大量TIME_WAIT不可用的端口号。最后,A应用程序应调用closesocket()函数,回收socket资源。

被动的关闭连接的过程如下:

B系统收到FIN包(此时B系统的socket状态变成CLOSE_WAIT,还顺手发了个ACK),B应用程序在调用recv函数时,收到EOF(这是告诉应用程序收到FIN包了)。B心想A要跑路呀。然后尽快调用send()函数,把自己要给A说千言万语投递给系统。然后调用closesocket()函数,等待系统处理。B系统把千言万语发送出去后,再发个FIN包。B系统进入LAST_ACK状态,就是等待ACK。如果没等到就再发个FIN或RST,反正向外发个东西,自己不损失什么。但是这个多发的消息可能给A造成困扰(所以A系统设计的TIME_WAIT防御这个事)。当B系统收到ACK后,进入CLOSED状态。

另外,TIME_WAIT是正常状态,也可以通过系统配置,让这个状态尽快转移到CLOSED。而CLOSE_WAIT是需要引起警惕的状态,此状态需要应用程序调用关闭TCP连接的函数才能走过去。如果大量长期出现此状态,要检查是否忘记调用shutdown或closesocket函数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值