TCP/IP 状态

http://blog.csdn.net/whuslei/article/details/6667471/


三次握手

TCP/IP 状态



四次挥手

TCP/IP 状态


主动fin Client端所经历的状态如下:

TCP/IP 状态

Server端所经历的过程如下

TCP/IP 状态

【问题1】为什么连接的时候是三次握手,关闭的时候却是四次握手?
答:因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,"你发的FIN报文我收到了"。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。

【问题2】为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?

答:虽然按道理,四个报文都发送完毕,我们可以直接进入CLOSE状态了,但是我们必须假象网络是不可靠的,有可以最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。


注意红色的子就大概能明白这个过程,其实很简单。


http://skynetdoc.com/?p=67 

1)、LISTEN:首先服务端需要打开一个socket进行监听,状态为LISTEN

2)、SYN_SENT:客户端通过应用程序调用connect进行active open.于是客户端tcp发送一个SYN以请求建立一个连接.之后状态置为SYN_SENT

3)、SYN_RECV:服务端应发出ACK确认客户端的SYN,同时自己向客户端发送一个SYN.之后状态置为SYN_RECV

4)、ESTABLISHED: 代表一个打开的连接,双方可以进行或已经在数据交互了

5)、FIN_WAIT1:主动关闭(active close)端应用程序调用close,于是其TCP发出FIN请求主动关闭连接,之后进入FIN_WAIT1状态

6)、CLOSE_WAIT:被动关闭(passive close)端TCP接到FIN后就发出ACK以回应FIN请求(它的接收也作为文件结束符传递给上层应用程序)并进入CLOSE_WAIT. The remote end has shut down, waiting for the socket to close 等待从本地用户发来的连接中断请求

7)、FIN_WAIT2:主动关闭端接到ACK后,就进入了FIN-WAIT-2

8)、LAST_ACK:被动关闭端一段时间后,接收到文件结束符的应用程序将调用CLOSE关闭连接。这导致它的TCP也发送一个 FIN,等待对方的ACK.就进入了LAST-ACK

9)、TIME_WAIT:在主动关闭端接收到FIN后,TCP就发送ACK包,并进入TIME-WAIT状态

10)、CLOSING: 比较少见./* Both sockets are shut down but we still don't have all our data sent. 等待远程TCP对连接中断的确认 */

11)、CLOSED: 被动关闭端在接受到ACK包后,就进入了closed的状态。连接结束./* The socket is not being used. 没有任何连接状态 */

状态图

TCP/IP 状态

TCP/IP 状态


实际案例

TCP keepalive VS socket keepalive VS http keepalive

http://www.cnblogs.com/my_life/articles/4522338.html

TCP/IP 状态

TCP层是没有请求的概念,HTTP协议是事务 性协议才有请求的概念,TCP报文承载HTTP协议的请求(Request)和响应(Response)


TCP/IP 状态

如果Client端把请求发送给Nginx,Nginx的后端 需要一段时间才能返回结果,超过1分30秒就会有问题,使用LVS作为负载均衡设备看到的现象就是1分30秒之后, Client和Nginx链接被断开,没有数据返回

In this case, you can decrease TCP keepalive parameter to workround.

原因是LVS默认保持TCP的Session为90s,超过90s没有TCP报文在链接上传输,LVS就会给两端发送RESET报文断开链接

KeepAlive并不是默认开启的,在Linux系统上没有一个全局的选项去开启TCP的KeepAlive。需要开启KeepAlive的应用必须在TCP的socket中单独开启。Linux Kernel有三个选项影响到KeepAlive的行为

1.net.ipv4.tcpkeepaliveintvl = 75
2.net.ipv4.tcpkeepaliveprobes = 9
3.net.ipv4.tcpkeepalivetime = 7200

tcpkeepalivetime的单位是秒,表示TCP链接在多少秒之后没有数据报文传输启动探测报文; tcpkeepaliveintvl单位是也秒,表示前一个探测报文和后一个探测报文之间的时间间隔,tcpkeepaliveprobes表示探测的次数。


TCP socket也有三个选项和内核对应,通过setsockopt系统调用针对单独的socket进行设置:


TCPKEEPCNT: 覆盖 tcpkeepaliveprobes
TCPKEEPIDLE: 覆盖 tcpkeepalivetime
TCPKEEPINTVL: 覆盖 tcpkeepalive_intvl

TCP KeepAlive和HTTP的Keep-Alive是一样的吗?
TCP/IP 状态

开启HTTP Keep-Alive之后,能复用已有的TCP链接


当然通常会启用多个链接去从服务器器 上请求资源,但是开启了Keep-Alive之后,仍然能加快资源的加载速度。HTTP/1.1之后默认开启Keep-Alive, 在HTTP的头域中增加Connection选项。当设置为Connection:keep-alive表示开启,设置为 Connection:close表示关闭。实际上HTTP的KeepAlive写法是Keep-Alive,跟TCP的KeepAlive写法上也有不 同。所以TCP KeepAlive和HTTP的Keep-Alive不是同一回事情


图解http的keep-alive

TCP/IP 状态


TCP保活(TCP keepalive)

http://www.vants.org/?post=162

TCP/IP 状态

TCP保活报文格式:

1, TCP keepalive probe报文

       我们看到,TCP保活探测报文是将之前TCP报文的序列号减1,并设置1个字节,内容为“00”的应用层数据,如下图所示:

TCP/IP 状态


发送keepalive probe报文之前的TCP报文

TCP/IP 状态


 TCP keepalive probe报文

2, TCP keepalive ACK报文

        TCP保活探测确认报文就是对保活探测报文的确认, 其报文格式如下:

TCP/IP 状态

TCP keepalive ACK报文

TCP保活报文交互过程

        TCP保活的交互过程大致如下图所示:

TCP/IP 状态

TCP保活可能带来的问题

1, 中间设备因大量保活连接,导致其连接表满

       网关设备由于保活问题,导致其连接表满,无法新建连接(XX局网闸故障案例)或性能下降严重
2, 正常连接被释放

       当连接一端在发送保活探测报文时,中间网络正好由于各种异常(如链路中断、中间设备重启等)而无法将该保活探测报文正确转发至对端时,可能会导致探测的一方释放本来正常的连接,但是这种可能情况发生的概率较小,另外,一般也可以增加保活探测报文发生的次数来减小这种情况发生的概率和影响



本文转自 liqius 51CTO博客,原文链接:http://blog.51cto.com/szgb17/1632811,如需转载请自行联系原作者

上一篇:vs2013 配置支持https的libcurl


下一篇:Cocos2d-x多场景切换生命周期