TCP协议之三次握手、四次挥手

HTTP图解是大半月前看完的书,由于自己懒,加上还有新书要看,所以学习总结一直搁置,233333333。好了进入正题,这次总结的是TCP协议中三次握手和四次挥手的原理。

为了确保无误地将数据送达目标处,TCP协议采用了三次握手策略建立连接,四次挥手策略断开连接。

三次握手:

第一次握手:发送端首先发送一个带SYN(synchronize)标志的数据包给对方。

第二次握手:接收端收到后,回传一个带有SYN/ACK(acknowledgement)标志的数据包以示传达确认信息。

第三次握手:最后,发送端再回传一个带ACK标志的数据包,代表“握手”结束。若在握手过程中某个阶段莫名中断,TCP协议会再次相同的顺序发送相同的数据包

四次挥手:

由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。

第一次挥手: TCP客户端发送一个FIN,用来关闭客户到服务器的数据传送。设置Sequence Number和Acknowledgment Number,此时,客户端进入FIN_WAIT_1状态;这表示客户端没有数据要发送给服务器了;

第二次挥手: 服务器收到了客户端发送的FIN报文段,向客户端回一个ACK报文段,Acknowledgment Number为Sequence Number加1;客户端进入FIN_WAIT_2状态;服务器告诉客户端,我也没有数据要发送了,可以进行关闭连接了;

第三次挥手:服务器向客户端发送FIN报文段,关闭客户端的连接,同时服务器进入CLOSE_WAIT状态;

第四次挥手:客户端发回ACK报文确认,并将确认序号设置为收到序号加1。客户端收到服务器发送的FIN报文段,向服务器发送ACK报文段,然后客户端进入TIME_WAIT状态;服务器收到客户端的ACK报文段以后,就关闭连接;此时,客户端等待2MSL(报文最大生存时间)后依然没有收到回复,则证明Server端已正常关闭,那好,客户端也可以关闭连接了。

CLOSED:表示初始状态。

LISTEN:这个也是非常容易理解的一个状态,表示服务器端的某个SOCKET处于监听状态,可以接受连接了。

SYN_RCVD:这个状态表示接受到了SYN报文,在正常情况下,这个状态是服务器端的SOCKET在建立TCP连接时的三次握手会话过程中的一个中间状态,很短暂,基本上用netstat你是很难看到这种状态的,除非你特意写了一个客户端测试程序,故意将三次TCP握手过程中最后一个ACK报文不予发送。因此这种状态时,当收到客户端的ACK报文后,它会进入到ESTABLISHED状态。

SYN_SENT:这个状态与SYN_RCVD遥想呼应,当客户端SOCKET执行CONNECT连接时,它首先发送SYN报文,因此也随即它会进入到了SYN_SENT状态,并等待服务端的发送三次握手中的第2个报文。SYN_SENT状态表示客户端已发送SYN报文。

ESTABLISHED:这个容易理解了,表示连接已经建立了。

FIN_WAIT_1:这个状态要好好解释一下,其实FIN_WAIT_1和FIN_WAIT_2状态的真正含义都是表示等待对方的FIN报文。而这两种状态的区别是:FIN_WAIT_1状态实际上是当SOCKET在ESTABLISHED状态时,它想主动关闭连接,向对方发送了FIN报文,此时该SOCKET即进入到FIN_WAIT_1状态。而当对方回应ACK报文后,则进入到FIN_WAIT_2状态,当然在实际的正常情况下,无论对方何种情况下,都应该马上回应ACK报文,所以FIN_WAIT_1状态一般是比较难见到的,而FIN_WAIT_2状态还有时常常可以用netstat看到。

FIN_WAIT_2:上面已经详细解释了这种状态,实际上FIN_WAIT_2状态下的SOCKET,表示半连接,也即有一方要求close连接,但另外还告诉对方,我暂时还有点数据需要传送给你,稍后再关闭连接。

TIME_WAIT:表示收到了对方的FIN报文,并发送出了ACK报文,就等2MSL后即可回到CLOSED可用状态了。如果FIN_WAIT_1状态下,收到了对方同时带FIN标志和ACK标志的报文时,可以直接进入到TIME_WAIT状态,而无须经过FIN_WAIT_2状态。

CLOSING:这种状态比较特殊,实际情况中应该是很少见,属于一种比较罕见的例外状态。正常情况下,当你发送FIN报文后,按理来说是应该先收到(或同时收到)对方的ACK报文,再收到对方的FIN报文。但是CLOSING状态表示你发送FIN报文后,并没有收到对方的ACK报文,反而却也收到了对方的FIN报文。什么情况下会出现此种情况呢?其实细想一下,也不难得出结论:那就是如果双方几乎在同时close一个SOCKET的话,那么就出现了双方同时发送FIN报文的情况,也就会出现CLOSING状态,表示双方都正在关闭SOCKET连接。

CLOSE_WAIT:这种状态的含义其实是表示在等待关闭。怎么理解呢?当对方close一个SOCKET后发送FIN报文给自己,你系统毫无疑问地会回应一个ACK报文给对方,此时则进入到CLOSE_WAIT状态。接下来呢,实际上你真正需要考虑的事情是查看你是否还有数据发送给对方,如果没有的话,那么你也就可以close这个SOCKET,发送FIN报文给对方,也即关闭连接。所以你在CLOSE_WAIT状态下,需要完成的事情是等待你去关闭连接。

LAST_ACK:这个状态还是比较容易好理解的,它是被动关闭一方在发送FIN报文后,最后等待对方的ACK报文。当收到ACK报文后,也即可以进入到CLOSED可用状态了。

为什么需要三次握手呢?

在谢希仁著《计算机网络》第四版中讲“三次握手”的目的是“为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误”,书中的例子是这样的,“已失效的连接请求报文段”的产生在这样一种情况下:客户端(client)发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达服务端(server)。本来这是一个早已失效的报文段。但服务端(server)收到此失效的连接请求报文段后,就误认为是客户端(client)再次发出的一个新的连接请求。于是就向客户端(client)发出确认报文段,同意建立连接。假设不采用“三次握手”而是“两次握手”,那么只要服务端(server)发出确认,新的连接就建立了。由于现在客户端(client)并没有发出建立连接的请求,因此不会理睬服务端(server)的确认,也不会向服务端(server)发送数据。但服务端(server)却以为新的运输连接已经建立,并一直等待客户端(client)发来数据。这样,服务端(server)的很多资源就白白浪费掉了。采用“三次握手”的办法可以防止上述现象发生。例如刚才那种情况,客户端(client)不会向服务端(server)的确认发出确认。服务端(server)由于收不到确认,就知道客户端(client)并没有要求建立连接。说白了主要目的是防止服务端(server)一直等待,浪费资源

为什么需要四次挥手呢?

  1. A向B发起请求,表示A没有数据要发送了:A——>B;
  2. B向A发送信号,确认A的断开请求请求:B——>A;
  3. B向A发送信号,请求断开连接,表示B没有数据要发送了:B——>A;
  4. A向B发送确认信号,同意断开:A——>B。

第一是为了保证最后一个的一个ACK报文能到达B。这个ACK报文有可能丢失,因而使得处在LAST_ACK状态得不到对已发送的FIN+ACK报文的确认,B会超时重传这个FIN+ACk ,而A就能在这TIME_WAIT时间(2MSL)里收到这个重传的报文,A就可以重传一次确认,如果没有这个TIME_WAIT, 那B重传的FIN_ACK,可A早就走了,自然不会再重发确认,这样B就无法按照正常步骤进入CLOSE 状态。 

第二是防止“已失效的报文连接请求”,A在TIME_WAIT中,经过这2MSL的时间,就可以使本链接持续的时间内产生的所有连接消失,这样就可以使下一个新的连接中不会出现这样旧的连接请求报文段。 聪明的你会发现谁先关闭谁就有一个TIME_WAIT的状态; 在linux的网络编程中,如果服务器如果先关闭,你会发现,现在想要立马再次启动服务器,就会报错说这个端口号被占用着,那就是因为有这个TIME_WAIT,2msl的时间.那么怎么解决 ? 

解决:setsockopt()函数。在这就不多说了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值