java知识扩展,偏应用型,建议有Java基础者看。(一)

课内容以及一些周边知识的扩展,不妥之处望批评指正。

 

前置问题:当app访问服务器,服务器出现宕机,立刻关闭重启会出现报错说端口被占用,过几秒后重连就会好,但是不久后又会宕机或出现问题。

 

 

TCP/UDP协议:

 

 

TCP:面向连接、传输可靠(保证数据正确性,保证数据顺序)、用于传输大量数据(流模式)、速度慢,建立连接需要开销较多(时间,系统资源)。

 

UDP:面向非连接、传输不可靠、用于传输少量数据(数据包模式)、速度快。

 

这里重点讲TCP,下面安利TCP的三次握手

1 主机A通过向主机B 发送一个含有同步序列号的标志位的数据段给主机B,向主机B 请求建立连接,通过这个数据段,主机A告诉主机B 两件事,我想要和你通信

你可以用哪个序列号作为起始数据段来回应我。

2 主机B 收到主机A的请求后,用一个带有确认应答(ACK)和同步序列号(SYN)标志位的数据段响应主机A,也告诉主机A两件事:我已经收到你的请求了,你可以

传输数据了,你要用哪个序列号作为起始数据段来回应我。

3 主机A收到这个数据段后,再发送一个确认应答,确认已收到主机B 的数据段,我已收到回复,我现在要开始传输实际数据了。
 

ACK  TCP报头的控制位之一,对数据进行确认,确认由目的端发出,用它来告诉发送端这个序列号之前的数据段都收到了。比如,确认号为X,则表示前X-1个数

据段都收到了,只有当ACK=1时,确认号才有效,当ACK=0时,确认号无效,这时会要求重传数据,保证数据的完整性。

SYN  同步序列号,TCP建立连接时将这个位置1,会随着指令的来回递增,当溢出时会重新建立连接或者置1。

 

but!!!TCP建立连接要进行3次握手,而断开连接要进行4次

1 当主机A完成数据传输后,将控制位FIN置1,提出停止TCP连接的请求。

2  主机B收到FIN后对其作出响应,确认这一方向上的TCP连接将关闭,将ACK置1。

3 由B 端再提出反方向的关闭请求,将FIN置1。

4 主机A对主机B的请求进行确认,将ACK置1,双方向的关闭结束。


FIN  发送端完成发送任务位,当TCP完成数据传输需要断开时,提出断开连接的一方将这位置1。

 

下面就是问题的重点所在了,CLOSE_WAIT和TIME_WAIT  

客户端TCP状态迁移:

CLOSED->SYN_SENT->ESTABLISHED->FIN_WAIT_1->FIN_WAIT_2->TIME_WAIT->CLOSED

服务器TCP状态迁移:

CLOSED->LISTEN->SYN收到->ESTABLISHED->CLOSE_WAIT->LAST_ACK->CLOSED

当客户端开始连接时,服务器还处于LISTENING,客户端发一个SYN包后,他就处于SYN_SENT状态,服务器就处于SYS收到状态,然后互相确认进入连接状态

ESTABLISHED.

1、LISTENING状态

服务启动后首先处于侦听(LISTENING)状态。

2、ESTABLISHED状态

ESTABLISHED的意思是建立连接。表示两台机器正在通信。


3、CLOSE_WAIT

对方主动关闭连接或者网络异常导致连接中断,这时我方的状态会变成CLOSE_WAIT 此时我方要调用close()来使得连接正确关闭

4、TIME_WAIT

我方主动调用close()断开连接,收到对方确认后状态变为TIME_WAIT,缺省为240秒。TCP协议规定TIME_WAIT状态会一直持续2MSL(即两倍的分段最大生存

期),以此来确保旧的连接状态不会对新连接产生影响。处于TIME_WAIT状态的连接占用的资源不会被内核释放,所以作为服务器,在可能的情况下,尽量不要主

动断开连接,以减少TIME_WAIT状态造成的资源浪费。

TCP协议规定,对于已经建立的连接,网络双方要进行四次握手才能成功断开连接,如果缺少了其中某个步骤,将会使连接处于假死状态,连接本身占用

的资源不会被释放。网络服务器程序要同时管理大量连接,所以很有必要保证无用连接完全断开,否则大量僵死的连接会浪费许多服务器资源。

在断开连接的时候, 当发起主动关闭的左边这方发送一个FIN过去后,右边被动关闭的这方要回应一个ACK,这个ACK是TCP回应的,而不是应用程序发送的,此

时,被动关闭的一方就处于CLOSE_WAIT状态了。如果此时被动关闭的这一方不再继续调用closesocket,那么他就不会发送接下来的FIN,导致自己老是处于

CLOSE_WAIT。只有被动关闭的这一方调用了closesocket,才会发送一个FIN给主动关闭的这一 方,同时也使得自己的状态变迁为LAST_ACK。出现大量

CLOSE_WAIT的原因很简单,就是某一方在网络连接断开后,没有检测到这个错误,没有执行closesocket,导致了这个状态的实现,这在TCP/IP协议的状态变

迁。同时和这个相对应的还有一种叫TIME_WAIT的。一端的Socket调用close后,另一端的Socket没有调用close。

 

分析问题:

这个问题主要因为TCP的结束流程未走完,造成连接未释放。现设客户端主动断开连接,流程如下


Client 消息 Server

close()
------ FIN ------->
FIN_WAIT1 CLOSE_WAIT
<----- ACK -------
FIN_WAIT2 
close()
<------ FIN ------ 
TIME_WAIT LAST_ACK

------ ACK -------> 
CLOSED
CLOSED

如上所示,由于Server的Socket在客户端已经关闭时而没有调用关闭,造成服务器端的连接处在“挂起”状态,而客户端则处在等待应答的状态上。此问题的典型特

征是:一端处于FIN_WAIT2 ,而另一端处于CLOSE_WAIT。由于基于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不会太费时间,但是有这么多状态要维护总是不好。

 

解决方案:

1.客户端判断是否接受完整数据并及时close。

2.服务器端HTTP协议1.1版规定default行为是Keep-Alive,也就是会重用TCP连接传输多个request/response,一个主要原因就是发现了这个问题。还有一个方法减

缓TIME_WAIT压力就是把系统的2*MSL时间减少。

3.将linux的进程数量改大。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值