网络IO的工作机制
数据从一台主机发送到网络中的另外一台主机需要经过很多步骤。首先需要有相互沟通的意向。其次要有能够沟通的物理渠道(物理链路):是通过电话,还是直接面对面交流。再次,双方见面时语言要能够交流,而且双方说话的步调要一致,明白什么时候该自己说话,什么时候该对方说话(通信协议)。重点介绍通信协议和如何完成数据传输。
1.TCP状态转化
(1)CLOSED:起始点,在超时或者链接关闭的时候进入此状态。
(2)LISTEN:Server端在等待链接时的状态,Server端为此要调用Socket,bind,listen函数,就能进入此状态。这称为应用程序被动打开(等待客户端来连接)
(3)SYN-SENT:客户端发起连接,发送SYN给服务器端。如果服务器端不能链接,则直接进入CLOSED状态。
(4)SYN-RCVD:与3对应,服务器端接受客户端的SYN请求,服务器端由LISTEN状态进入SYN_RCVD状态。同时服务器端需要回应一个ACK,发送一个SYN给客户端;另外一种情况是,客户端发起SYN的同时接收到服务器端的SYN请求,客户端由SYN-SENT转换到SYN-RCVD状态。
(5)ESTALBLISHED:服务器端和客户端在完成3次握手后进入状态,说明可以开始传输数据了。
(6)FIN-WAIT-1:主动关闭一方,由状态5进入此状态。具体动作是发送FIN给对方。
(7)FIN-WAIT-2:主动关闭一方,接收到对方的FIN ACK ,进入此状态。此状态不能再接收对方的数据,但是能够向对方发送数据。
(8)CLOSE-WAIT :接收到FIN以后,被动关闭的一方进入此状态。具体动作是在接收到FIN的同时发送ACK。
(9)LAST-ACK:被动关闭的一方,发起关闭请求,由状态8进入此状态。具体动作是发送FIN给对方,同时在接收到ACK时进入CLOSED状态。
(10)CLOSING:两边同时发起关闭请求时,会由FIN-WAIT-1进入此状态。具体动作是接收到FIN请求,同时响应一个ACK。
(11)TIME-WAIT:这个状态比较复杂,也是我们最常见的一个连接状态,有3个状态可以转化为此状态。
由FIN-WAIT2转化到TIME-WAIT,具体情况是:在双发不同时发起FIN的情况下,主动关闭的一方在完成自身发起的关闭请求后,接收到被动关闭一方的FIN后进入的状态。
由CLOSING转换到TIME-WAIT,具体情况是:在双方同时发起关闭,都做了发起FIN的请求,同时收到了FIN并做了ACK的情况下,这时就由CLOSING状态进入TIME-WAIT状态
由FIN-WAIT-1转换到TIME-WAIT,具体情况是:同时接收到FIN(对方发起)和ACK(本身发起的FIN回应),它与CLOSING转换到TIME-WAIT的区别在于本身发起的FIN回应的ACK先于对方的FIN请求到达,而由CLOSING转换到TIME-WAIT则是FIN先到达。
搞清楚TCP链接的几种状态转换堆我们调试网络程序是非常有帮助的。例如:我们在压测一个网络程序时可能遇到CPU、网卡,宽带等都不是瓶颈,但是性能就是压不上去的情况,你如果观察一下网络链接情况,看看当前的网络链接都处于什么状态,可能会发现由于网络链接的并发数不够导致连接都处于TIME_WAIT状态,这个时候就要做TCP网络参数调优了。
2.影响网络传输的因素
将一份数据从一个地方政权的传输到另一个地方所需要的实际我们称之为响应时间,影响这个响应时间的因素有很多。
1.网络带宽:所谓网络带宽就是一条物理链路在1s内能够传输到最大比特数,注意这里是比特,不是字节数。我就遇到过因为带宽过低,为了不影响业务,导致日志采集数据运送延迟几个小时的情况。
2.传输距离:也就是数据在光纤中要走的距离,虽然光的传播速度很快,但也是有时间的,由于数据在光线中的移动并不是走直线的,会有一个折射率,所以大概是光的2/3,这个时间也就是我们通常所说的传输延迟。传输延迟是一个无法避免的问题,例如:你在北京和香港的两个机房的一个数据库进行同步数据操作,那么必定会存在30ms的一个延迟。
3.TCP拥塞控制:我们知道TCP传输是一个“停-等-停-等”的协议,传输方和接受方的不掉要一致,达到步调一致就要通过拥塞控制来调节。TCP在传输时会设定一个“窗口(BDP,Bandwidth Delay Product)",这个窗口的大小是由带宽和TTT(Round-Trip Time,数据在两端的来回时间,也就是响应时间)决定的。计算公式是带宽(b/s)x RTT(s)。通过这个可以得出理论最优的TCP缓冲区的大小。Linux 2.4已经可以自动地调整发送端的缓冲区的大小,而Linux2.6.7时接收端也可以自动调整了。
参考《深入JAVAWEB技术分析》