2023-07-20
网络协议
00
请注意,本文编写于 218 天前,最后修改于 20 天前,其中某些信息可能已经过时。

目录

传输层概述
UDP
UDP的首部
UDP的特点
UDP的优缺点
TCP协议
TCP协议的特点
TCP协议的头部
可靠传输的基本原理
流量控制
拥塞控制
BBR拥塞控制算法
三次握手
四次挥手
TCP与UDP的区别
SYN攻击
套接字

本文将介绍传输层的两个协议 TCP和UDP,系统讲解TCP可靠传输、拥塞控制、三次握手四次挥手。

常见问题

  • UDP和TCP的区别
  • 为什么需要三次握手、四次挥手,为什么挥手多一次?
  • 拥塞控制的原理?
  • 什么是SYN攻击?

传输层概述

传输层是面向通信过程的最高层了,它工作在终端设备,管理端到端的通信连接 image.png

在上一篇文章中讲过,通过网络层IP协议,解决了网络通信问题,可以把A计算机(浏览器)与B计算机(网站后台服务器)的通信看成 A --> 虚拟的互联网络 --> B,不管A与B运行的实例都是进程,因此传输层协议可以看做进程与进程之间的通信

与 Unix域套接字和共享内存只能在单机进程间通信不同, 网络通信可以在单机通信也可以跨网络通信

那么计算机如何识别是与哪一个进程进行通信呢? -- 端口

  • 使用端口(Port)来标记不同的网络进程
  • 端口(Port)使用16比特位表示(0~65535)
FTPHTTPHTTPSDNSTELNET
21804435323

传输层主要就两种协议UDP和TCP

UDP

  • UDP(User Datagram Protocol: 用户数据报协议)
  • UDP是一个非常简单的协议

数据报(Datagram)

  • 数据报(是UDP协议中一个非常重要的特征
  • 数据报是应用层传输过来的完整数据
  • 对这个数据UDP不对它进行任何处理(不合并、不拆分)
  • 所以UDP数据的长度由应用层数据的长度决定

UDP协议被包裹在IP数据包中

image.png

UDP的首部

image.png

  • 校验和 是检测UDP报文传输中是否出错(使用的是上一篇文章中说的CRC循环冗余检测算法)

对比IP协议头部 和 TCP协议头部,可以看出UDP非常简单

UDP的特点

  • UDP是无连接协议
    • 有连接 如打电话的过程
  • UDP不能保证可靠的交付数据
  • UDP是面向报文传输的(内容里面即是应用层数据)
  • UDP没有拥塞控制
  • 首部开销小 总共8字节

UDP的优缺点

  • 数据包在传输过程中容易丢失
  • 大文件会被拆分成很多小的数据包来传输,这些小的数据包会经过不同的路由,并在不同的时间到达接收端,而 UDP 协议并不知道如何组装这些数据包,从而把这些数据包还原成完整的文件。
  • 虽说UDP不能保证数据的可靠性,但传输速度却非常快,所以UDP会关注速度,但对数据完整性要求没有那么严格的领域,如在线视频、互动游戏。

为了解决UDP丢包问题和无法传输大文件问题,引入了TCP协议。

TCP协议

  • TCP(Transmission Control Protocol: 传输控制协议)
  • TCP协议是计算机网络中非常复杂的一个协议

TCP数据包也是被包裹在IP协议中

image.png

TCP协议的特点

  • TCP是面向连接的协议
    • 类似打电话的过程,
  • TCP的一个连接有两端(点对点的通信)
  • TCP提供可靠的传输服务
    • 拥塞控制、重发机制
  • TCP协议提供全双工的通信
  • TCP是面向字节流的协议
    • 字节流 流入流出进程的字节序列
    • 取出数据包中的某一段 (可能进行合并也可能进行分拆)进行传输

TCP协议的头部

image.png

  • 序号
    • 023210 至 2^{32}-1
    • 一个字节一个序号
    • 代表传输的第一个字节的序号
  • 确认号
    • 和序号配合使用 也是 023210 至 2^{32}-1 一个字节一个序号
    • 代表期望收到的下一个数据的首字节序号
    • 比如当前报文序号为501,数据报的长度100字节,那么确认号就是600
    • 收到确认号 代表 前 确认号-1个字节的数据都已经收到
  • 数据偏移
    • 占4位:0~15,单位为:32位字
    • 由于TCP首部有可选的TCP选项的存在,所以需要纪录数据偏离首部的距离
    • 我们可以计算一下TCP首部有多少字节
    • 20个固定字节 最大偏移 15*4 即 20-60字节
  • TCP标记
    • 占6位,每位各有不同的意义
    • URG/ACK/PSH/PST/SYN/FIN
  • 窗口
    • 占16位:0021612^{16}-1
    • 窗口指明允许对方发送的数据量
    • 比如确认号501 窗口值1000,那么从501到1500这么多字节的数据都可以接受的
  • 校验和 同UDP校验和
  • 紧急指针
    • 紧急数据(URG=1)
    • 指定紧急数据在报文的位置
  • TCP选项
    • 最多40字节, 用于支持未来的拓展
  • 填充,填充为32bit(字)的整数倍

TCP标记

标记含义
URGUrgent: 紧急位,URG=1,表示紧急数据
ACKAcknowledgement: 确认位,ACK=1,确认号才生效
PSHPush: 推送位,PSH=1,尽快地把数据交付给应用层
PSTReset: 重置位,RST=1,重新建立连接
SYNSynchronization: 同步位,SYN=1 表示连接请求报文
FINFinish: 终止位,FIN=1 表示释放连接

头部有固定20个字节

可靠传输的基本原理

  • 停止等待协议
  • 连续ARQ协议

TCP可靠传输的原理.jpg

  • TCP的可靠传输基于连续ARQ协议
  • TCP的滑动窗口以字节为单位

对TCP选择重传的理解

  • TCP报文丢失是指整个片段的丢失而不是丢失某个字节,这时候需要重传这一片段段的字节
  • TCP将多个丢失的报文起止序列号放入 TCP选项中,告知发送端重新发送
    • TCP选项最多40字节,每个序列号是4字节,也就是能存储10个序列号
    • 每两个序列号是一个片段,一个片段可以由多个连续报文组成。

流量控制

通过窗口大小控制对方发送速率

image.png

我们在延伸一下

接收方告知发送方窗口为0后

发送方还是会一直等待,,,

接收方会对这些数据进行处理然后交给应用层。一段时间后它又可以接受消息了, 这时候接收方还可以给发送方发送消息说当前我的窗口可以接受1000字节数据了(rwnd=1000)。

假设该报文丢失了(TCP的可靠传输只针对数据,对特殊的消息是没有超时重传的机制)

接收方以为已经告知了发送方窗口调整的通知,也会继续等待

这是就形成死锁的情况

为了解决这个问题, TCP就引入了 坚持定时器, 这样就是窗口调整数据发生丢失 也不会造成死锁。

坚持定时器

  • 当接收到窗口为0的消息,则启动坚持定时器
  • 坚持定时器每隔一段时间发送一个窗口探测报文

拥塞控制

如何衡量网络用塞

  1. 以丢包作为依据
  2. 以探测带宽作为依据

由于TCP发送不定长字节流,所以天然的容易占满代码。 网络带宽 = min(拥塞窗口,通告窗口)

慢启动

  • 先发送一个报文
  • 收到ack后再发送2个报文
  • 收到2个ack确认,就发送4个报文
  • 依次类推, 这个过程叫做慢启动

慢启动要和拥塞避免一起使用才行,否则会大量丢包

拥塞避免

  • 达到慢启动阈值后以现行方式增加cwnd
    • cwnd+=SMSS
  • 当发现丢包后将将阈值调整为原来的一半,然后重新慢启动
  • 达到阈值,以线性增长

image.png

快速重传

  • 假设有一个大文件传输
  • 当发生丢包时,接收端只能回复丢包前ack(前一个报的最大序列号)
  • 发送端收到多个重复确认ack,不能再一直发送下去,因为接收端无法组装数据交付给应用端了。
  • 如果从连续确认的ack开始从新发送,这样效率低,
  • 应该只需发送丢失的部分数据包即可。
  • 所欲制定了个策略,当收到3个重复失序ACK时,不在等待定时器的触发,立刻基于快速重传机制重新发送报文段 image.png

快速恢复

  • 当快速重传发生丢包时,一定需要重新慢启动吗?这样效率很低,
  • 改进方案,适当的将网速降下来一点

image.png

BBR拥塞控制算法

2016年google提出了以测量驱动的算法,对TCP的拥塞控制有大幅提升。 Linux4.9内核引入,QUIC使用

image.png

  • 网络丢包我们可以抽象为瓶颈路由器造成的
  • 随着内存价格降低,路由器内存增大,可以缓存更多的报文,也造成RTT更高
  • 使用以丢包为依据的算法会造成高时延和大量丢包

最佳控制点 带宽.drawio.png

  • 有了最佳控制点, 当RTT增加时,我们就可以测量出带宽BW。
  • 当然实际算法要复杂很多,网络带宽是会变化的、RTT有误差等

三次握手

image.png 我来翻译一下上图

  • SYN=1 表示请求建立连接
  • seq=x seq=y 表示当前请求的首字节的序列号
  • ACK=1 表示我知道你的序列号是什么了
  • ack=x+1 ack=y+1 表示期望接收的下一个字节的序号
  • 发送方是在第二次请求时建立连接,接收方是在第三次请求时建立连接

为什么需要三次握手

  • 网上有一种说法 是 第一次握手确定用户端能发,第二次握手确定服务端能收能发,第三次握手是客户端能收。貌似有道理😇
  • 其实不是这样的, 三次握手是为了解决已经失效的连接请求报文传送到对方,引起错误
  • image.png
  • 因为TCP的丢包重传机制和网络延时问题,第一次发送的请求经过可很长时间才得到服务端,由于超时,客户端重发请求,第二次请求比第一次请求先到到服务端,此时服务端就建立了两个连接。
  • 如果使用第三次握手 服务端收到响应后立即回复,客户端收到请求后建立了连接, 此时第一个跑的慢的报文也到达服务端了,服务端也回应了,由于客户端已经建立连接,会把后面的请求丢弃掉。

Q:TCP是否每次连接都需要三次握手?

  • TCP有个机制 TFO(TCP fast open)快速连接
  • 第一次握手
    • SYN在fast open带上cookie
    • 服务端产生cookie,在ACK返回改cookie给客户端
    • 客户端存储cookie
  • 之后
    • 客户端带有cookie
    • 服务端验证该cookie,有效,在返回ACK的同时,将数据直接返回给应用层,无需3次握手
    • 少一次ACK的RTT(round-trip time,往返时延)

四次挥手

image.png

Q:为什么断开连接比建立连接多一次?

  • 服务端接收到客户端的请求后,还有一些数据没发送完,先回应客户端我知道了吗,等处理完以后再告知客户端我已经准备好了可以关闭连接了。

等待定时器

  • 等待定时器会等待2MSL后才关闭连接
  • MSL是最大报文段寿命
  • 一般MSL为2分钟,2MSL即4分钟
  • 由于一个TCP占用一个端口,断开连接后该端口无法使用,只能等到2MSL才能再次使用这个端口

为什需要等待定时器?

  • 在启动等待定时器时,最后一个报文服务端还没接收到,等待2MSL确保发送方的ACK可以到达接收方, 如果还没收到则服务端会重发
  • 另外等待2MSL,确保所有报文都已经过期

TCP与UDP的区别

TCPUDP
是否连接面向连接无连接
是否可靠可靠传输,流量控制、拥塞控制、重传机制不可靠传输
连接对象个数只能是一对一通信支持一对一,一对多,多对一和多对多交互通信
传输方式面向字节流面向报文
首部开销20 - 60 字节8 字节
适用场景适用于要求可靠传输的应用,例如文件传输、金融交易、MQ、可靠通信适用于实时应用(IP 电话、视频会议、语音、直播等)

SYN攻击

  • 半连接 & 全连接
    • 在三次握手中,当客户端发送SYN到服务端,服务端收到以后回复ACK和SYN,状态由LISTEN变为SYN_RCVD,此时这个连接就被推入了SYN队列,也就是半连接队列。
    • 当客户端返回ACK, 服务端接收后,三次握手完成。这个时候连接等待被具体的应用取走,在被取走之前,它会被推入另外一个 TCP 维护的队列,也就是全连接队列。
  • SYN flood攻击 客户端短时间内大量发送SYN:
    • 服务端的大量返回ACK,半连接池吃紧
    • 接收不到客户端的ACK,服务端超时重发

如何解决?

  • 服务端加大半连接池
  • SYN cookie:在接受达到SYN后不立即分配资源,根据这个SYN算出一个cookie,在ACK中返回给客户端,客户端在ACK里加上cookie,校验合法后分配资源

套接字

  • 使用端口(Port)来标记不同的网络进程
  • 端口(Port)使用16比特位表示(0~65535)

域套接字与网络套接字

  • 网络套接字会在协议栈走一遭

  • 传输层--》网络层--》网络接口层 --》网络接口层--》网络层--》传输层

  • 域套接字 通过与套接字文件来传输, 开销更小

本文作者:郭敬文

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!