C++/java网络常见题目1_TCP三次握手及四次挥手

TCP

定义:TCP(Transmission Control Protocol 传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。

TCP报头

  1. 源端口和目的端口,各占2个字节,分别写入源端口和目的端口;
  2. 序号是发送数据包中的第一个字节的序列号,TCP连接中传送的字节流中的每个字节都按顺序编号。
  3. 确认号,占4个字节,表示下一次应该收到的数据的序列号。发送端收到这个确认应答以后可以认为在这个序号以前的数据都已经被正常接收。
  4. 数据偏移,占4位,它指出TCP报文的数据距离TCP报文段的起始处有多远;
  5. 保留,占6位,保留今后使用,但目前应都位0;
  6. 字段 含义
    URG 紧急指针是否有效。为1,表示某一位需要被优先处理。
    ACK 仅当ACK=1时,确认号字段才有效。
    PSH 提示接收端应用程序立即从TCP缓冲区把数据读走。
    RST 对方要求重新建立连接,复位。
    SYN 请求建立连接,并在其序列号的字段进行序列号的初始值设定。建立连接,设置为1.
    FIN 希望断开连接。当FIN=1,表明此报文的发送方的数据已经发送完毕,并且要求释放;
  7. 窗口,占2字节,指的是通知接收方,发送本报文你需要有多大的空间来接受;
  8. 检验和,占2字节,校验首部和数据这两部分;
  9. 紧急指针,占2字节,只有URG标志位被设置时该字段才有意义,表示紧急数据相对序列号(Sequence Number字段的值)的偏移
  10. 选项,长度可变,定义一些其他的可选的参数。

三次握手:建立连接


第一次握手:建立连接时,客户端发送请求报文(SYN=1,同时选择一个初始序列号 seq=x)到服务器,并进入SYN_SEND状态,等待服务器确认;

第二次握手:服务器收到请求报文,同意连接,则发出确认报文(ACK=1,SYN=1,确认号是ack=x+1,同时也要为自己初始化一个序列号 seq=y),此时服务器进入SYN_RECV状态;

第三次握手:客户端收到服务器的确认后,还要向服务器给出确认报文(ACK=1,确认号是ack=y+1,自己的序列号为 seq=x+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。

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

 

四次挥手:释放连接


  1. 客户端进程发出连接释放报文(FIN=1,其序列号为seq=u,其中u为前面已经传送过来的数据的最后一个字节的序号加1),并且停止发送数据。

  2. 服务器收到连接释放报文,发出确认报文(ACK=1,ack=u+1,并且带上自己的序列号seq=t),进入CLOSE_WAIT状态,客户端收到这个ACK,进入FIN_WAIT2状态。此阶段若服务器发送数据,客户端仍要接受。

  3. 服务器将最后的数据发送完毕后,就向客户端发送连接释放报文(FIN=1,ACK = 1,ack=u+1,seq=w,其中seq不是t的原因是可能在此过程中发送了数据,故序号增加改变),服务器进入LAST_ACK状态

  4. 客户端收到服务器的连接释放报文后,必须发出确认报文(ACK=1,ack=w+1,自己的序列号是seq=u+1),进入TIME_WAIT状态,服务端收到ACK,进入CLOSE状态。

TIME_WAIT

  • TIME_WAIT 是主动关闭链接时形成的,等待2MSL时间,约4分钟。主要是防止最后一个ACK丢失。 由于TIME_WAIT 的时间会非常长,因此server端应尽量减少主动关闭连接

CLOSE_WAIT

  • CLOSE_WAIT是被动关闭连接是形成的。根据TCP状态机,服务器收到客户端发送的FIN,则按照TCP实现发送ACK,因此进入CLOSE_WAIT状态。但如果服务器端不执行close(),就不能由CLOSE_WAIT迁移到LAST_ACK,则系统中会存在很多CLOSE_WAIT状态的连接。此时,可能是系统忙于处理读、写操作,而未将已收到FIN的连接,进行close。此时,recv/read已收到FIN的连接socket,会返回0。

为什么需要 TIME_WAIT 状态?

  • 假设最终的ACK丢失,服务器将重发FIN,客户端必须维护TCP状态信息以便可以重发最终的ACK,否则会发送RST,结果服务器认为发生错误。TCP实现必须可靠地终止连接的两个方向(全双工关闭),客户端必须进入 TIME_WAIT 状态,因为客户端可能面 临重发最终ACK的情形。

为什么 TIME_WAIT 状态需要保持 2MSL 这么长的时间?

  1. 为了保证A发送的最后一个ACK报文能够到达B。这个ACK报文段有可能丢失,因而使处在LAST-ACK状态的B收不到对已发送的FIN+ACK报文段的确认。B会超时重传这个FIN+ACK报文段,而A就能在2MSL时间内收到这个重传的FIN+ACK报文段。如果A在TIME-WAIT状态不等待一段时间,而是在发送完ACK报文段后就立即释放连接,就无法收到B重传的FIN+ACK报文段,因而也不会再发送一次确认报文段。这样,B就无法按照正常的步骤进入CLOSED状态。
  2. A在发送完ACK报文段后,再经过2MSL时间,就可以使本连接持续的时间所产生的所有报文段都从网络中消失。这样就可以使下一个新的连接中不会出现这种旧的连接请求的报文段。

 建立连接为什么需要三次握手,两次不可以吗?

  • 第三次握手是为了防止:如果客户端迟迟没有收到服务器返回确认报文,这时会放弃连接,重新启动一条连接请求,但问题是:服务器不知道客户端没有收到,所以他会收到两个连接,浪费连接开销。如果每次都是这样,就会浪费多个连接开销。
  • 假设客户端请求建立连接,发给服务器SYN包等待服务器确认,服务器收到确认后,如果是两次握手,假设服务器给客户端在第二次握手时发送数据,数据从服务器发出,服务器认为连接已经建立,但在发送数据的过程中数据丢失,客户端认为连接没有建立,会进行重传。假设每次发送的数据一直在丢失,客户端一直SYN,服务器就会产生多个无效连接,占用资源,这个时候服务器可能会挂掉。这个现象就是我们听过的“SYN的洪水攻击”。

本系列文章目的为个人准备面试的简单总结,文中多有不足,敬请批评指正!

参考:

https://blog.csdn.net/qzcsu/article/details/72861891
https://blog.csdn.net/ZWE7616175/article/details/80432486

猜你喜欢

转载自blog.csdn.net/zzhang_12/article/details/81285860