Contents

计算机网络-小林coding-TCP篇

本系列笔记为作者在跟随小林coding学习的时候做的笔记。感谢小林大大。加上自己的笔记

TCP 三次握手与四次挥手面试题

TCP 基本认识

TCP 头格式

https://imgconvert.csdnimg.cn/aHR0cHM6Ly9jZG4uanNkZWxpdnIubmV0L2doL3hpYW9saW5jb2Rlci9JbWFnZUhvc3QyLyVFOCVBRSVBMSVFNyVBRSU5NyVFNiU5QyVCQSVFNyVCRCU5MSVFNyVCQiU5Qy9UQ1AtJUU0JUI4JTg5JUU2JUFDJUExJUU2JThGJUExJUU2JTg5JThCJUU1JTkyJThDJUU1JTlCJTlCJUU2JUFDJUExJUU2JThDJUE1JUU2JTg5JThCLzYuanBn?x-oss-process=image/format,png
http头格式

为什么需要 TCP 协议? TCP 工作在哪一层?

IP无连接不可靠,TCP实现有连接可靠传输

传输层

什么是 TCP ?

TCP 是面向连接的、可靠的、基于字节流的传输层通信协议

  • 面向连接:「一对一」
  • 可靠的:保证报文到达接收端
  • 字节流:应用层消息可能会被操作系统「分组」成多个的 TCP 报文,需要应用层协议规定消息的边界

什么是 TCP 连接?

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

如何唯一确定一个 TCP 连接呢?

TCP 四元组可以唯一的确定一个连接:源地址,源端口,目的地址,目的端口

TCP 连接建立

TCP 三次握手过程是怎样的

https://cdn.xiaolincoding.com/gh/xiaolincoder/ImageHost4/%E7%BD%91%E7%BB%9C/TCP%E4%B8%89%E6%AC%A1%E6%8F%A1%E6%89%8B.drawio.png
TCP三次握手

如何在 Linux 系统中查看 TCP 状态?

netstat -napt 

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

  1. 避免历史连接(首要原因)
https://imgconvert.csdnimg.cn/aHR0cHM6Ly9jZG4uanNkZWxpdnIubmV0L2doL3hpYW9saW5jb2Rlci9JbWFnZUhvc3QyLyVFOCVBRSVBMSVFNyVBRSU5NyVFNiU5QyVCQSVFNyVCRCU5MSVFNyVCQiU5Qy9UQ1AtJUU0JUI4JTg5JUU2JUFDJUExJUU2JThGJUExJUU2JTg5JThCJUU1JTkyJThDJUU1JTlCJTlCJUU2JUFDJUExJUU2JThDJUE1JUU2JTg5JThCLzE5LmpwZw?x-oss-process=image/format,png
避免历史连接
  1. 同步双方初始序列号
  2. 避免资源浪费

什么是 SYN 攻击?如何避免 SYN 攻击?

短时间伪造不同 IP 地址的 SYN 报文占满服务端的半连接队列,后续再在收到 SYN 报文就会丢弃

TCP 三次握手的时候,Linux 内核会维护两个队列

  • 半连接队列,也称 SYN 队列
  • 全连接队列,也称 accept 队列
https://imgconvert.csdnimg.cn/aHR0cHM6Ly9jZG4uanNkZWxpdnIubmV0L2doL3hpYW9saW5jb2Rlci9JbWFnZUhvc3QyLyVFOCVBRSVBMSVFNyVBRSU5NyVFNiU5QyVCQSVFNyVCRCU5MSVFNyVCQiU5Qy9UQ1AtJUU0JUI4JTg5JUU2JUFDJUExJUU2JThGJUExJUU2JTg5JThCJUU1JTkyJThDJUU1JTlCJTlCJUU2JUFDJUExJUU2JThDJUE1JUU2JTg5JThCLzI2LmpwZw?x-oss-process=image/format,png

TCP 连接断开

TCP 四次挥手过程是怎样的?

https://imgconvert.csdnimg.cn/aHR0cHM6Ly9jZG4uanNkZWxpdnIubmV0L2doL3hpYW9saW5jb2Rlci9JbWFnZUhvc3QyLyVFOCVBRSVBMSVFNyVBRSU5NyVFNiU5QyVCQSVFNyVCRCU5MSVFNyVCQiU5Qy9UQ1AtJUU0JUI4JTg5JUU2JUFDJUExJUU2JThGJUExJUU2JTg5JThCJUU1JTkyJThDJUU1JTlCJTlCJUU2JUFDJUExJUU2JThDJUE1JUU2JTg5JThCLzMwLmpwZw?x-oss-process=image/format,png

图里面先关闭连接的是客户端,后关闭的是服务端,这顺序可以反过来

主动关闭连接的,才有 TIME_WAIT 状态

为什么挥手需要四次?

tcp是全双工通信

为什么 TIME_WAIT 等待的时间是 2MSL?

MSL 是 Maximum Segment Lifetime,报文最大生存时间,任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。

发送过去FIN还要接收ACK,一来一回需要等待 2 倍的时间,至少允许报文丢失一次触发超时重传

为什么需要 TIME_WAIT 状态?

  1. 保证「被动关闭连接」的一方,能被正确的关闭(主要)
  2. 防止历史连接中的数据,被后面相同四元组的连接错误的接收
https://cdn.xiaolincoding.com/gh/xiaolincoder/ImageHost4/%E7%BD%91%E7%BB%9C/TIME-WAIT%E8%BF%9E%E6%8E%A5%E6%AD%A3%E5%B8%B8%E5%85%B3%E9%97%AD.drawio.png

Socket 编程

https://imgconvert.csdnimg.cn/aHR0cHM6Ly9jZG4uanNkZWxpdnIubmV0L2doL3hpYW9saW5jb2Rlci9JbWFnZUhvc3QyLyVFOCVBRSVBMSVFNyVBRSU5NyVFNiU5QyVCQSVFNyVCRCU5MSVFNyVCQiU5Qy9UQ1AtJUU0JUI4JTg5JUU2JUFDJUExJUU2JThGJUExJUU2JTg5JThCJUU1JTkyJThDJUU1JTlCJTlCJUU2JUFDJUExJUU2JThDJUE1JUU2JTg5JThCLzM0LmpwZw?x-oss-process=image/format,png

accept 发生在三次握手的哪一步

https://cdn.xiaolincoding.com/gh/xiaolincoder/ImageHost4/%E7%BD%91%E7%BB%9C/socket%E4%B8%89%E6%AC%A1%E6%8F%A1%E6%89%8B.drawio.png

客户端调用 close 了,连接是断开的流程是什么?

https://imgconvert.csdnimg.cn/aHR0cHM6Ly9jZG4uanNkZWxpdnIubmV0L2doL3hpYW9saW5jb2Rlci9JbWFnZUhvc3QyLyVFOCVBRSVBMSVFNyVBRSU5NyVFNiU5QyVCQSVFNyVCRCU5MSVFNyVCQiU5Qy9UQ1AtJUU0JUI4JTg5JUU2JUFDJUExJUU2JThGJUExJUU2JTg5JThCJUU1JTkyJThDJUU1JTlCJTlCJUU2JUFDJUExJUU2JThDJUE1JUU2JTg5JThCLzM3LmpwZw?x-oss-process=image/format,png

TCP 重传、滑动窗口、流量控制、拥塞控制

重传机制

超时重传

https://cdn.xiaolincoding.com/gh/xiaolincoder/ImageHost2/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/TCP-%E5%8F%AF%E9%9D%A0%E7%89%B9%E6%80%A7/5.jpg?image_process=watermark,text_5YWs5LyX5Y-377ya5bCP5p6XY29kaW5n,type_ZnpsdHpoaw,x_10,y_10,g_se,size_20,color_0000CD,t_70,fill_0

RTT 指的是数据发送时刻到接收到确认的时刻的差值,也就是包的往返时间。

超时重传时间 RTO 的值应该略大于报文往返 RTT 的值

https://cdn.xiaolincoding.com/gh/xiaolincoder/ImageHost2/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/TCP-%E5%8F%AF%E9%9D%A0%E7%89%B9%E6%80%A7/9.jpg?image_process=watermark,text_5YWs5LyX5Y-377ya5bCP5p6XY29kaW5n,type_ZnpsdHpoaw,x_10,y_10,g_se,size_20,color_0000CD,t_70,fill_0

快速重传

https://cdn.xiaolincoding.com/gh/xiaolincoder/ImageHost2/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/TCP-%E5%8F%AF%E9%9D%A0%E7%89%B9%E6%80%A7/10.jpg?image_process=watermark,text_5YWs5LyX5Y-377ya5bCP5p6XY29kaW5n,type_ZnpsdHpoaw,x_10,y_10,g_se,size_20,color_0000CD,t_70,fill_0

SACK 方法

SACK( Selective Acknowledgment), 选择性确认,SACK字段记录在ACK后面的已收到的字节

https://cdn.xiaolincoding.com/gh/xiaolincoder/ImageHost2/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/TCP-%E5%8F%AF%E9%9D%A0%E7%89%B9%E6%80%A7/11.jpg?image_process=watermark,text_5YWs5LyX5Y-377ya5bCP5p6XY29kaW5n,type_ZnpsdHpoaw,x_10,y_10,g_se,size_20,color_0000CD,t_70,fill_0

Duplicate SACK

SACK 字段标记重复接收字节

https://cdn.xiaolincoding.com/gh/xiaolincoder/ImageHost2/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/TCP-%E5%8F%AF%E9%9D%A0%E7%89%B9%E6%80%A7/13.jpg?image_process=watermark,text_5YWs5LyX5Y-377ya5bCP5p6XY29kaW5n,type_ZnpsdHpoaw,x_10,y_10,g_se,size_20,color_0000CD,t_70,fill_0

滑动窗口

Window字段告诉发送端自己还有多少缓冲区可以接收数据。

发送方的滑动窗口

https://cdn.xiaolincoding.com/gh/xiaolincoder/ImageHost2/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/TCP-%E5%8F%AF%E9%9D%A0%E7%89%B9%E6%80%A7/19.jpg?image_process=watermark,text_5YWs5LyX5Y-377ya5bCP5p6XY29kaW5n,type_ZnpsdHpoaw,x_10,y_10,g_se,size_20,color_0000CD,t_70,fill_0
  • SND.WND:表示发送窗口的大小(大小是由接收方指定的)
  • SND.UNA(Send Unacknoleged):指向已发送但未收到确认的第一个字节的序列号
  • SND.NXT:指向未发送但可发送范围的第一个字节的序列号

可用窗口大小 = SND.WND -(SND.NXT - SND.UNA)

接收方的滑动窗口

https://cdn.xiaolincoding.com/gh/xiaolincoder/ImageHost2/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/TCP-%E5%8F%AF%E9%9D%A0%E7%89%B9%E6%80%A7/20.jpg
  • RCV.WND:表示接收窗口的大小
  • RCV.NXT:指向期望从发送方发送来的下一个数据字节的序列号

流量控制

操作系统缓冲区与滑动窗口的关系

先收缩窗口,过段时间再减少缓存

窗口关闭

窗口大小为 0 阻止发送方给接收方传递数据,直到窗口变为非 0 为止,这就是窗口关闭

TCP 连接一方收到对方的零窗口通知时启动持续计时器,计时器超时发送窗口探测 ( Window probe ) 报文获取接收窗口大小,如果接收窗口仍然为 0,那么收到这个报文的一方就会重新启动持续计时器

窗口探测的次数一般为 3 次,每次大约 30-60 秒(不同的实现可能会不一样)。如果 3 次过后接收窗口还是 0 的话,有的 TCP 实现就会发 RST 报文来中断连接。

糊涂窗口综合症

接收方腾出几个字节并告诉发送方现在有几个字节的窗口,而发送方会义无反顾地发送这几个字节,这就是糊涂窗口综合症

解决办法:

  • 让接收方不通告小窗口:「窗口大小」小于 min( MSS,缓存空间/2 ) ,也就是小于 MSS 与 1/2 缓存大小中的最小值时,就会向发送方通告窗口为 0
  • 让发送方避免发送小数据: Nagle 算法(延时处理),只在下面两个条件下发送数据:1.窗口大小 >= MSS 并且 数据大小 >= MSS。2.收到之前发送数据的 ack 回包。

两个都用上才能避免糊涂窗口综合症

拥塞控制

目的:避免「发送方」的数据填满整个网络

拥塞窗口 cwnd是发送方维护的一个的状态变量,根据网络的拥塞程度动态变化的。

接收窗口 rwnd

发送窗口的值是swnd = min(cwnd, rwnd)

慢启动

发送方每收到一个 ACK,拥塞窗口 cwnd 的大小就会加 1 (指数性的增长),图中纵坐标的单位是MSS,横坐标是传输轮数

https://cdn.xiaolincoding.com/gh/xiaolincoder/ImageHost2/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/TCP-%E5%8F%AF%E9%9D%A0%E7%89%B9%E6%80%A7/27.jpg?image_process=watermark,text_5YWs5LyX5Y-377ya5bCP5p6XY29kaW5n,type_ZnpsdHpoaw,x_10,y_10,g_se,size_20,color_0000CD,t_70,fill_0

慢启动门限 ssthresh (slow start threshold)

  • cwnd < ssthresh 时,使用慢启动算法
  • cwnd >= ssthresh 时,就会使用「拥塞避免算法」

拥塞避免算法

每当收到一个 ACK 时,cwnd 增加 1/cwnd

https://cdn.xiaolincoding.com/gh/xiaolincoder/ImageHost2/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/TCP-%E5%8F%AF%E9%9D%A0%E7%89%B9%E6%80%A7/28.jpg?image_process=watermark,text_5YWs5LyX5Y-377ya5bCP5p6XY29kaW5n,type_ZnpsdHpoaw,x_10,y_10,g_se,size_20,color_0000CD,t_70,fill_0

拥塞发生

  1. 超时重传
  • ssthresh 设为 cwnd/2
  • cwnd 重置为 1 (是恢复为 cwnd 初始化值,我这里假定 cwnd 初始化值 1)
https://cdn.xiaolincoding.com/gh/xiaolincoder/ImageHost2/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/TCP-%E5%8F%AF%E9%9D%A0%E7%89%B9%E6%80%A7/29.jpg?image_process=watermark,text_5YWs5LyX5Y-377ya5bCP5p6XY29kaW5n,type_ZnpsdHpoaw,x_10,y_10,g_se,size_20,color_0000CD,t_70,fill_0

重新开始慢启动

  1. 快速重传

收到3个一样的ACK

  • cwnd = cwnd/2 ;
  • ssthresh = cwnd;

接着快速恢复算法(但是先加3,因为快速重传收到了3个ACK)

https://cdn.xiaolincoding.com/gh/xiaolincoder/ImageHost4@main/%E7%BD%91%E7%BB%9C/%E6%8B%A5%E5%A1%9E%E5%8F%91%E7%94%9F-%E5%BF%AB%E9%80%9F%E9%87%8D%E4%BC%A0.drawio.png?image_process=watermark,text_5YWs5LyX5Y-377ya5bCP5p6XY29kaW5n,type_ZnpsdHpoaw,x_10,y_10,g_se,size_20,color_0000CD,t_70,fill_0

服务端挂了,客户端的 TCP 连接还在吗

服务端挂了,客户端的 TCP 连接还在吗

  • 服务端进程挂,发生4次握手
  • 服务端宕机,超时重传一定次数断开,开启了keepalive则在探测报文检测到服务端宕机并断开

拔掉网线后, 原本的 TCP 连接还存在吗?

拔掉网线后, 原本的 TCP 连接还存在吗?

不会直接影响TCP连接

TCP校验和和UDP校验和的计算

都需要添加伪首部(共有12字节(前96Bits),包含如下信息:源IP地址4字节、目的IP地址4字节、保留字节(置0)1字节、传输层协议号(TCP是6)1字节、TCP报文长度(报头+数据)2字节)

  1. 首先,把伪首部、TCP报头、TCP数据分为16位的字,如果总长度为奇数个字节,则在最后增添一个位都为0的字节
  2. 把TCP报头中的校验和字段置为0
  3. 反码相加法累加所有的16位字(进位也要累加)
  4. 对计算结果取反,作为TCP的校验和

发送RST的场景

  • 被connect不存在的端口
  • 已经关闭或崩溃的连接被发送数据
  • close(sockfd)
  • 重启后收到保活探针

发送RST的主机连接立刻进入CLOSED状态,收到RST的立刻终止连接

PSH,URG位作用

PUSH推

让接收缓冲区收到包后直接上推到应用层处理

URGENT紧急

接收区方必须通知应用层

 |