CLOSE_WAIT和TIME_WAIT

    tcp状态转移要点<br>tcp协议规定,对于已经建立的连接,网络双方要进行四次握手才能成功断开连接,如果缺少了其中某个步骤,将会使连接处于假死状态,连接本身占用的资源不会被释放。网络服务器程序要同时管理大量连接,所以很有必要保证无用连接完全断开,否则大量僵死的连接会浪费许多服务器资源 
客户端tcp状态迁移:<br>closed->syn_sent->established->fin_wait_1->fin_wait_2->time_wait->closed<br>服务器tcp状态迁移:<br>closed->listen->syn收到->established->close_wait->last_ack->closed<br>当客户端开始连接时,服务器还处于listening,客户端发一个syn包后,他就处于syn_sent状态,服务器就处于sys收到状态,然后互相确认进入连接状态established.
 
1、listening状态<br> 服务启动后首先处于侦听(listening)状态。
2、established状态<br> established的意思是建立连接。表示两台机器正在通信。
<span style="color: #ff0000;">3、close_wait</span>
对方主动关闭连接或者网络异常导致连接中断,这时我方的状态会变成close_wait 此时我方要调用close()来使得连接正确关闭
<span style="color: #ff0000;">4、time_wait</span>
我方主动调用close()断开连接,收到对方确认后状态变为time_wait,缺省为240秒。tcp协议规定time_wait状态会一直持续2msl(即两倍的分段最大生存期),以此来确保旧的连接状态不会对新连接产生影响。处于time_wait状态的连接占用的资源不会被内核释放,所以作为服务器,在可能的情况下,尽量不要主动断开连接,以减少time_wait状态造成的资源浪费。
目前有一种避免time_wait资源浪费的方法,就是关闭socket的linger选项。但这种做法是tcp协议不推荐使用的,在某些情况下这个操作可能会带来错误
 
断开连接的时候, 当发起主动关闭的左边这方发送一个fin过去后,右边被动关闭的这方要回应一个ack,这个ack是tcp回应的,而不是应用程序发送的,此时,被动关闭的一方就处于close_wait状态了。如果此时被动关闭的这一方不再继续调用closesocket,那么他就不会发送接下来的fin,导致自己老是处于close_wait。只有被动关闭的这一方调用了closesocket,才会发送一个fin给主动关闭的这一 方,同时也使得自己的状态变迁为last_ack。
出现大量close_wait的原因很简单,就是某一方在网络连接断开后,没有检测到这个错误,没有执行closesocket,导致了这个状态的实现,这在tcp/ip协议的状态变迁图上可以清楚看到。同时和这个相对应的还有一种叫time_wait的。 <span style="color: #ff0000;">一端的socket调用close后,另一端的socket没有调用close</span>
另外,把socket的so_linger设置为0秒拖延(也就是立即关闭)在很多时候是有害处的。 <br>还有,把端口设置为可复用是一种不安全的网络编程方法
当主动关闭的一方发送fin到被动关闭这边后,被动关闭这边的tcp马上回应一个ack过去,同时向上面应用程序提交一个error,导 致上面的socket的send或者recv返回socket_error,正常情况下,如果上面在返回socket_error后调用了closesocket,那么被动关闭的者一方的tcp就会发送一个fin过去,自己的状态就变迁到last_ack
虚线和实线分别对应服务器端(被连接端)和客户端端(主动连接端)。 结合上图使用netstat -na命令即可知道到当前的tcp连接状态。一般listen、established、time_wait是比较常见。
分析:
这个问题主要因为tcp的结束流程未走完,造成连接未释放。现设客户端主动断开连接,流程如下
client 消息 server
close()<br>------ fin -------><br>fin_wait1 close_wait<br><----- ack -------<br>fin_wait2 <br>close()<br><------ fin ------ <br>time_wait last_ack
------ ack -------> <br>closed<br>closed
如上图所示,由于server的socket在客户端已经关闭时而没有调用关闭,造成服务器端的连接处在“挂起”状态,而客户端则处在等待应答的状态上。此问题的典型特征是: <span style="color: #ff0000;">一端处于fin_wait2 ,而另一端处于close_wait</span>
于基于tcp的http协议,关闭tcp连接的是server端,这样,server端会进入time_wait状态,可 想而知,对于访问量大的web server,会存在大量的time_wait状态,假如server一秒钟接收1000个请求,那么就会积压240*1000=240,000个time_wait的记录,维护这些状态给server带来负担。当然现代操作系统都会用快速的查找算法来管理这些time_wait,所以对于新的tcp连接请求,判断是否hit中一个time_wait不会太费时间,但是有这么多状态要维护总是不好。
  http协议1.1版规定default行为是keep-alive,也就是会重用tcp连接传输多个request/response,一个主要原因就是发现了这个问题。还有一个方法减缓time_wait压力就是把系统的2*msl时间减少,因为240秒的时间实在是忒长了点,对于windows,修改注册表,在hkey_local_machine\ system\currentcontrolset\services\ tcpip\parameters上添加一个dword类型的值tcptimedwaitdelay,一般认为不要少于60,不然可能会有麻烦。
 

你可能感兴趣的:(java,工作)