菜鸟笔记
提升您的技术认知

四次挥手中time-ag真人游戏

先给出四次挥手过程中c/s的状态变化示意图。有了图理解起来就容易许多。

time_wait 表示主动关闭,close_wait 表示被动关闭。

close_wait状态的生成原因
首先我们知道,如果ag真人游戏的服务器程序apache处于close_wait状态的话,说明套接字是被动关闭的!

因为如果是client端主动断掉当前连接的话,那么双方关闭这个tcp连接共需要四个packet:

      client --->  fin  --->  server 

      client <---  ack  <---  server 

 这时候client端处于fin_wait_2状态;而server 程序处于close_wait状态。

      client <---  fin  <---  server 

这时server 发送fin给client,server 就置为last_ack状态。

       client --->  ack  --->  server 

client回应了ack,那么server 的套接字才会真正置为closed状态。

server 程序处于close_wait状态,而不是last_ack状态,说明还没有发fin给client,那么可能是在关闭连接之前还有许多数据要发送或者其他事要做,导致没有发这个fin packet。

客户端主动关闭时,发出fin包,收到服务器的ack,客户端停留在fin_wait2状态。而服务端收到fin,发出ack后,停留在colse_wait状态。     这个close_wait状态非常讨厌,它持续的时间非常长,服务器端如果积攒大量的colse_wait状态的socket,有可能将服务器资源(套接字描述符耗尽)耗尽,进而无法提供服务。     那么,服务器上是怎么产生大量的失去控制的colse_wait状态的socket呢?

我们来追踪一下。     一个很浅显的原因是,服务器没有继续发fin包给客户端。    

服务器为什么不发fin,可能是业务实现上的需要,现在不是发送fin的时机,因为服务器还有数据要发往客户端,发送完了自然就要通过系统调用发fin了,这个场景并不是上面我们提到的持续的colse_wait状态,这个在受控范围之内。    

那么究竟是什么原因呢,咱们引入两个系统调用close(sockfd)和shutdown(sockfd,how)接着往下分析。    

在这儿,需要明确的一个概念---- 一个进程打开一个socket,然后此进程再派生子进程的时候,此socket的sockfd会被继承。

socket是系统级的对象,现在的结果是,此socket被两个进程打开,此socket的引用计数会变成2。      

继续说上述两个系统调用对socket的关闭情况。     调用close(sockfd)时,内核检查此fd对应的socket上的引用计数。如果引用计数大于1,那么将这个引用计数减1,然后返回。如果引用计数等于1,那么内核会真正通过发fin来关闭tcp连接。    

调用shutdown(sockfd,shut_rdwr)时,内核不会检查此fd对应的socket上的引用计数,直接通过发fin来关闭tcp连接。        

现在应该真相大白了,可能是服务器的实现有点问题,父进程打开了socket,然后用派生子进程来处理业务,父进程继续对网络请求进行监听,永远不会终止。客户端发fin过来的时候,处理业务的子进程的read返回0,子进程发现对端已经关闭了,直接调用close()对本端进行关闭。

实际上,仅仅使socket的引用计数减1,socket并没关闭。从而导致系统中又多了一个close_wait的socket。。。   如何避免这样的情况发生? 子进程的关闭处理应该是这样的: shutdown(sockfd, shut_rdwr); close(sockfd);

这样处理,服务器的fin会被发出,socket进入last_ack状态,等待最后的ack到来,就能进入初始状态closed 最后加上点干货(从百度百科上看到关于fin_wait_1和fin_wait_2的理解。)

其实fin_wait_1和fin_wait_2状态的真正含义都是表示等待对方的fin报文。

而这两种状态的区别是:fin_wait_1状态实际上是当socket在established状态时,它想主动关闭连接,向对方发送了fin报文,此时该socket即进入到fin_wait_1状态。

而当对方回应ack报文后,则进入到fin_wait_2状态,当然在实际的正常情况下,无论对方何种情况下,都应该马上回应ack报文,所以fin_wait_1状态一般是比较难见到的,而fin_wait_2状态还有时常常可以用netstat看到。

网站地图