关于TCP的三次握手和四次分手 专题

 

 

客户端TCP状态迁移:
CLOSED->SYN_SENT->ESTABLISHED->FIN_WAIT_1->FIN_WAIT_2->TIME_WAIT->CLOSED
服务器TCP状态迁移:
CLOSED->LISTEN->SYN收到->ESTABLISHED->CLOSE_WAIT->LAST_ACK->CLOSEDhtml


各个状态的意义以下:
LISTEN - 侦听来自远方TCP端口的链接请求;
SYN-SENT -在发送链接请求后等待匹配的链接请求;
SYN-RECEIVED - 在收到和发送一个链接请求后等待对链接请求的确认;
ESTABLISHED- 表明一个打开的链接,数据能够传送给用户;
FIN-WAIT-1 - 等待远程TCP的链接中断请求,或先前的链接中断请求的确认;
FIN-WAIT-2 - 从远程TCP等待链接中断请求;
CLOSE-WAIT - 等待从本地用户发来的链接中断请求;
CLOSING -等待远程TCP对链接中断的确认;
LAST-ACK - 等待原来发向远程TCP的链接中断请求的确认;
TIME-WAIT -等待足够的时间以确保远程TCP接收到链接中断请求的确认;
CLOSED - 没有任何链接状态;服务器

 

 

 

【注意】
在TIME_WAIT状态中,若是TCP client端最后一次发送的ACK丢失了,它将从新发送。TIME_WAIT状态中所须要的时间是依赖于实现方法的。
典型的值为30秒、1分钟和2分钟。等待以后链接正式关闭,而且全部的资源(包括端口号)都被释放。

【问题1】为何链接的时候是三次握手,关闭的时候倒是四次握手?
答:
由于当Server端收到Client端的SYN链接请求报文后,能够直接发送SYN+ACK报文。

可是关闭链接时,当Server端收到FIN报文时,极可能并不会当即关闭SOCKET,
因此只能先回复一个ACK报文,告诉Client端,"你发的FIN报文我收到了",(报文1,ACK,应答)
只有等到我Server端全部的报文都发送完了,我才能发送FIN报文(报文2,FIN,服务器已经结束),
所以不能一块儿发送。
故须要四步握手。

【问题2】为何TIME_WAIT状态须要通过2MSL(Maximum Segment Lifetime,最大报文段生存时间)才能返回到CLOSE状态?cookie

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

先说第一点(要知足可靠链接的须要),
若是Client直接CLOSED了,那么因为IP协议的不可靠性或者是其它网络缘由,致使Server没有收到Client最后回复的ACK。
那么Server就会在超时以后继续发送FIN,此时因为Client已经CLOSED了,就找不到与重发的FIN对应的链接,最后Server就会收到RST而不是ACK,Server就会觉得是链接错误把问题报告给高层。
这样的状况虽然不会形成数据丢失,可是却致使TCP协议不符合可靠链接的要求
因此,Client不是直接进入CLOSED,而是要保持TIME_WAIT,当再次收到FIN的时候,可以保证对方收到ACK,最后正确的关闭链接。并发

再说第二点(防止先后两次链接的数据包混淆),
若是Client直接CLOSED,而后又再向Server发起一个新链接,咱们不能保证这个新链接与刚关闭的链接的端口号是不一样的。
也就是说有可能新链接和老链接的端口号是相同的。
通常来讲不会发生什么问题,可是仍是有特殊状况出现:
假设新链接和已经关闭的老链接端口号是同样的,若是前一次链接的某些数据仍然滞留在网络中,这些延迟数据在创建新链接以后才到达Server,因为新链接和老链接的端口号是同样的,又由于TCP协议判断不一样链接的依据是socket pair,
因而,TCP协议就认为那个延迟的数据是属于新链接的,这样就和真正的新链接的数据包发生混淆了。
因此TCP链接还要在TIME_WAIT状态等待2倍MSL,这样能够保证本次链接的全部数据都从网络中消失。socket

各类协议都是前人千锤百炼后获得的标准,规范。
从细节中都能感觉到精巧和严谨。
每次深刻体会都有同一个感受:精妙。tcp

 

在TCP层,有个FLAGS字段,这个字段有如下几个标识:SYN, FIN, ACK, PSH, RST, URG.
其中,对于咱们平常的分析有用的就是前面的五个字段。ide

它们的含义是:
SYN表示创建链接,
FIN表示关闭链接,
ACK表示响应,
PSH表示有DATA数据传输,
RST表示链接重置。高并发

其中,
ACK是可能与SYN,FIN等同时使用的,好比SYN和ACK可能同时为1,它表示的就是创建链接以后的响应,
若是只是单个的一个SYN,它表示的只是创建链接。idea

TCP的几回握手就是经过这样的ACK表现出来的。
但SYN与FIN是不会同时为1的,由于前者表示的是创建链接,然后者表示的是断开链接。

RST通常是在FIN以后才会出现为1的状况,表示的是链接重置。
通常地,当出现FIN包或RST包时,咱们便认为客户端与服务器端断开了链接;而当出现SYN和SYN+ACK包时,咱们认为客户端与服务器创建了一个链接。
PSH为1的状况,通常只出如今 DATA内容不为0的包中,也就是说PSH为1表示的是有真正的TCP数据包内容被传递。

TCP的链接创建和链接关闭,都是经过请求-响应的模式完成的。

概念补充-TCP三次握手:
TCP(Transmission Control Protocol)传输控制协议
TCP是主机对主机层的传输控制协议,提供可靠的链接服务,采用三次握手确认创建一个链接:
位码即tcp标志位,有6种标示:
SYN(synchronous创建联机)
ACK(acknowledgement 确认)
PSH(push传送)
FIN(finish结束)
RST(reset重置)
URG(urgent紧急)
Sequence number(顺序码)
Acknowledge number(确认码)


在TCP/IP协议中,TCP协议提供可靠的链接服务,采用三次握手创建一个链接。
第一次握手:创建链接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时本身也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。

完成三次握手,客户端与服务器开始传送数据.


示例:
第一次握手:主机A发送位码为syn=1,随机产生seq number=1234567的数据包到服务器,主机B由SYN=1知道,A要求创建联机;
第二次握手:主机B收到请求后要确认联机信息,向A发送ack number=(主机A的seq+1),syn=1,ack=1,随机产生seq=7654321的包;
第三次握手:主机A收到后检查ack number是否正确,即第一次发送的seq number+1,以及位码ack是否为1,
若正确,主机A会再发送ack number=(主机B的seq+1),ack=1,主机B收到后确认seq值与ack=1则链接创建成功。

完成三次握手,主机A与主机B开始传送数据。

 

 

 

这个协议很是重要,这里把它的连接和释放整理一下

首先是三次握手:

一、  客户端发起,像服务器发送的报文SYN=1,ACK=0,而后选择了一个初始序号:seq=x。

SYN是干什么用的?

在连接的时候建立一个同步序号,当SYN=1同时ACK=0的时候,代表这是一个链接请求的报文段。若是对方有意连接,返回的报文里面SYN=1,ACK=1,。从这个意义上来讲,SYN=1的时候,就代表这是一个‘请求’或者‘接受请求’的报文。

SYN=1的报文段不能携带数据。可是要消耗掉一个序号,

ACK是干什么用的?

仅当ACK=1的时候,确认字号(指望收到对方下一个报文段的第一个数据字节的编号)才有效。所以,TCP规定,当连接创建以后,全部往来的报文里面的ACK都应该是1(事实上,也只有客户端发起的连接请求报文的ACK没有置1)。

如今的状态:客户端进入SYN-SEND状态;

二、  服务器接收到了SYN=1,ACK=0的请求报文以后,返回一个SYN=1,ACK=1的确认报文。

同时,确认号ack=x+1,同时也为本身选择一个初始序号seq=y

如今的状态:服务器进入SYN-REVD状态;

三、  客户端接收到了服务器的返回信息以后,还要给服务器返回最后一条确认,ACK=1,确认号ack=y+1;

如今的状态:客户端进入ESTABLISHED状态。

 

下面说一下为何两次握手不行,非得三次:

 

首先说明一种正常的状况,就是客户端发送了一条请求连接的报文,可是因为网络缘由丢失了,因此,不可能接收到服务器端的确认。这个时候,客户端就就只有再一次发送原来的请求报文,此次服务器收到以后返回确认,客户端再确认一次,连接确立。

 

而后考虑一种不正常的状况,客户端发了两次请求连接的报文,第二条被服务器捕捉到,返回数据,完成了两次握手。数据传送完成以后,连接关闭。可是这时候,第一条拥塞的请求报文如今到达了服务器端,服务器还觉得客户端要又一次创建链接,因而发送确认,而后把本身敞开,等着客户端发送过来数据。因而,不少的网络资源就是这样浪费掉了。

 

要是实行三次握手,服务器收到了一条过时的请求报文,返回确认信息,客户端接收到了服务器的信息以后感到莫名其妙,心想:我他妈又没要连接,你返回这个是否是疯了。因而不置一词。服务器过一段时间尚未收到第三次握手的数据,知道客户端并无要求创建连接的请求,含泪离开。

 

 

而后是四次挥手(four-way handshake):

如今双方的状态都是ESTABLISHED状态。

一、  客户端发起请求,请求断开连接。FIN=1,seq=u。u是以前传送过来的最后一个字节的序号+1。

FIN:用来释放一个连接,当FIN=1的时候,代表此报文的发送方已经完成了数据的发送,没有新的数据要传送,并要求释放连接。

客户端进入FIN-WAIT-1状态,等着服务器返回确认;

二、  服务器收到客户端的请求断开连接的报文以后,返回确认信息。ACK=1,seq=v,ack=u+1。

服务器进入CLOSE-WAIT状态。

这个时候,客户端不能给服务器发送信息报文,只能接收。可是服务器要是还有信息要传给服务器,仍然能传送。

三、  当服务器也没有了能够传的信息以后,给客户端发送请求结束的报文。FIN=1,ACK=1,

ack=u+1,seq=w。

这个时候的状态:服务器进入LAST-ACK状态。

四、  客户端接收到FIN=1的报文以后,返回确认报文,ACK=1,seq=u+1,ack=w+1。

发送完毕以后,客户端进入等待状态,等待两个时间周期。关闭。

 

为何最后还要等待两个时间周期呢?

一、  客户端的最后一个ACK报文在传输的时候丢失,服务器并无接收到这个报文。
这个时候服务器就会超时重传这个FIN消息,而后客户端就会从新返回最后一个ACK报文,等待两个时间周期,完成关闭。
若是不等待这两个时间周期,服务器重传的那条消息就不会收到。服务器就由于接收不到客户端的信息而没法正常关闭。

二、  预防上一次在三次握手中提到的失效的报文干扰。两个时间周期过去以后,全部的报文都会在网络中消失,保证下一次从新链接的时候有乱七八糟的报文影响。

 

下面看下你们通常比较关心的三种TCP状态

SYN_RECV
服务端收到创建链接的SYN没有收到ACK包的时候处在SYN_RECV状态。有两个相关系统配置:
一、net.ipv4.tcp_synack_retries :INTEGER
默认值是5
对于远端的链接请求SYN,内核会发送SYN + ACK数据报,以确认收到上一个 SYN链接请求包。这是所谓的三次握手( threeway handshake)机制的第二个步骤。这里决定内核在放弃链接以前所送出的 SYN+ACK 数目。不该该大于255,默认值是5,对应于180秒左右时间。一般咱们不对这个值进行修改,由于咱们但愿TCP链接不要由于偶尔的丢包而没法创建。

二、net.ipv4.tcp_syncookies
通常服务器都会设置net.ipv4.tcp_syncookies=1来防止SYN Flood攻击。假设一个用户向服务器发送了SYN报文后忽然死机或掉线,那么服务器在发出SYN+ACK应答报文后是没法收到客户端的ACK报文的(第三次握手没法完成),这种状况下服务器端通常会重试(再次发送SYN+ACK给客户端)并等待一段时间后丢弃这个未完成的链接,这段时间的长度咱们称为SYN Timeout,通常来讲这个时间是分钟的数量级(大约为30秒-2分钟)。

这些处在SYNC_RECV的TCP链接称为半链接,并存储在内核的半链接队列中,在内核收到对端发送的ack包时会查找半链接队列,并将符合的requst_sock信息存储到完成三次握手的链接的队列中,而后删除此半链接。大量SYNC_RECV的TCP链接会致使半链接队列溢出,这样后续的链接创建请求会被内核直接丢弃,这就是SYN Flood攻击。

可以有效防范SYN Flood攻击的手段之一,就是SYN Cookie。SYN Cookie原理由D. J. Bernstain和 Eric Schenk发明。SYN Cookie是对TCP服务器端的三次握手协议做一些修改,专门用来防范SYN Flood攻击的一种手段。它的原理是,在TCP服务器收到TCP SYN包并返回TCP SYN+ACK包时,不分配一个专门的数据区,而是根据这个SYN包计算出一个cookie值。在收到TCP ACK包时,TCP服务器在根据那个cookie值检查这个TCP ACK包的合法性。若是合法,再分配专门的数据区进行处理将来的TCP链接。

观测服务上SYN_RECV链接个数为:7314,对于一个高并发链接的通信服务器,这个数字比较正常。


CLOSE_WAIT
发起TCP链接关闭的一方称为client,被动关闭的一方称为server。被动关闭的server收到FIN后,但未发出ACK的TCP状态是CLOSE_WAIT。
出现这种情况通常都是因为server端代码的问题,若是你的服务器上出现大量CLOSE_WAIT,应该要考虑检查代码

TIME_WAIT
根据TCP协议定义的3次握手断开链接规定,发起socket主动关闭的一方 socket将进入TIME_WAIT状态。TIME_WAIT状态将持续2个MSL(Max Segment Lifetime),在Windows下默认为4分钟,即240秒。TIME_WAIT状态下的socket不能被回收使用. 具体现象是对于一个处理大量短链接的服务器,若是是由服务器主动关闭客户端的链接,将致使服务器端存在大量的处于TIME_WAIT状态的socket, 甚至比处于Established状态下的socket多的多,严重影响服务器的处理能力,甚至耗尽可用的socket,中止服务。

 

创建链接:

理解:窗口和滑动窗口
TCP的流量控制,TCP使用窗口机制进行流量控制
什么是窗口?
链接创建时,各端分配一块缓冲区用来存储接收的数据,并将缓冲区的尺寸发送给另外一端,接收方发送的确认信息中包含了本身剩余的缓冲区尺寸

剩余缓冲区空间的数量叫作窗口

2. TCP的流控过程(滑动窗口)

参考文章:

http://www.cnblogs.com/lamian/p/3983497.html

http://kb.cnblogs.com/page/209100/

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

http://www.cnblogs.com/Jessy/p/3535612.html

http://www.cnblogs.com/softidea/p/6062147.html(TIME_WAIT)

相关文章
相关标签/搜索