TCP协议基本功能

190 阅读5分钟

tcp三次握手

为什么是三次而不是二次或四次更多?

A发起一个请求包,请求包可能会超时、丢包或没有异常,A在没有接收到B的响应包之前会不停的向B发送请求包;这时B收到A的请求包,并响应给A.如果A在一定次数或时间没有接收到B的相应就会放弃这次连接.

假如二次握手,B的请求不是有来有回,单向消息,而且还会有一个问题,就是之前A向B发送多个请求包,如果有一个请求包超时,A与B都完成通信,结束了连接.这时B收到A之前发送的超时请求包,会认为A又建立一次连接.但A不知道,这次的连接不会终止.

其实四次以及更多次也是可以的,但三次足够用,更多次握手也保证不了网络的可靠.

TCP包的序号,每次连接都会产生不同的序号(32位),在一定时间内不会重复;这样设计的原因?

A与B的第一次连接中有一个数据包超时,假如发送的数据包如果每次连接序号都从0开始,第一次发送0、1、2,在A与B第二次连接时,第二次发送0、1,由于超时的原因:第一次的2在第二次连接时B才收到,所以需要每次连接产生不同的序号. 这个序号就是三次握手中SYN,seq=x、SYN,ACK,seq=y中x与y

tcp四次挥手

TIME-WAIT(2分钟,报文最大生存时间)作用:

A发送B的响应包后就会进入这个状态,如果B在一定时间内没有收到A的响应包,B会从新发送请求包,同时确保B的请求包自然消亡,防止对下一个使用这个端口的新应用造成影响

TIME_WAIT的危害:

占用内存资源;
端口号资源的占用,无法创建新连接

TIME_WAIT优化方案

  • 方案一:Linux的内核tcp_tw_reuse选项
    如果连接是安全可控的,复用处于 TIME_WAIT 的套接字可以为新的连接所用
  • 什么是安全可用?
    只适用于连接发起方(C/S 模型中的客户端)
    对应的 TIME_WAIT 状态的连接创建时间超过 1 秒才可以被复用
  • 方案二:setsockopt方法
    SO_REUSEADDR 是用户的选项,SO_REUSEADDR 选项用来告诉操作系统内核,如果端口已被占用,但是 TCP 连接状态位于 TIME_WAIT ,可以重用端口
    “Address already in use”的错误信息:因为连接处于TIME_WAIT

数据包顺序、不丢包

AdvertisedWindow是滑动窗口的大小
MaxRcvBuffer:接收端最大缓存量

  • 假设4发送端确认了,5的ack丢失;6、7的数据包丢失
  • 方法一:超时重传,TCP 通过采样 RTT(数据包往返的时间) 的时间,然后进行加权平均,算出一个值,这个值是在一定范围动态变化的
  • 如果过了一段时间5、6、7都超时,重新发送,接收端发现5发送过了,直接丢弃5;6的ack收到了,7又丢失了.
  • 方法二:重传超时间隔加倍。遇到一次超时重传的时候,都会将下一次超时时间间隔设为先前值的两倍。两次超时,就说明网络环境差,不宜频繁反复发送。缺点:超时周期可能相对较长
  • 方法三:快速重传的机制,发送三个 6 的 ACK,要求下一个是 7,客户端收到 3 个,发现 7 丢了,不等超时,马上重发。
  • 方法四:SACK,在 TCP 头里加一个 SACK 的东西,可以将缓存的地图发送给发送方。例如可以发送 ACK6、SACK8、SACK9,有了地图,发送方一下子就能看出来是 7 丢了。

流量控制

滑动窗口: rwnd
假设一个最坏现象:

目前窗口大小是9
发送端将未发送的数据包全部发送,接收端又接收到几个数据包,窗口变成6

发送端发现窗口变成6,窗口没有滑动而是变小,这时接收端将数据都已接收,但不处理数据,窗口变成0

发送端的窗口是0,无法发送数据,接收方在处理数据后,窗口太小时不会更新窗口大小,达到一定大小才会更新

拥塞控制

滑动窗口: cwnd
tcp拥塞控制主要合理利用宽带资源;
发生拥塞的现象:包丢失和超时重传;一旦出现了这些现象就说明,发送数据量很大。

cwnd 呈指数性增长,有一个值 ssthresh 为 65535 个字节,超过这个值呈线性增长;
慢启动:网络超时,sshresh 设为 cwnd/2,cwnd 设为 1,但是这个方式太激进,会造成网络卡顿
快速重传:发现丢包,发送三次前一个包的 ACK,于是发送端就会快速的重传,cwnd 减半为 cwnd/2,然后 sshthresh = cwnd,当三个包返回的时候,继续呈线性增长
传统的方法会产生两个问题
第一个问题是丢包并不代表着通道满了。例如公网上带宽不满也会丢包,这个时候就认为拥塞了,其实是不对的。
第二个问题是 TCP 的拥塞控制要等到将中间设备缓存都满了,才发生丢包,从而降低速度,这时候已经晚了。其实 TCP 只要填满管道就可以了,不应该接着填,直到连缓存也填满。
优化这两个问题,TCP的BBR拥塞算法,它会找到一个平衡点,就是通过不断的加快发送速度,找到一个平衡点可以达到高带宽和低时延的平衡。