记录一些学习计算机网络:自顶向下的学习笔记和心得
Github地址,欢迎star ⭐️⭐️⭐️⭐️⭐️
运输层
-
TCP:
-
传输控制协议
-
报文段
-
-
UDP:
-
用户数据包协议
-
数据报
-
-
将主机间交付扩展到进程间交付被称为运输层的多路复用与多路分解
-
将运输层报文段中的数据交付道正确的套接字的工作称为多路分解
-
将来自源主机的不同数据块收集起来,并为每个数据块封装上首部信息从而生成报文段,然后将报文段传递至网络层称为多路复用
-
-
多路复用要求:
-
套接字有唯一标识符
-
每个报文段有特殊字段来指示该报文段要交付的套接字
- 源端口号和目的端口号
- 端口号16比特
- 每个运输层报文段最起码包括目的端口号和源端口号
- 源端口号和目的端口号
-
-
多路分解服务:
- 在主机上的每个套接字能够分配一个端口号,当报文段到达主机时,运输层检查目的端口号并将其定位到相应的套接字
-
一个UDP套接字是一个二元组(目的IP,目的端口号);两个UDP报文段有不同的源IP或源端口,指向相同的目的IP和目的端口,那么两个报文段将通过相同的目的套接字被定向到相同的进程。
-
一个TCP套接字是一个四元组(源IP,源端口,目的IP,目的端口);两个TCP报文段有不同的源IP或源端口,指向相同的目的IP和目的端口,那么两个报文段将通过相同的目的套接字被定向到两个不同的进程。
无连接运输:UDP
- UDP只在最基础的运输层需要提供的服务基础之上添加了一点差错检测服务
- 无需连接建立
- 无连接状态
- 分组首部开销小
- 关于发送什么数据以及何时发送控制更精细
- 可以在应用层构建可靠性,从而避免了TCP协议的拥塞控制和流量控制
UDP报文段结构
-
源端口号,目的端口号,长度,校验和分别16比特
-
校验和:发送方UDP报文段中所有16比特字的和进行反码求和时遇到的所有溢出都会回卷,得到的结果。
-
UDP提供差错检测是因为不能保证从源和目的之间的所有链路都有差错检验
可靠数据传输原理
-
发送方需要发送(函数):
-
rdt_send()
-
udt_send()
-
-
接收方需要(函数):
-
deliver_data()
-
rdt_rcv()
-
-
rdt的接收方和发送方需要往返交换控制分组,调用
udt_send()
rdt 1.0
- 假设底层信道完全可靠
- 发送方使用rdt_send发送之后只需等待上层调用
- 接收方使用rdt_rcv接受之后只需等待下层调用
rdt 2.0
- 此时分组中的比特可能会受损
- 发送方
- 自动重传请求协议(ARQ)
- 差错检测
- 接收方反馈:ACK和NAK
- 重传
- 发送方并不能从
上层
获取更多的数据,rdt_send不会出现,发送方不会发送新的数据;停等协议
- 自动重传请求协议(ARQ)
- 接收方
- 接受数据,进行差错检验,根据结果返回ACK或NAK
rdt 2.1
- 传送过程中ACK或者NAK受损
- 当发送方接收到含糊不清的ACK或NAK分组时重传,但是接收方并不知道这次的分组是新的还是一次重传,冗余分组
- 发送方对数据分组进行编号,将数据分组的序号放在该字段
rdt 2.2
- 在
rdt 2.1
的基础上去掉了NAK - 接收方和发送方需要附带分组序号
rdt 3.0(比特交替协议)
-
假设除了比特受损之外,底层信道还会丢包
-
定时重传,设置一个倒数计时器,发送方每发送一个分组就会启动一个倒数计时器
-
数据传输协议的要点:校验和、序号、定时器、肯定与否定确认
流水线协议
- 停等协议浪费了大量资源,所以引入了流水线机制
- 引入流水线机制必须对RDT协议做出改变
- 增加序号范围
- 协议发送方和接收方需要缓存多个分组
- 流水线的差错恢复:回退N步和选择重传
- 回退N步(GBN)
- base:最先发出但是未被确认的分组的序号
- nextseqnum:下一个未被使用的分组的序号
- N最大长度:窗口最大长度
- 一个分组的序号承载在分组首部的一个固定长度的字段重
- GBN发送方必须响应如下几种情况
- 上层的调用:上层调用rdt_send(),GBN检查发送窗口是否已经满了;如果未满则更新变量,否则向上层反馈
- 收到一个ACK:接收方已经正确接收到ACK为n以及之前的所有分组
- 超时重传:一旦出现超时,GBN会重传所有已发送但是未被确认的分组
- 发送方只有一个定时器,每当收到一个ACK并且还有已发送未被确认的分组,重启定时器
- GBN发送方必须维护窗口的上下边界以及nextnum在该窗口中的位置
- GBN的接收方:
- 接收方只需要维护一个下一个按序接受的分组序号,expectnum
- 接收方正确收到一个序号为n的分组
- 累计确认:接收方收到为n的正确按序分组意味着之前的分组也已经按序正确收到
- 按序,接收方为分组n发送ACK,并将该分组中的数据交付到上层
- 乱序,接收方丢弃该分组,并向发送方返回最近按序接受的分组ACK
选择重传
在GBN协议中单个分组的差错就会引起大量GBN协议分组的重传,许多分组没必要重传,因此出现了选择重传(SR)
-
选择重传(SR)让发送方仅重传那些又可能出错的分组
-
这种个别的,按需的重传要求接收方逐个确认正确接收的分组
-
SR接收方也引入了接收窗口,失序的分组将被缓存,直到所有的分组都被接受为止
-
SR发送方:
- 从上层接收到数据
- 超时,每个分组都有自己的逻辑定时器,可以使用单个硬件定时器模拟多个逻辑定时器
- 收到ACK,如果该ACK分组在SR发送窗口内,则标记为已确认分组;如果该ACK对应的是send_base则整个窗口向前移动到具有最小未被确认分组处;如果窗口移动期间有序号落在窗口内的未发送分组,则发送这些分组.
-
SR接收方:
- 序号在rcv_base~rcv_base+N-1内的分组被正确接受
- 如果未被接受过,则该分组被缓存,并向发送方返回一个选择ACK
- 如果是起始rcv_base序号,则按序向上层传送以该序号为起始的已经缓存的分组
- 序号在rcv_base - N ~ rcv_base - 1 的序号,必须产生一个ACK,即使接收方之前确认过
- 其余情况,忽略
- 序号在rcv_base~rcv_base+N-1内的分组被正确接受
-
对于SR协议而言,窗口长度必须小于或等于序号空间大小的一半
-
在分组被重新排序的情况下,我们必须确保一个序号不被重新使用,除非发送方确信任何先前发送的序号为x的分组都不在网络中为止,通过假设一个分组在网络中的存活时间不会超过某一个最大量来实现.
有链接运输:TCP
- tcp是面向连接的,三次握手
- TCP运行在端系统中,中间的网络元素不会维持TCP的链接状态,对于他们而言只是数据包
- TCP是全双工服务,Poin2Point
客户端通过socket套接字传递数据
- 客户端通过socket套接字来传递数据流,TCP将数据引导到发送缓存中
- TCP可以从发送缓存中取出并放入报文段的大小取决于
MSS
MSS
通常由本地主机发送的最大链路层帧长度MTU
来设置MSS
保证一个TCP报文段封装在IP
数据报中,加上TCP/IP
首部长度(通常40字节)- MTU一般为1500字节,MSS一般为1460字节
TCP链接的每一端都有各自的发送缓存和接收缓存
TCP链接一般由一台主机的变量,缓存以及套接字和另外一台主机的相应元素组成
TCP报文段结构
-
TCP报文段由首部字段和数据字段组成,数据字段大小被MSS限制
-
首部字段包括:
- 源端口号和目的端口号:用于多路复用/多路分解
- 序号和确认号:用于TCP双方实现可靠数据传输
- 序号是该报文段首字节的字节流编号.
- 确认号表明了源主机希望目的主机发送的下一字节的序号
- 首部长度:因为TCP首部字段是变长的(通常选项为空的时候,大小为20字节),该字段指示了以32比特的字为单位的TCP首部的长度
- 保留未用:
- 标志位:
- ACK:用于确认
- RST,SYN,FIN:用于链接建立和拆除
- URG:用于指示报文段存在着"紧急数据",紧急数据由16比特的紧急数据指针指出
- 接受窗口:用于流量控制
- 因特网校验和:检查校验和
- 紧急数据指针:
- 选项:可选与变长,用于发送方和接收方协商最大报文字段长度
-
一条TCP链接的双方均可随机选择序号
-
TCP被称为提供累计确认
往返时间的估计与超时
- 样本时间 SampleRTT
- 维护一个均值 SampleRTT,EstimateRTT
- E s t i m a t e R T T = ( 1 − α ) ∗ E s t i m a t e R T T + α ∗ S a m p l e R T T EstimateRTT=(1-\alpha)*EstimateRTT + \alpha*SampleRTT EstimateRTT=(1−α)∗EstimateRTT+α∗SampleRTT
- 一般 α \alpha α的值取0.125
- 这种指数加权移动移动平均(EWMA)
- 测量 EstimateRTT变化
- D e v R T T = ( 1 − β ) D e v R T T + β ∗ ∣ S a m p l e R T T − E s t i m a t e R T T ∣ DevRTT=(1-\beta)DevRTT+\beta*|SampleRTT-EstimateRTT| DevRTT=(1−β)DevRTT+β∗∣SampleRTT−EstimateRTT∣
- β \beta β为0.25
- 如果SampleRTT变化小DevRTT值也小
- 超时间隔TimeoutInterval设置为EstimateRTT加上一点余量
- T i m e o u t I n t e r v a l = E s t i m a t e R T T + 4 ∗ D e v R T T TimeoutInterval=EstimateRTT+4*DevRTT TimeoutInterval=EstimateRTT+4∗DevRTT
- 一般初始Time设置为1秒,如果出现超时,Time加倍,直到收到报文段才会使用上述公式再次计算Time
可靠数据传输
TCP主要3个事件有关:从上层应用程序接收数据、定时器超时、收到ACK
- 从上层应用程序接受数据:启动定时器,更新Nextseqnum
- 定时器超时:TCP重传引起超时的报文段,TCP重启定时器
- 收到ACK:TCP是累计确认,收到y代表y之前的所有字节序列都已经正确被接受,如果y大于sendbase,则代表该ACK在确认一个或多个先前未被确认的报文段;如果当前仍有未确认的报文段,TCP还要重启定时器
超时间隔加倍
-
TCP重传具有最小序号的还未被确认的报文段
-
每次TCP超时重传的时间间隔是先前的两倍,而不是通过EstimatedRTT个DevRTT推算的值
-
当定时器在另外两个时间触发的时候(收到上层应用数据和收到ACK)TimeoutRTT被更新为推算出来的值
快速重传
- 因为超时重传的时间间隔可能很长,会增加了端到端时延
- 当TCP发送方连续收到三个冗余ACK的时候就会出发快速重传
- 快速重传:在该报文段定时器过期之前,迅速重传之前丢失的报文段
TCP差错恢复机制
- TCP的差错恢复机制为GBN和SR的混合体
- TCP接收方优选择地确认失序报文段,将正确接收但是失序的报文段缓存起来
流量控制
- 经过TCP发送的数据会到达接收方的TCP缓存中等待应用程序调用,但是如果TCP发送的数据速度过大会导致接收方缓存溢出
- 流量控制是一个速度匹配服务,即发送方和接收方应用程序的读取速率相匹配
- 拥塞控制和流量控制都是对发送方的遏制,但是引起二者的原因不同
流量控制的实现
- TCP让发送方维护一个接受窗口来进行流量控制,接收窗口用于给发送方指示接收方还有多少可用的缓存
- 接收缓存大小:RcvBuffer
- LastByteRead:接收方用用程序从数据流中读取的最后一个字节的编号
- LastByteRcvd:接收方缓存的数据流最后一个字节的编号
- LastByteRcvd - LastByteRead <= RcvBuffer
- 接受窗口用rwnd表示
- rwnd = RcvBuffer - [LastByteRcvd - LastByteRead]
- rwnd是动态变化的
- TCP发送方
- LastByteSent:最后一个发送的字节的序号
- LastByteAcked:最后一个被确认的字节的序号
- LastByteSent - LastByteAcked <= rwnd
- 通过将未确认的值控制在
rwnd
之间就可以保证接收方缓存不会溢出
- TCP接收方仅当有数据或有确认要发时才会发送报文段给TCP发送方
- TCP接受缓存满了之后,发送方就不会发送数据,但是此时接收方已经释放了新的缓存,需要告知发送方
- 发送方会继续发送只有一个字节数据的报文段,这些报文段会被接收方接受,开始清理缓存,并且确认报文中含有一个非0 rwnd的值
TCP链接管理
-
三次握手
-
TCP客户端发送不含应用数据的SYN报文段,标志位SYN被置为1
-
服务器接收到该报文,并为这个TCP链接分配缓存和变量,向客户端发送报文,SYN被置为1,确认号为client_server + 1,序号为server_client,这个允许链接的报文段被称为SYNACK报文段
-
客户端收到SYNACK之后,客户为该链接分配缓存和变量,同时向服务器进行了确认,该SYN比特被置为0,此时可以负载客户到服务器的数据
-
-
关闭释放链接
- 客户端
- 客户端发送报文段,FIN比特位置为1,变为FIN_WAIR_1状态
- 客户端收到服务器ACK之后变为FIN_WAIR_2状态
- 接收到服务器的FIN之后变为TIME_WAIT状态,等待30秒,进入CLOSED状态
- 服务器端
- 服务器接收到客户端的FIN后,向客户端发送ACK
- 服务器向客户端发送FIN,接收到ACK之后关闭链接
- 客户端
-
当端口号或源IP与套接字不匹配的时候,目的主机向源主机发送一个特殊重置报文RST
-
当收到UDP套接字不匹配,发送ICMP数据包
-
nmap就是这种方式来扫描端口
- 收到TCPSYNACK报文,则目标主机一个应用程序使用TCP在该端口运行
- 收到TCP RST报文,目标主机该端口没有运行TCP程序,但是没有防火墙等阻挡
- 什么也没收到,证明被防火墙等阻挡
拥塞控制原理
拥塞原因和代价
- 分组的到达速率接近链路容量,分组经历巨大的排队时延
- 发送方必须重发来补偿因为缓存溢出而丢弃的分组
- 发送方因为遇到大时延所进行的不必要重传会引起路由器使用其有限链路带宽来转发不必要的分组
- 竞争路由器R上的优先缓存空间,当载荷过大的时候会导致A-C端吞吐量趋近于0
- 一个分组在一条路径被丢弃时,每个上游路由器用于转发该分组的传输容量都被浪费掉了
拥塞控制方法
- 端到端拥塞控制,网络层没有为运输层提供显式支持
- 网络辅助的拥塞控制,路由器向发送方提供关于网络中拥塞状态的显式反馈信息
- 阻塞分组
- 路由器标记或更新从发送方向接收方的分组中的某个字段,接收方接收后会向发送方通知该网络拥塞指示(该方法至少需要一个RTT)
TCP拥塞控制
经典TCP拥塞控制
-
Tcp所采用的方法是让每一个发送方都能感受到网络拥塞程度来限制其能向链接发送流量的速率
-
怎么感知拥塞程度?
-
如何限制?
-
采用什么算法来改变速率?
-
-
运行在TCP发送端拥塞控制机制跟踪一个额外变量,拥塞窗口
cwnd
-
LastByteSent - LastByteRead <= min{cwnd,rwnd}
-
通过调节cwnd的值来调整发送方向链接发送数据的速率
-
丢包事件发生代表着拥塞:
- 超时
- 收到三个冗余ACK
-
TCP通过确认来增大拥塞窗口长度,TCP被称为自计时
-
TCP拥塞控制算法:慢启动,拥塞避免,快速恢复
- 慢启动
- cwnd以一个MSS开始启动,每次被确认的时候cwnd加倍
- 遇到超时,cwnd被设置为1个MSS,重启慢启动过程.慢启动阈值ssthresh被设置为cwnd/2
- 到达或超过阈值ssthresh的时候,TCP结束慢启动进入拥塞避免模式
- 遇到3个冗余ACK,TCP执行快速重传,并进入快速恢复状态
- 一般重传只有在定时器超时才会重传
- 快速重传则是不需要等待定时器过期,直接重传丢失的报文段
- 拥塞避免
- 每个RTT,cwnd增加一个MSS
- 遇到超时,与慢启动一样,cwnd被设置为1MSS,ssthresh被设置为cwnd/2
- 遇到3个冗余ACK,cwnd减半(已收到的3个冗余ACK,也需要加3个MSS),ssthresh设置为cwnd/2,进入快速恢复状态
- 快速恢复
- 在快速恢复中,对于引起TCP进入快速恢复状态的缺失报文段,每当收到冗余ACK,cwnd就增加一个MSS.最终当对丢失报文的一个ACK到达时,TCP降低cwnd后进入拥塞避免状态.
- 遇到超时,与慢启动和拥塞避免一样,执行相同操作,并进入慢启动状态
网络辅助的拥塞控制
- 明确拥塞通告(ECN)
- ECN明确涉及TCP和IP,有两个比特用于ECN,这两个比特位于IP数据报的服务类型字段中
- 当接收方收到的数据包中包含网络层设置的ECN信号时,在返回TCP ACK报文段的ECE比特置位,发送方收到TCP ACK之后会对ECE指示做出反应,并在下一个发送的报文段中对**CWR(拥塞窗口缩减)**比特进行置位
- 除了TCP以外的运输层协议也可以利用网络层发送ECN信号
公平性
- UDP流量会压制TCP的流量传送
- 有的应用程序会同时开启多个并行TCP链接,也会占用大量带宽.
运输层功能演化
- 待补充…