TCP连接中的状态
1. 正常状态转换
我们用图 3-13 来显示在正常的 TCP 连接的建立与终止过程中,客户与服务器所经历的不同状态。读者可以对照图 3-12 来阅读,使用图 3-12 的状态图来跟踪图 3-13 的状态变化过程,以便明白每个状态的变化:
-
服务器端首先执行 LISTEN 原语进入被动打开状态( LISTEN ),等待客户端连接;
-
当客户端的一个应用程序发出 CONNECT 命令后,本地的 TCP 实体为其创建一个连接记录并标记为 SYN SENT 状态,然后给服务器发送一个 SYN 报文段;
-
服务器收到一个 SYN 报文段,其 TCP 实体给客户端发送确认 ACK 报文段同时发送一个 SYN 信号,进入 SYN RCVD 状态;
-
客户端收到 SYN + ACK 报文段,其 TCP 实体给服务器端发送出三次握手的最后一个 ACK 报文段,并转换为 ESTABLISHED 状态;
-
服务器端收到确认的 ACK 报文段,完成了三次握手,于是也进入 ESTABLISHED 状态。
在此状态下,双方可以自由传输数据。当一个应用程序完成数据传输任务后,它需要关闭 TCP 连接。假设仍由客户端发起主动关闭连接。
-
客户端执行 CLOSE 原语,本地的 TCP 实体发送一个 FIN 报文段并等待响应的确认(进入状态 FIN WAIT 1 );
-
服务器收到一个 FIN 报文段,它确认客户端的请求发回一个 ACK 报文段,进入 CLOSE WAIT 状态;
-
客户端收到确认 ACK 报文段,就转移到 FIN WAIT 2 状态,此时连接在一个方向上就断开了;
-
服务器端应用得到通告后,也执行 CLOSE 原语关闭另一个方向的连接,其本地 TCP 实体向客户端发送一个 FIN 报文段,并进入 LAST ACK 状态,等待最后一个 ACK 确认报文段;
-
客户端收到 FIN 报文段并确认,进入 TIMED WAIT 状态,此时双方连接均已经断开,但 TCP 要等待一个 2 倍报文段最大生存时间 MSL ( Maximum Segment Lifetime ),确保该连接的所有分组全部消失,以防止出现确认丢失的情况。当定时器超时后, TCP 删除该连接记录,返回到初始状态( CLOSED )。
-
服务器收到最后一个确认 ACK 报文段,其 TCP 实体便释放该连接,并删除连接记录,返回到初始状态( CLOSED )。
2. 同时打开:
尽管发生的可能性极小,两个应用程序同时彼此执行主动打开的情况还是可能的。每一方必须发送一个 SYN ,且这些 SYN 必须传递给对方。这需要每一方使用一个对方周知的端口作为本地端口。例如,主机 A 中的一个应用程序使用本地端口 7777 ,并与主机 B 的端口 8888 执行主动打开。主机 B 中的应用程序则使用本地端口 8888 ,并与主机 A 的端口 7777 执行主动打开。 TCP 是特意设计为了可以处理同时打开,对于同时打开它仅建立一条连接而不是两条连接(其他的协议族,最突出的是 OSI 传输层,在这种情况下将建立两条连接而不是一条连接)。
当出现同时打开的情况时,状态变迁与图 3-13 所示的不同。两端几乎在同时发送 SYN ,并进入 SYN_SENT 状态。当每一端收到 SYN 时,状态变为 SYN_RCVD ,同时它们都再发 SYN 并对收到的 SYN 进行确认。当双方都收到 SYN 及相应的 ACK 时,状态都变迁为 ESTABLISHED 。图 3-14 显示了这些状态变迁过程。
图 3-14 同时打开期间报文段的交换
一个同时打开的连接需要交换 4 个报文段,比正常的三次握手多一个。此外,要注意的是我们没有将任何一端称为客户或服务器,因为每一端既是客户又是服务器。
3. 同时关闭:
正常情况下都是由一方(通常但不总是客户方)发送第一个 FIN 执行主动关闭,但双方都执行主动关闭也是可能的, TCP 协议也允许这样的同时关闭。
在图 3-12 中,当两端应用层同时发出关闭命令时,两端均从 ESTABLISHED 变为 FIN_WAIT_1 。这将导致双方各发送一个 FIN ,两个 FIN 经过网络传送后分别到达另一端。收到 FIN 后,状态由 FIN_WAIT_1 变迁到 CLOSING ,并发送最后的 ACK 。当收到最后的 ACK 时,状态变化为 TIME_WAIT 。图 3-15 总结了这些状态的变化,从图中可以看出同时关闭与正常关闭使用的报文段交换数目相同。
图 3-15 同时关闭期间的报文段交换
4. 其它情况:
-
服务方打开:从 LISTEN 到 SYN_SENT 的变迁是正确的,它由服务器端主动发出 SYN 报文段,但 Berkeley 版的 TCP 软件并不支持它。
-
重置连接(复位):只有当 SYN_RCVD 状态是从 LISTEN 状态(正常情况)进入,而不是从 SYN_SENT 状态(同时打开)进入时,从 SYN_RCVD 回到 LISTEN 的状态变迁才是有效的。这意味着如果我们执行被动打开(进入 LISTEN ),收到一个 SYN ,发送一个带 ACK 的 SYN (进入 SYN_RCVD ),然后收到一个 RST ,而不是一个 ACK ,便又回到 LISTEN 状态并等待另一个连接请求的到来。
-
快速关闭:在主动关闭后的 FIN_WAIT_1 状态,如果收到的报文段不仅是 ACK ,而且还包括对方的 FIN 信号,则直接进入 TIME_WAIT 状态,给对方发送 ACK 报文段,然后等待超时。
另外, TIME_WAIT 状态的等待超时需要再详细解释一下,因为它直接影响到网络应用程序的表现。
每个具体 TCP 实现必须选择一个报文段最大生存时间 MSL ( Maximum Segment Lifetime ),它是任何报文段被丢弃前在网络内的最长时间。我们知道这个时间是有限的,因为 TCP 报文段以 IP 数据报在网络内传输,而 IP 数据报有限制其生存时间的 TTL 字段。 RFC 793 [Postel 1981c ] 指出 MSL 为 2 分钟。然而,实现中的常用值是 30 秒、 1 分钟、或 2 分钟。
对一个具体实现所给定的 MSL 值,处理的原则是:当 TCP 执行一个主动关闭,并发回最后一个 ACK ,该连接必须在 TIME_WAIT 状态停留的时间为 2 倍的 MSL ,因此 TIME_WAIT 状态也称为 2MSL 等待状态。在这段时间内,如果最后的 ACK 丢失,对方会超时并重发最后的 FIN ,这样本地 TCP 可以再次发送 ACK 报文段(这也是它唯一可以发送的报文,并重置 2MSL 定时器)。
这种 2MSL 等待的另一个结果是这个 TCP 连接在 2MSL 等待期间,定义这个连接的套接字( socket ,客户的 IP 地址和端口号,服务器的 IP 地址和端口号)不能再被使用。这个连接只能在 2MSL 结束后才能再被使用。在连接处于 2MSL 等待时,任何迟到的报文段将被丢弃。
我们假设图 3-12 中是客户执行主动关闭并进入 TIME_WAIT ,这是正常的情况,因为服务器通常执行被动关闭,不会进入 TIME_WAIT 状态。这暗示如果我们终止一个客户程序,并立即重新启动这个客户程序,则这个新客户程序将不能重用相同的本地端口。这不会带来什么问题,因为客户使用本地端口,而并不关心这个端口号是什么。然而,对于服务器,情况就有所不同,因为服务器使用周知端口。如果我们终止一个已经建立连接的服务器程序,并试图立即重新启动这个服务器程序,服务器程序将不能把它的这个周知端口赋值给它的端点,因为那个端口是处于 2MSL 连接的一部分。在重新启动服务器程序前,它需要在 1~4 分钟。这就是很多网络服务器程序被杀死后不能够马上重新启动的原因(错误提示为“ Address already in use ”)。
http://hi.baidu.com/psorqkxcsfbbghd/item/70f3bd91943b9248f14215cd
------------------------------------------------------------------------------------------------------------------------------------
TCP协议的连接是全双工连接,一个TCP连接存在双向的读写通道。 简单说来是 “先关读,后关写”,一共需要四个阶段。以客户机发起关闭连接为例: 1.服务器读通道关闭 2.客户机写通道关闭 3.客户机读通道关闭 4.服务器写通道关闭 关闭行为是在发起方数据发送完毕之后,给对方发出一个FIN(finish)数据段。直到接收到对方发送的FIN,且对方收到了接收确认ACK之后,双方的数据通信完全结束,过程中每次接收都需要返回确认数据段ACK。 详细过程: 第一阶段 客户机发送完数据之后,向服务器发送一个FIN数据段,序列号为i; 1.服务器收到FIN(i)后,返回确认段ACK,序列号为i+1,关闭服务器读通道; 2.客户机收到ACK(i+1)后,关闭客户机写通道; (此时,客户机仍能通过读通道读取服务器的数据,服务器仍能通过写通道写数据) 第二阶段 服务器发送完数据之后,向客户机发送一个FIN数据段,序列号为j; 3.客户机收到FIN(j)后,返回确认段ACK,序列号为j+1,关闭客户机读通道; 4.服务器收到ACK(j+1)后,关闭服务器写通道。 这是标准的TCP关闭两个阶段,服务器和客户机都可以发起关闭,完全对称。 FIN标识是通过发送最后一块数据时设置的,标准的例子中,服务器还在发送数据,所以要等到发送完的时候,设置FIN(此时可称为TCP连接处于半关闭状态,因为数据仍可从被动关闭一方向主动关闭方传送)。如果在服务器收到FIN(i)时,已经没有数据需要发送,可以在返回ACK(i+1)的时候就设置FIN(j)标识,这样就相当于可以合并第二步和第三步。
-
服务器端首先执行 LISTEN 原语进入被动打开状态( LISTEN ),等待客户端连接;
-
当客户端的一个应用程序发出 CONNECT 命令后,本地的 TCP 实体为其创建一个连接记录并标记为 SYN SENT 状态,然后给服务器发送一个 SYN 报文段;
-
服务器收到一个 SYN 报文段,其 TCP 实体给客户端发送确认 ACK 报文段同时发送一个 SYN 信号,进入 SYN RCVD 状态;
-
客户端收到 SYN + ACK 报文段,其 TCP 实体给服务器端发送出三次握手的最后一个 ACK 报文段,并转换为 ESTABLISHED 状态;
-
服务器端收到确认的 ACK 报文段,完成了三次握手,于是也进入 ESTABLISHED 状态。
在此状态下,双方可以自由传输数据。当一个应用程序完成数据传输任务后,它需要关闭 TCP 连接。假设仍由客户端发起主动关闭连接。
-
客户端执行 CLOSE 原语,本地的 TCP 实体发送一个 FIN 报文段并等待响应的确认(进入状态 FIN WAIT 1 );
-
服务器收到一个 FIN 报文段,它确认客户端的请求发回一个 ACK 报文段,进入 CLOSE WAIT 状态;
-
客户端收到确认 ACK 报文段,就转移到 FIN WAIT 2 状态,此时连接在一个方向上就断开了;
-
服务器端应用得到通告后,也执行 CLOSE 原语关闭另一个方向的连接,其本地 TCP 实体向客户端发送一个 FIN 报文段,并进入 LAST ACK 状态,等待最后一个 ACK 确认报文段;
-
客户端收到 FIN 报文段并确认,进入 TIMED WAIT 状态,此时双方连接均已经断开,但 TCP 要等待一个 2 倍报文段最大生存时间 MSL ( Maximum Segment Lifetime ),确保该连接的所有分组全部消失,以防止出现确认丢失的情况。当定时器超时后, TCP 删除该连接记录,返回到初始状态( CLOSED )。
-
服务器收到最后一个确认 ACK 报文段,其 TCP 实体便释放该连接,并删除连接记录,返回到初始状态( CLOSED )。
http://blog.sina.com.cn/s/blog_3c6889fe0100u7l2.html
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
TCP连接断开过程中TIME_WAIT的一些知识点
2010-01-09
TCP连接断开过程的四步骤:
(1)MSL -- Maximum Segment Lifetime, TCP分节报文最长生命周期,也就是IP数据包能在网络上存活的最长时间。任何一个系统中的TCP实现都必须设定一个MSL值。RFC 1122中的建议值是120秒。BSD和Linux一般使用的是30秒 --- CentOS 5.3中是30秒。
TIME_WAIT状态要维持2MSL秒,也就是说一般TIME_WAIT状态的延时在1~4分钟。
(2)TIME_WAIT状态存在的两个理由
(a) 可靠地实现TCP全双工链接的终止。
主要是考虑第四步的ACK丢失的情况。若ACK丢失,则被动关闭端再次发送FIN,即第三步。ACK在网络上经过MSL秒后未到达主动关闭端,在网络上消逝了。被动关闭端在2MSL时间内未收到ACK回应,则重传FIN。
(b) 允许旧的重复分节在网络中消逝。
这个很好理解,旧的TCP连接介于A[ip1 : port1]和B[ip2 : port2]之间。某TCP报文S在被A发送后正在网络中前往B。若在次过程该TCP连接关闭了,且在S到达B之前,A、B之间又被重新利用,重新建立起一条TCP链接。然后报文S打到B,以为是原先TCP连接的B端。这样问题就出现了。
现在设置了TIME_WAIT状态的维持时间为2MSL,则可保证在某一方向上的TCP报文(旧的)在MSL秒后消逝;且另一个方向上的应答报文也在MSL秒后消逝。这样就可以保证属于旧连接的报文在新连接建立之前已经在网络上消逝了,即旧报文不会影响新连接。
(3)内核微调
修改/etc/sysctl,然后运行 # sysctl -p使之立即生效。
#重用time_wait的值
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.netfilter.ip_conntrack_tcp_timeout_time_wait = 120# 2分钟
net.ipv4.netfilter.ip_conntrack_tcp_timeout_close_wait = 60
net.ipv4.netfilter.ip_conntrack_tcp_timeout_fin_wait = 120
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
http://networking.ctocio.com.cn/231/12474731.shtml
TCP三次连接和四次断开
随后在网上搜了下,说这个版本不适合千兆网卡,sniffer4.7SP5才支持.又下载了4.7SP5.还是装不上.老提示注册没成功.换了SN也不管用.郁闷啊...
最后就装了ethereal和 OmniPeek .ethereal可以分析本机的协议.OmniPeek 抓取局域网的包.
看看我用ethereal抓到图...
在TCP断开的过程中会有四个状态变化过程,如下图所示:
在连接撤销过程中,有如下过程:
1.HOST1上的应用程序关闭己方的连接导致TCP发送一个FIN消息给HOST2.
2.HOST2发送一个确认消息给HOST1,并且HOST2把FIN作为EOF递交给HOST2上的应用程序.
3.一段时间过后,HOST2上的应用程序关闭它那边的连接,引发一个FIN消息给HOST1.
4.HOST1给HOST2发送一个确认消息,然后HOST2关闭连接并释放资源,然而,HOST1却没有关闭连接,而是进入了TIME_WAIT状态,并为两个最大段生存时间(2MSL)保留在此状态.
为什么需要TIME_WAIT?
1.因为在第四步的时候,HOST1发送的ACK可能丢失并导致HOST2重新发送FIN消息,TIME_WAIT维护连接状态.
如果执行主动关闭的一方HOST1 不进入到TIME_WAIT状态就关闭连接那会发生什么呢?当重传的FIN消息到达时,因为TCP已经不再有连接的信息了,所以就用RST(重新启动)消息应答,导致HOST2进入错误的状态而不是有序终止状态,如果发送最后ACK消息的一方处于TIME_WAIT状态并仍然记录着连接的信息,它就可以正确的响应对等方HOST2的FIN消息了.
2.TIME_WAIT为连接中“离群的段”提供从网络中消失的时间.
考虑一下,如果延迟或者重传段在连接关闭后到达时会发生什么呢?通常情况下,因为TCP仅仅丢弃该数据并响应RST消息,所以这不会造成任何问题.当RST消息到达发出延时段的主机时,因为该主机也没有记录连接的任何信息,所以它也丢弃该段.然而,如果两个相同主机之间又建立了一个具有相同端口号的新连接,那么离群的段就可能被看成是新连接的,如果离群的段中数据的任何序列号恰恰在新连接的当前接收窗口中,数据就会被重新接收,其结果就是破坏新连接.