TCP 三次握手四次挥手

TCP 的基本信息

  • 序列号:在建立连接时,由计算机随机生成的随机数,作为其初始值,通过SYN 包传给接收端的主机,每发送一次数据,就累加一次该数据字节数大小,用来解决网络包乱序问题。
  • 确认应答号:指下一次期望收到的数据的序列号,发送端收到这个确认应答以后,可以认为在这个序号之前的数据都被正常接收,用来解决不丢包问题。
  • 控制位:ACK 该位为1时,确认应答的字段变为有效,TCP 规定除了最初建立连接的SYN包之外,该位必须设置为1。 RST为1,表示TCP连接中出现异常必须强制断开连接。 SYN:该位为1时,表示希望建立连接,在其序列号的字段进行序列号的初始值的设定,FIN 为1时,表示今后不会再有数据发送,希望断开连接。
    IP 层是不可靠的,它不保证网络包的交付、不保证网络包的按序交付、也不保证网络包中的数据的完整性。如果要保证网络数据包的可靠性,那么就需要上层的TCP协议负责。他保证接收端接受的网络包时无损坏、无间隔、非冗余和按序的。TCP的链接是字节流形式,无论我们消息有多大都可以进行传输,并且消息是有序的,对前一个消息没有接受的时候,即使它先收到了后面的字节,那么也不能扔给应用层去处理,同时对重复的报文会自动丢弃。

建立一个TCP 连接时需要客户端以及服务端达成上述的三个信息的共识:

  • Socket: 由IP 地址和端口号组成
  • 序列号:用来解决乱序问题
  • 窗口大小: 用来做流量控制

建立一个TCP四元组包括如下:

  • 源地址
  • 源端口
  • 目的地址
  • 目的端口

一旦完成三次握手,双方都处于ESTABLISHED状态,此时连接就已经建立完成了,客户端和服务端就可以相互发数据了。

为什么是三次握手?不是两次、四次?

  • 避免历史连接
    三次握手的首要原因就是为了防止旧的重复连接初始化造成混乱。
    TCP 三次握手四次挥手
  • 同步双方初始序列号
    序列号是可靠传输的一个关键因素,他的作用是:1、接受方可以去除重复数据,2、接受方可以根据数据包中的序列号按序接受 3、可以标识发送出去的数据包,那些是已经被对方收到的。

避免资源浪费

如果客户端的 SYN 阻塞了,重复发送多次SYN 报文,因为服务器不清楚客户端是否收到了自己发送的建立连接的ACK 确认信号,所以每收到一个SYN,就只能先主动建立一个连接。这样造成了资源的浪费。

为了达到最佳的传输效能,TCP 协议在建立连接的时候通常需要协商双方的MSS值,当TCP层发现数据超过了MSS时,则就会先进行分片,当然由它形成的IP包的长度也就不会大于MTU, 自然也就不会进行IP 分片了。经过一个TCP 分片之后,进行重发的时候是以MSS为单位,而不用重传所有的分片,大大增加了重传的效率。

SYN 攻击

TCP 建立连接时需要三次握手的,假设攻击者短时间内,伪造了不同的IP 地址的SYN 报文,服务端每接受到一个SYN 报文就进入SYN_RCVD 状态,但是服务端发送出去的ACK + SYN 报文,无法得到未知IP 主机的ACK应答,久而久之就会沾满服务端的SYN 接受队列,使得服务器不能为正常用户服务。
LINUX 内核SYN(未完成连接建立) 队列与Accpet(以完成连接建立)队列是如何工作的?
TCP 三次握手四次挥手

  • 当如无端接收到客户端的SYN 报文时候,将其加入到内核的SYN 队列
  • 接着发送SYN + ACK给客户端,等待客户端回应ACK 报文。
  • 服务端接收到ACK 报文后,从SYN 队列移除到Accept 队列。
  • 应用通过调用accpet() socket 接口,从 Accept 队列中取出连接。

TCP 连接的断开

只有主动关闭连接的,才会有TIME_WAIT状态
需要TIME_WAIT状态主要是两个原因:

  • 防止旧的连接的数据包,经过2MSL这个时间,足以让两个方向上的数据包都被丢弃,使原来连接的数据包在网络中都自然消失,再出现的数据包一定都是新建立连接所产生的。
  • 等待足够的时间保证最后的ACK能让被动关闭方接受,从而帮助其正常关闭。
    TIME_WAIT 状态主要的危害有两种:
  • 对内存资源占用
  • 对端口资源的占用,一个TCP 连接至少消耗一个本地端口。

Socket 编程

TCP 三次握手四次挥手

  • 服务端和客户端初始化socket,得到文件描述符
  • 服务端调用 bind 将绑定在IP地址和端口
  • 服务端调用 listen, 进行监听
  • 服务端调用accept, 等待客户端连接
  • 客户端调用connect, 向服务器端的地址和端口发起连接请求
  • 服务器端调用accept 返回用于传输的 socket 文件描述符;
  • 客户端调用 write 写入数据; 客户端调用read 读取数据;
  • 客户端断开连接,会调用close, 那么服务端 read 读取数据的时候,就会读取到EOF, 待处理完数据之后,服务端会调用close, 表示连接关闭。

注意的是当服务端调用accept 时,连接成功了就会返回一个已完成的socket,后续用来传输数据,所以监听的socket 和真正用来传送数据的socket 时俩socket,一个作监听socket, 一个叫做已完成连接socket

  • LINUX 内核中会维护两个队列
    未完成连接队列(SYN队列):接到一个SYN建立连接请求,处于SYN_RCVD 状态
    已完成的连接队列(Accept队列): 已经完成了TCP的三次握手过程,处于ESTABLISHED 状态。
    TCP 三次握手四次挥手
    客户端的connect 成功返回时在第二次握手,服务端accept 成功返回时在第三次握手

原文链接: https://www.cnblogs.com/wsl-hitsz/p/14544580.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

    TCP 三次握手四次挥手

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/397331

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年4月10日 上午9:29
下一篇 2023年4月10日 上午9:29

相关推荐