TCP三次握手四次挥手

0. overview

tcp是面向连接的通信。

服务器必须准备好接受外来的连接。这通常通过调用socket,bind和listen这三个函数来完成。我们称之为被动打开。客户端初始化一个Socket,然后调用(connect)连接服务器。

1. 三次握手建立socket连接

三次握手的主要作用就是为了确认双方的接收能力和发送能力是否正常、指定自己的初始化序列号为后面的可靠性传送做准备。

三次握手不是TCP本身的要求, 而是为了满足"在不可靠信道上可靠地传输信息"这一需求所导致的。三次握手的过程中会同步客户端和服务器的序列号,为确认应答处理、重发控制以及重复控制等功能提供了保证。

三次握手的其中一个重要功能是客户端和服务端交换初始序列号ISN,以便让对方知道接下来接收数据的时候如何按序列号组装数据。如果 初始序列号 ISN 是固定的,攻击者很容易猜出后续的确认号,从而打断正常的TCP连接,因此 ISN 是动态生成的

1.1 详述

SYN:连接请求/接收 报文段

 seq:发送的第一个字节的序号

 ACK:确认报文段

 ack:确认好,希望收到的下一个数据的第一个字节的序号

第一次握手:客户端给服务器发送一个同步报文段SYN,并指定客户端的初始序列号ISN,此时客                        户端处于SYN_SENT状态

第二次握手:服务器接收到来自客户端的同步报文段SYN后,会以自己的SYN报文作为应答,                             并且也指定了自己的初始序列号ISN。同时会把客户端的 seq+1 确认序列号ack的                           值,表示自己已经收到了客户端的同步报文段SYN,此时服务器处于SYN_RCVD的                       状态。

第三次握手:客户端收到来自服务器的同步报文段SYN之后,会发送一个确认报文段ACK,以服                         务器的 seq+1作为ack的值 ,表明自己已经收到来自服务器的同步报文段SYN。客                         户端进入ESTABLISHED状态,服务器确认报文段ACK之后,也会进入                                           ESTABLISHED状态。

三次握手结束,双方已经建立起连接,可以正常的收发数据。

1.2 面试问题

1)为什么两次握手不可以?

因为:第三次握手是为了防止失效的请求连接到达服务器,让服务器错误的打开连接。

假如客户端发出了连接请求,但因为网络波动导致服务器并没有收到来自客户端的请求连接,于是客户端又重发了一次连接请求,客户端和服务器经过两次握手就建立好连接。双方开始传输数据,数据传输完成以后,双方断开连接。过一段时间后,原本在网络传输中搁置的连接请求到达了服务器。服务器以为是客户端又发出来一次新的连接请求,于是就向客户端发送确认报文段,同意建立连接(两次握手只需要服务器发出确认报文段,就建立好连接)。此时服务器一直在等待客户端发送的数据,一直浪费着系统资源。

总的来说,经过三次握手让客户端和服务器互相知道了自己的发送、接收和对方发送、接收都是正常的。

2)改为四次握手行不行?
行!!!TCP三次握手原本应该是"四次握手",但是中间的同步报文段SYN和应答报文ACK是可以合在一起的,这两个操作在时间上是同时发送的。

当客户端的到达同步报文段SYN到达服务器的时候,服务器的内核就会第一时间进行应答报文段ACK, 同时也会第一时间发起同步报文段SYN,这两件事情同时触发,于是就没必要分成两次传输,直接一步到位。分成两次反而会更浪费系统资源(需要进行两次的封装和分用)。

3)TCP第三次握手失败了怎么办?
服务器发送了SYN+ACK报文后就会启动一个定时器,等待客户端返回的ACK报文。如果服务器在定时器的范围内没有收到来自客户端的ACK报文,服务器会再次重发SYN+ACK报文。重传的次数可以根据/proc/sys/net/ipv4/tcp_synack_retries来指定,默认为5次。

达到重传的指定次数后仍然没有收到ACK应答,那么一段时间后,服务器自动关闭这个连接。但是client认为这个连接已经建立好了。

如果客户端向服务器发送数据,服务器将以RST包(重置连接)响应。

4)三次握手是否可以携带数据?
第一次、第二次不可以,第三次可以。

如果第一次握手可以携带数据的话,那么将会使服务器更容易遭受攻击。如果第一次握手携带就大量的数据,那么服务器需要花老长的时间才能对此解析。如果进行重复的发送,那么服务器就会因为系统资源殆尽而崩溃。

第三次握手可以携带数据。第三次握手时客户端处于ESTABLISH状态。对于客户端来说,它已经建立好了连接,并且它已经知道服务器的接收能力和自己的发送能力是正常的,所以可以进行正常的发送数据。

1.3 SYN泛洪攻击

SYN泛洪攻击利用的是TCP的三次握手机制,攻击端利用伪造的IP地址向服务器发出请求,而被服务器发出的响应响应将永远发送不到目的地,那么就会触发服务器的超时重传机制等待客户端的响应(客户端的IP地址不存在,根本不会进行响应)。那么被服务器在等待关闭这个连接的过程中消耗了资源,如果有成千上万的这种连接,主机资源将被耗尽,从而达到攻击的目的。

措施:

        降低SYN timeout时间

        采用SYN cookie设置

        增加半连接数

        合理地采用防火墙等外部网络安全设施

2. tcp四次挥手断开socket连接

2.1 详述

第一次挥手:客户端打算断开连接,向服务器发送FIN报文(FIN标记位被设置为1,1表示为FIN,0表示不是),FIN报文中会指定一个序列号,之后客户端进入FIN_WAIT_1状态。

也就是客户端发出连接释放报文段(FIN报文),指定序列号seq = u,主动关闭TCP连接,等待服务器的确认。

第二次挥手:服务器收到连接释放报文段(FIN报文)后,就向客户端发送ACK应答报文,以客户端的FIN报文的序列号 seq+1 作为ACK应答报文段的确认序列号ack = seq+1 = u + 1。

接着服务器进入CLOSE_WAIT(等待关闭)状态,此时的TCP处于半关闭状态(下面会说什么是半关闭状态),客户端到服务器的连接释放。客户端收到来自服务器的ACK应答报文段后,进入FIN_WAIT_2状态。

第三次握手:服务器也打算断开连接,向客户端发送连接释放(FIN)报文段,之后服务器进入LASK_ACK(最后确认)状态,等待客户端的确认。

服务器的连接释放(FIN)报文段的FIN=1,ACK=1,序列号seq=m,确认序列号ack=u+1。

第四次握手:客户端收到来自服务器的连接释放(FIN)报文段后,会向服务器发送一个ACK应答报文段,以连接释放(FIN)报文段的确认序号 ack 作为ACK应答报文段的序列号 seq,以连接释放(FIN)报文段的序列号 seq+1作为确认序号ack。

之后客户端进入TIME_WAIT(时间等待)状态,服务器收到ACK应答报文段后,服务器就进入CLOSE(关闭)状态,到此服务器的连接已经完成关闭。

客户端处于TIME_WAIT状态时,此时的TCP还未释放掉,需要等待2MSL后,客户端才进入CLOSE状态。

2.2 面试问题

1)为什么挥手需要四次?
这是由于TCP的半关闭(half-close)造成的。半关闭是指:TCP提供了连接的一方在结束它的发送后还能接受来自另一端数据的能力。通俗来说,就是不能发送数据,但是还可以接受数据。

TCP不允许连接处于半打开状态时,就单向传输数据,因此完成三次握手后才可以传输数据(第三握手可以携带数据)。

当连接处于半关闭状态时,TCP是允许单向传输数据的,也就是说服务器此时仍然可以向客户端发送数据,等服务器也不再发送数据时,才会发送FIN报文段,同意现在关闭连接

这一特性是由于TCP双向通道互相独立所导致的,也使得关闭连接必须经过四次握手。

2)为什么中间的ACK和FIN不可以像三次握手那样合为一个报文段呢?

在socket网络编程中,执行close()方法会触发内核发送FIN报文。什么时候调用close()方法,这是由用户态决定的,假如服务器仍有大量数据等待处理,那么服务器会等数据处理完后,才调用close()方法,这个时间可能会很久,而ACK报文则是由系统内核来完成的,这个过程会很快。所以中间的ACK和FIN不能合为一个包。

3)为什么TIME_WAIT等待的时间是2MSL?
MSL(Maximum Segment LifeTime)是报文最大生存时间,它是任何报文在网络上存在的最长时间,超过这个时间的报文将被丢弃。

因为TCP协议是基于IP协议(位于IP协议的上一层),IP数据报中有限制其生存时间的TTL字段,是IP数据报可以经过的最大路由器的个数,每经过处理它的路由,TTL就会减一。TTL为 0 时还没有到达目的地的数据报将会被丢弃,同时发送 ICMP 报文通知源主机。

MSL的单位为时间,TTL的单位为跳转数。所以MSL应该大于等于TTL变为0的时间,以确保报文已被丢弃。

TIME_WAIT等待的2MSL时间,可以理解为数据报一来一回所需要的最大时间

2MSL时间是从客户端接收到FIN后发送ACK开始计时的。如果在这个时间段内,服务器没有收到ACK应答报文段,会重发FIN报文段,如果客户端收到了FIN报文段,那么2MSL的时间将会被重置。如果在2MSL时间段内,没有收到任何数据报,客户端则会进入CLOSE状态。

4)等待2MSL的意义
1.保证客户端最后发送的ACK能够到达服务器,帮助其正常关闭。

由于这个ACK报文段可能会丢失,使得处于LAST_ACK状态的服务器得不到对已发送FIN报文段的确认,从而会触发超时重传。服务器会重发FIN报文段,客户端能保证在2MSL时间内收到来自服务器的重传FIN报文段,从而客户端重新发送ACK应答报文段,并重置2MSL计数。

假如客户端不等待2MSL就之间进入CLOSE状态,那么服务器会一直处于LAST_ACK状态。

当客户端发起建立SYN报文段请求建立新的连接时,服务端会发送RST报文段给客户端,连接建立的过程就会被终止。

2.防止已失效的连接请求报文段出现在本连接中。

TIME_WAIT等待的2MSL时间,确保本连接内所产生的所有报文段都从网络中消失,使下一个新的连接中不会出现这种旧的连接请求报文段。

5)TIME_WAIT状态过多有什么危害?
只有主动发起断开请求的一方才会进入TIME_WAIT状态!

1.占用系统资源

2.socket的TIME_WAIT状态结束之前,该socket占用的端口号将一直无法释放。如果服务器TIME_WAIT状态过多,占满了所有端口资源,则会导致无法创建新的连接。

6)如何解决TIME_WAIT状态过多?
最好的办法是尽量让客户端主动断开连接,除非遇到一些异常情况,如客户端协议错误、客户端超时等。

打开系统的TIME_WAIT重用和快速回收。

  • 22
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值