tcp为什要三次握手

准备知识: windows

单工:信息只能单向传递。发送-->接收,单向,不能返回响应。服务器

双工:指的是信息可双向发送。网络

全双工:信息可同时双向传递。socket

半双工:不能同时,单行道,一边传输完了,另外一边才能发起传输。tcp

 

因为IP协议是不可靠的,为了在不可靠信道上传输可靠数据,就要进行三次握手,准确的说是发送三次预备信息,这样就完成了信息传递的双工准备。(HTTP协议是须要双向传递的)。spa

双方都须要确认本身的发信和收信功能正常,收信功能经过接收对方信息获得确认,发信功能须要发出信息—>对方回复信息获得确认。操作系统

第一次发信息: CLIENT --> SERVER blog

第二次发信息:  SERVER --> CLIENT     客户端接收到了,确信本身能够收,而且收到的信息里有上一步发过去信息里的内容,说明也是能够发送的。io

第三次发信息: CLIENT --> SERVER     同理,服务端也确信了能够收和发的能力。sed

 

若是没有第三次发信息,只是保证了一个单向的链接畅通。客户端能够大胆地单向给服务端发信息。服务端因为没收到过“回音”,不能肯定对方能不能收到,tcp协议是保证了传输可靠性的,不容许这种不肯定性存在,就不容许服务器给客户端发送响应了。

固然UDP协议就不保证输出的可靠性了,就算没有收到过“回音”也敢发出信息。

 

-------------------------------链接断开的时候为何要四次呢-----------------

因为TCP链接是全双工的,所以每一个方向都必须单独进行关闭。

由于能够同时双向传输,A B 两个终端上有两个通道四个端口。分别是A端的读端口,A端的写端口和B端的读端,B端的写端口。 

TCP采用四次挥手关闭链接如图2所示。

以客户机发起关闭链接为例:
1.Client发送FIN给Server,Server收到Fin信息后知道已经没有要再接收的东西了,就关闭本身的读端口,而后发送ACK给CLient   --Server 读端关闭 
2.Client收到ACK后,知道对面已经关闭读通道了,如今本身能够把写端口关闭了                                                                    --Client  写端关闭
3.Server发送FIN给Client表示本身没有要发送的了,Client收到FIN后,关闭本身的读端口,而后发送ACK给Server                  --Client  读端关闭
4.Server接受到ACK后,关闭本身的写端口,而且Server的Conection状态变为Closed,完全关闭能够重用了。                        --Server 写端关闭 
5.Client在最后发给Server的ACK报文后等待两个MSL时间,而后Client端的onection状态变为Closed。

* 能够看出,读端口的关闭,是收到对方发来的FIN信号便可。而写端口的关闭是,发送一个FIN给对方,收到对方的ACK回复才能够关闭。这是确保数据包都发送过去的重发机制要求的。

第2步和第3步不少时候均可以合并,就是收到对方的FIN的时候,本身没有要发过去的东西,就把ACK和FIN一块儿返回去了。

* 主动发起关闭链接的一方发出最后的ACK报文后达到TIME_WAIT状态,并且这个状态要保持Maximum Segment Lifetime的两倍时间。这是由于两点:

保证TCP协议的全双工链接可以可靠关闭
2 保证此次链接的重复数据段从网络中消失

先说第一点,若是Client直接CLOSED了,那么因为IP协议的不可靠性或者是其它网络缘由,致使Server没有收到Client最后回复的ACK。那么Server就会在超时以后继续发送FIN,此时因为Client已经CLOSED了,就找不到与重发的FIN对应的链接,最后Server就会收到RST而不是ACK,Server就会觉得是链接错误把问题报告给高层。这种状况虽然不会形成数据丢失,可是却致使TCP协议不符合可靠链接的要求。因此,Client不是直接进入CLOSED,而是要保持TIME_WAIT,当再次收到FIN的时候再发一个ACK给对方。保证对方收到,最后正确的关闭链接。(MSL指一个片断在网络中最大的存活时间,2MSL就是一个发送和一个回复所需的最大时间,为操做系统决定大小,windows默认MSL值为2分钟。若是直到2MSL,Client都没有再次收到FIN,那么Client推断ACK已经被成功接收,则结束TCP链接。)

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

------------------TCP的粗暴关闭链接方式--------------------

除了如上可靠的关闭方式以外,TCP还提供了另一种不可靠的关闭方式RST(Reset)
(CLOSED)  A    ---RST-->  B (CLOSED)
  A端发送RST状态以后,TCP进入CLOSED状态,B端接收到RST后,也便可进入CLOSED状态。
在上面第一关闭方式上(可靠的),很是遗憾,A端在最后发送一个ACK请求后,并不能立刻将该Socket回收,由于A并不能肯定B必定可以接收到这个ACK报文,所以A端必须对这个Socket维持TIME_WAIT状态2MSL。

若是A端是Client,这并不会成为问题,但若是A端是Server,那就很危险了,若是链接的Socket很是多,而又维持如此多的TIME_WAIT状态的话,那么有可能会将Socket耗尽(报Too Many Open File)。

服务端为了解决这个问题,可选择的方式有三种:    Ø  保证由客户端主动发起关闭(即作为B端)    Ø  关闭的时候使用RST的方式    Ø  对处于TIME_WAIT状态的TCP容许重用通常咱们固然最好是选择第一种方式,实在没有办法的时候,咱们可使用SOCKET参数【SO_LINGER】开启第二种方式,使用SOCKET参数【SO_REUSEADDR】开启第三种方式

相关文章
相关标签/搜索