面试 Tcp的三次握手和四次挥手

一、TCP的三次握手及相关问题


1. TCP报文段首部格式


TCP报文段首部格式
  • 序号seq(sequence number): 表示本报文段所发送的数据的第一个字节序号

    • 比如序号字段值是301,携带的数据共有100个字节,表示本报文段数据的第一个字节的序号是301
  • 确认号ack(acknowledge number):表示期望收到对方下一个报文段的第一个数据字节的序号

    • 比如 B收到A发来的报文中:
      • 序号的字段值是501(序号表示的是数据的第一个字节序号),数据长度是200
      • 则:B收到了序号为501-700的数据---->说明 B期待收到的下一个数据的序列号应该是 701
      • 于是:B把返回给A的报文中 确认号(ack)设置为701
  • 确认ACK(AXKnowlegment): 仅仅当ACK为1时该字段才有效,建立连接后所有传送的报文段都必须把ACK置1

  • 同步SYN(Synchronize Sequence Numbers) 在建立连接时用来同步序号

    • SYN=1 ACK=0 表示是连接请求报文段
    • SYN=1 ACK=1 表示对方同意建立连接
  • 终止FIN(FINis) 用来释放一个连接

    • FIN = 1时表示要求释放连接

2. tcp三次握手详解


三次握手
  • 客户端的初始状态是 closed
  • 服务端的初始状态是 listen

2.1 第一次握手


客户端给服务端发送请求报文段

  • 此报文段的同步位 SYN = 1 ,表示这是一个请求报文段
  • 随机生成一个序列号 seq = x;
    • 随机生成一个序列号是为了网络安全,如果序列号不是随机的容易被黑客获取到初始序列号
  • 客户端的状态变成: SYN_SEND(同步已发送)
  • 这个报文段不能携带数据

2.2 第二次握手


服务端同意建立连接

  • SYN = 1 , ACK = 1 表示同意建立连接
  • 确认号是 ack = 1 ;
  • 随机生成一个初始序号 seq = y;
  • 不携带数据
  • 服务端状态变成 SYN_RCVD(同步已收到)

2.3 第三次握手


客户端再次向服务端给出确认

  • AXK = 1
  • 确认号 ack = y + 1 ; seq = x + 1 ;
  • 客户端状态变成 ESTABLISHED
  • 当服务端收到确认后也变成 ESTABLISHED

3. 为什么要三次握手,三次握手功能

三次握手功能生动解释

  • 第一次握手可以确认: 客户端发送数据功能正常 (A发出信号)
  • 第二次握手可以确认: 服务端接收发送功能均正常(B确认喜欢A,并发出信号)
  • 第三次握手可以确认: 客户端接收功能正常(第三个阶段才能确认A也喜欢B,第一个阶段并不能确认A喜欢B,第一个阶段A只是问了B)

4. 半连接队列和全连接队列


[图片上传失败...(image-e1545c-1578234377605)]

  • 第一次受到client的SYN之后,server处于SYN_RCVD状态,此时双方还没有完全建立连接,server会把这种状态下的请求连接放在一个队列里,称为半连接队列
  • 已经完成三次握手之后,建立起的连接会放在全连接队列中,如果队列满了可能会出现丢包,这样的队列称为全连接队列
  • server发送SYN和ACK包的重传:服务器发送完SYN-ACK包,如果未收到客户确认包,服务器进行首次重传,等待一段时间仍未收到客户确认包,进行第二次重传。如果重传次数超过系统规定的最大重传次数,系统将该连接信息从半连接队列中删除。注意,每次重传等待的时间不一定相同,一般会是指数增长,例如间隔时间为 1s,2s,4s,8s......

5. 三次握手中可以携带数据吗


第一次和第二次握手不可以携带信息,第三次可以携带信息,前两个阶段不可以携带信息。因为第三次握手的时候客户端才是ESTABLISHED状态,就上面那个生动的图来讲,只有第三次握手你确定了互相喜欢才可以携带一些信息(比如一起看电影、约会)

6. SYN 和 SYN 攻击


SYN Flood是当前最流行的DoS(拒绝服务攻击)与DDoS(分布式拒绝服务攻击)的方式之一,这是一种利用TCP协议缺陷,发送大量伪造的TCP连接请求,常用假冒的IP或IP号段发来海量的请求连接的第一个握手包(SYN包),被攻击服务器回应第二个握手包(SYN+ACK包),因为对方是假冒IP,对方永远收不到包且不会回应第三个握手包。导致被攻击服务器保持大量SYN_RECV状态的“半连接”,并且会重试默认5次回应第二个握手包,塞满TCP等待连接队列,资源耗尽(CPU满负荷或内存不足),让正常的业务请求连接不进来。


TCP的四次挥手及相关问题


1. 四次挥手详解


四次挥手

1.1 第一次挥手


client发出连接释放报文段

  • FIN = 1 (要求释放连接)
  • seq = u 前面传输数据的最后一个字节加1
  • client状态:FIN_WAIT1(终止等待1、等待server确认)

1.2 第二次挥手


server接收到释放报文段后发出确认 (这时候 client ---> server方向连接断了)

  • ACK = 1
  • ack = u + 1 ;
  • seq = v ; 已经发送的数据的最后一个字节序号加1
  • server 进入CLOSE_WAIT(等待关闭状态)
  • client 进入FIN_WAIT2(终止等待2状态),等待server发出释放确认报文段
  • 这时候CLIENT-SERVER的连接释放了,这时候与的TCP处于办关闭状态(half-close),这时候client已经没有数据要发了,但是这时候server还有可能向client发送数据

1.3 第三次挥手


这时候server发出连接释放报文段(想让 server--->client方向连接断掉)

  • FIN = 1;
  • 重复发送确认报文段: ACK = 1; ack = u + 1;
  • server状态: LAST_ACK 等待A确认

1.4 第四次挥手


client同意与server断开连接

  • ACK = 1;
  • client状态: TIME_WAIT 在2MSL之后变成CLOSED
  • server状态: CLOSED

1.5 通俗解释一下


四次挥手

2. 为什发送端需要等待 2MSL后关闭


MSL:(Maximum segment lifetime)最长报文寿命
为什么要等待两个msl?

  • 1.保证client发送的ACK可以成功到达server,如果client发送完就close了,万一报文丢失,server收不到client发来的ACK,就会超时重新进行第三次挥手,这个时间就是2MSL:即:超时等待时间+再次进行第三次挥手的事件

  • 2.防止“已失效的连接请求报文段”出现在本连接中。
    客户端在发送完最后一个ACK报文段后,再经过2MSL,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失,使下一个新的连接中不会出现这种旧的连接请求报文段


3. 为什么第二次挥手和第三次挥手不能合并


细心的同学发现,所谓四次挥手中的第二次和第三次就是把握手中的第二次拆来了。为什么不能合并?

  • 因为挥手过程和握手过程不同,前两次握手是不携带数据的只处理连接问题。挥手不仅要解决连接问题,还要解决数据传输问题,第二次挥手后,client只是不能发送数据了,但是并不说明不能接受数据。server可能还有数据要给client。所以二三两次不可以合并

引用博客


  • 本篇博客主要是在这篇博客基础上的修改:https://segmentfault.com/a/1190000020610336#item-1-4
  • 参考文档
    • https://blog.csdn.net/u014507230/article/details/45310847
    • https://blog.csdn.net/lengxiao1993/article/details/82771768
    • https://blog.csdn.net/qq_36865108/article/details/84885506
    • https://www.jianshu.com/p/7d0f91345483
    • https://cloud.tencent.com/developer/article/1115567
    • https://blog.csdn.net/wudiyi815/article/details/8505726
    • http://jm.taobao.org/2017/05/25/525-1/
    • https://www.jianshu.com/p/bbb6261cb13e
  • 书本才是最权威易懂的
    • 《谢希仁计算机网络第六版》
  • 转载标明链接哦

你可能感兴趣的:(面试 Tcp的三次握手和四次挥手)