分析过程:根据TCP建立连接和断开连接的过程,如下图:
close wait状态一般是在服务端出现的。执行:ss -tnp | grep CLOSE-WAIT | wc -l命令可查看有多少close wait连接状态;执行:ss -tnp | grep CLOSE-WAIT | more,根据第三、四列可以看出,由谁向谁发起socket连接(客户端发起请求的端口是随机的,服务端提供服务的端口比较有规律)。根据TCP断开连接的状态变换过程,基本可以判断close wait堆积是因为客户端发出FIN包,服务端回了ACK包,但是服务端没发出FIN包导致。
分析代码后发现,客户端有调用关闭socket方法去主动关闭socket连接,但是服务端没有调用关闭socket方法发送FIN包结束连接,导致服务端大量close wait堆积。
解决方法:服务端加上调用关闭socket方法发送FIN给客户端。上新版本后,连续几天到服务端执行ss -tnp | grep CLOSE-WAIT | wc -l命令,没发现有大量close wait了。
另附如下tcp连接相关内容:
TCP建立连接(三次握手)都是由客户端发起的,但是断开连接视情况而定。一般由客户端主动断开连接比较好,因为由服务端发起断开连接,服务器会产生time-wait状态的连接,而time wait占用的资源不会被内核释放。SSH、数据库等断开连接由客户端主动发起,如果超时了,断开连接可能由服务端发起。
HTTP(S)断开连接有时由服务端主动发起,如下情况:
1、客户端请求头带content-length时,响应体body长度可知,接收完数据后,客户端主动断开连接
2、响应头中的Transfer-encoding为chunked传输,body会被分成多个块,每块的开始会标识出当前块的长度,body就不需要通过content-length来指定了。也可以知道body的长度,客户端主动断开连接
3、响应头中的Transfer-encoding为非chunked传输,而且有content-length,则按照content-length来接收数据,接收完数据后,客户端主动断开连接
4、响应头中的Transfer-encoding非chunked且不带content-length,客户端无法知道要接收多少数据,直到服务端主动断开连接。
即 :如果客户端知道服务器传来的长度,客户端在接收完成后,会主动断开;如果不知道,客户端就一直接收数据,直到服务端断开连接。
在TCP的三次握手、数据传输以及四次挥手的过程中,给Client和Server定义了很多状态用于描述整个流程,结合上面的状态转换图来理解这些状态定义:
- LISTEN(Server): 正在侦听来自Client的TCP端口的连接请求,服务端启动后处于LISTEN 状态用于监听不同客户端的TCP请求并建立连接
- SYN-SENT(Client): 三次握手时,Client在发送SYN后处于等待建立连接的状态
- SYN_RCVD(Server):三次握手时,当Server收到Client的SYN时,将ACK和SYN发送给 Client后到建立连接之前,Server处于SYN_RCVD状态
- ESTABLISHED(Server And Client):三次握手成功以后,Client和Server处于数据传输的状态
- FIN-WAIT-1(Client):四次挥手时,Client 端发送中断请求FIN到收到Server端的中断确认的过程
- CLOSE_WAIT(Server):四次挥手时,Server接收到Client的FIN请求后回复ACK确认到发送FIN包的状态
- FIN-WAIT-2(Client):四次挥手时,当Client接收到Server对于FIN的响应ACK后到收到 Server端的FIN包的状态
- LAST_ACK(Server):四次挥手时,Server发送FIN请求关闭连接到关闭连接前的状态
- TIME_WAIT(Client):四次挥手时,Client对于Server的FIN回复ACK到连接关闭前的状态,又称 2MSL 状态
- CLOSE(Server And Client):Server和CLient关闭连接后的状态
客户端的状态转换流程如下:
大部分情况下:CLOSED -> SYN_SENT -> ESTABLISHED -> FIN_WAIT_1 -> FIN_WAIT_2 -> TIME_WAIT -> CLOSED
少数情况:CLOSED -> SYN_SENT -> ESTABLISHED -> CLOSE_WAIT -> LAST_ACK -> CLOSED
服务端的状态转换流程如下:
大部分情况下:CLOSED -> LISTEN -> SYN_RCVD -> ESTABLISHED -> CLOSE_WAIT -> LAST_ACK -> CLOSED
少数情况:CLOSED -> LISTEN -> SYN_RCVD -> ESTABLISHED -> FIN_WAIT_1 -> FIN_WAIT_2 -> TIME_WAIT -> CLOSED
为何服务器上存在CLOSE_WAIT?文章来源:https://www.toymoban.com/news/detail-464069.html
- 在数据库连接过程中,客户端(或发起请求的应用)提交或回滚事务时,忘记关闭(即没发送FIN)与数据库的连接,导致数据库因为连接超时而主动关闭连接(即数据库主动发送FIN),此时,发起请求的应用服务器(客户端),就会出现大量CLOSE_WAIT状态。
- 例2,客户端发送了FIN,但是服务端忙于读或者写(处理未完成的客户端请求),没有及时发送FIN,此时可能会有少量的close wait。代码需要判断socket连接,一旦读到0,断开连接。
总之,被动关闭的一方(一般是服务端)要调用关闭 socket方法,才会发送FIN给主动关闭的一方(一般是客户端),自己的状态才会变LAST_ACK。文章来源地址https://www.toymoban.com/news/detail-464069.html
到了这里,关于TCP close-wait 状态分析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!