《计算机网络-自顶向下方法》读书笔记-传输层篇

本文是《计算机网络-自顶向下方法》读书笔记,主要探讨传输层的TCP和UDP协议。介绍了TCP的可靠数据传输机制,如序列号、确认号、超时重传、快速重传和拥塞控制策略。同时,分析了UDP的简单结构和适用于实时应用的原因。
摘要由CSDN通过智能技术生成

《计算机网络-自顶向下方法》读书笔记-传输层篇

标签: 网络 读书笔记 校招 面试


概述和传输层服务

传输层协议为运行在不同Host上的进程提供了一种逻辑通信机制

端系统运行传输层协议

  • 发送方 : 将应用递交的消息分成一个或多个Segment,并向下穿给网络层
  • 接收方 : 将接收到的segment组装成消息,并向上交给应用层
    .

传输层可以为应用提供的协议主要有TCP和UDP

传输层VS网络层
网络层: 提供主机之间的逻辑通信
传输层: 提供进程之间的逻辑通信

  • 位于网络层之上
  • 依赖网络层服务
  • 对网络层服务进行(可能的)增强

可靠、按序的交付服务(TCP)

  • 拥塞控制
  • 流量控制
  • 连接建立

不可靠的交付服务(UDP)

  • 基于”尽力而为(Best-effort)”的网络层,没有(可靠性方面的)扩展

两种服务均不保证

  • 延迟
  • 带宽

多路复用与多路分解

接收端进行多路分组:传输层依据头部信息将收到的Segment交付给正确的Socket,即正确的进程.
发送端进行多路复用:从多个Socket接收数据,为每块数据封装上头部信息,生成Segment,交给网络层.

分用如何工作

主机接收到IP数据报(datagram)

  • 每个数据报携带源IP地址、目的IP地址
  • 每个数据报携带一个传输层的段(Segment)
  • 每个段携带源端口号和目的端口号

主机收到Segment之后,传输层协议提取IP地址和端口号信息,将Segment导向相应的Socket.

  • TCP做更多处理

无连接分用

主机收到UDP之后,检查目的端口号然后把数据导向相应Socket.

不同源IP地址和源端口号的IP数据包被导向同一个Socket

UDP的Socket用二元组标识:

  • (目的IP地址,目的端口号)

Java中使用UDP的方式说明只关心监听的端口,而不管数据从何而来

DatagramSocket socket = new DatagramSocket(servPort);  
DatagramPacket packet = new DatagramPacket(new byte[ECHOMAX], ECHOMAX);  
while(true){  
    socket.receive(packet);  
    System.out.println("Handling client at " + packet.getAddress().getHostAddress()
        + " on port" + packet.getPort());  
    socket.send(packet);  
    packet.setLength(ECHOMAX);  
}  

面向连接的分用

TCP的Socket用四元组标识:

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

服务器可能同时支持多个TCP

接收端利用所有的四个值将Segment导向合适的Socket

Web服务器为每个客户端开不同的 Socket

ServerSocket servSock = new ServerSocket(servPort);  
while(true){  
        //可以看出每次有新连接进来,accept方法都会返回一个新的Socket对象
        Socket clntSock = servSock.accept();  
        SocketAddress clientAddress =      
            clntSock.getRemoteSocketAddress();  
        System.out.println("Handling client at " + clientAddress);  
        InputStream in = clntSock.getInputStream();  
        OutputStream out = clntSock.getOutputStream();  
        while((recvMsgSize = in.read(receiveBuf)) != -1)  {  
            out.write(receiveBuf, 0, recvMsgSize);  
        }     
        clntSock.close();  
}    

无连接传输:UDP

基于Internet IP协议

  • 复用/分用
  • 简单的错误校验

“Best effort”服务,UDP段可能

  • 丢失
  • 非按序到达

无连接

  • UDP发送方和接收方之间不需要握手
  • 每个UDP段的处理独立于其他段

为什么UDP有这么多缺点,还是坚持用UDP协议?

  • 无需建立连接(减少延迟)
  • 实现简单,无需维护连接状态
  • 头部开销少
  • 没有拥塞控制:应用程序员可以自己定义发送和接收的节奏

常用于流媒体应用

  • 容忍丢失
  • 速率敏感
    UDP还用于DNS和SNMP

在UDP上实现可靠数据传输?

  • 在应用层增加可靠性机制
  • 应用特定的错误恢复机制

UDP报文段结构

UDP报文段结构很简单,主要有以下字段
|———-32bit———-|
|–源端口号–|–目的端口–|
|—-长度—-|—校验和—|
|——–应用数据———|

UDP校验和

发送方:

  • 将段内容视为16bit的序列,初始校验和置全0
  • 将所有序列加一起后的结果按位取反得到校验和(如果最高位溢出,要”回卷”)
  • 将校验和放入校验和字段

接收方:

  • 计算收到的段的校验和
  • 将其与校验和字段进行对比,如果不相等,说明有错误.相等说明没有检测出错误(但可能有错误)

为什么链路层提供CRC,传输层还是要用校验和?

  • 路由器内部处理可能会出错
  • 整个互联网的情况错综复杂,难以保证所有路径上都有差错检测

可靠数据传输原理,如何使用UDP构建TCP

可靠数据传输概论

什么是可靠?

  • 不错
  • 不丢
  • 不乱

rdt1.0

rdt1.0非常简单,假设下层信道是按序到达,不丢包,且不出现比特差错的.
那么rdt1.0的状态机很简单,不作赘述.
看图即可
rdt

rdt2.0

rdt2.0中假设的信道:
rdt2.0中假设信道可能会翻转分组中的位(bit)

  • 利用校验和检测位错误

如何从错误中恢复?

  • 确认机制(Acknowledgements,ACK):接收方显式的告诉发送方分组已正确接收
  • NAK:接收方显式地告知发送方分组有错误
  • 发送方收到NAK后,重传分组

基于这种重传机制的rdt协议称为ARQ(Automatic Repeat reQuest)协议

rdt 2.0中引入的新机制

  • 差错检测
  • 接收方反馈控制:ACK/NAK
  • 重传

rdt2.0的状态机
发送端状态机

接收端状态机

rdt2.1

rdt2.0看起来能运行了,但是忽略了一个重要的事实,那就是ACK和NAK分组也可能会被损坏.
当ACK/NAK被损坏时,可以采取这几种方法:

  • 为ACK/NAK增加校验和,检错并纠错.(实现完全纠错代价太高)
  • 发送方收到被破坏ACK/NAK时不知道接收方发生了什么,添加额外的控制消息(很难确保额外的消息不会损坏,直接无解)
  • 如果ACK/NAK坏掉,发送方重传
  • 不能简单的重传:产生重复分组

如何解决重复分组问题?

  • 序列号(Sequence number): 发送方给每个分组增加序列号
  • 接收方丢弃重复分组

因为当发送端发送一个分组时,它会等待接收方的回复,因此这种协议被称为停止-等待协议

rdt2.1的状态机

发送方

接收方

发送方:

  • 为每个分组增加了序列号
  • 两个序列号(0,1)就够用,因为是停等协议
  • 需校验ACK/NAK消息是否发生错误
  • 状态数量翻倍,状态必须记住当前分组序列号

接收方:

  • 需判断分组是否重复,当前所处状态提供了期望收到分组的序列号.
  • 注意:接收方无法知道ACK/NAK是否被发送方正确收到

rdt2.2

rdt2.2在rdt2.1的基础上去除了NAK消息.
如何实现?

  • 接收方通过ACK告知最后一个被正确接收的分组
  • 在ACK消息中显式的被确认分组的序列号

发送方收到重复ACK之后,采取和收到NAK一样的动作,重传当前分组.

rdt3.0

rdt3.0在2.X的基础上完全模拟了真实的信道.信道既可能发生错误,也可能丢失分组.

为了解决这个问题?
方法: 发送方等待”合理”的时间

  • 如果没收到ACK,重传
  • 如果分组或ACK只是延迟而不是丢了那么
    • 重传会产生重复,序号机制能处理
    • 接收方需在ACK中显式告知所确认的分组
  • 需要定时器

rdt3.0的FSM

rdt3.0虽然能用,但是性能很差,因为这是一个停等协议.

流水线协议

允许发送方在收到ACK之前连续发送多个分组

  • 更大的序列号范围
  • 发送方和/或接收方需要更大的存储空间以缓存分组

滑动窗口协议

窗口:

  • 允许使用的序列号范围
  • 窗口尺寸为N:最多有N个等待确认的消息
    滑动窗口

  • 随着协议的运行,窗口在序列号空间内向前滑动
    滑动窗口协议有GBN和SR

GBN(Go Back N)

发送方:

分组头部包含k-bit序列号

窗口尺寸为N,最多允许N个分组未确认

ACK(n):确认到序列号n的分组均已被正确接收(累计确认)
可能收到重复ACK
为空中的分组设置定时器(timer)

超时Timeout(n)事件:重传序列号大于等于n,还未收到ACK的所有分组

发送方FSM:

接收方:
ACK机制:发送拥有最高序列号的、已被正确接收的分区ACK

  • 可能产生重复ACK
  • 只需要记住唯一的expectedsequm

乱序到达的分组

  • 直接丢弃接收方没有缓存
  • 重新确认序列号最大的、按序到达的分组

接收方FSM

SR协议

GBN的缺陷
* 重传所有分组,造成资源浪费

  • 接收方对每个分组单独进行确认
    • 设置缓存机制,缓存乱序到达的分组
  • 发送方只重传那些没收到ACK 的分组
    • 为每个分组设置定时器
  • 发送方窗口
    • N个连续的序列号
    • 限制已发送且未确认的分组

SR协议的缺陷
如图

对于第一种和第二种情况,发送方发送的分组序号都是0,但是第一种情况发送的是重发的分组0.
而第二种情况发送的复用的序号0,实际上是一个新的分组0.
发送方无法分辨这两种情况.
因此对于SR协议,要求序列号空间满足Ns+NR<=2k

TCP

TCP概述

  • 点对点
    • 一个发送方,一个接收方
  • 全双工(full-duplex)
    • 同一连接中能够传输双向数据流
  • 面向连接
    • 通信双方在发送数据之前必须建立连接
    • 连接状态只在连接的两端中维护,在沿途节点中并不维护状态
    • TCP连接包括:两台主机上的缓存、连接状态变量、socket等
  • 流水线机制
    • TCP拥塞控制和流量控制机制设置窗口尺寸
    • 发送方/接收方缓存
  • 可靠的、按序的字节流
  • 发送方/接收方缓存

TCP报文段结构:

  • 来源连接端口(16位长)-辨识发送连接端口
  • 目的连接端口(16位长)-辨识接收连接端口
  • 序列号(seq,32位长)
  • 确认号(ack,32位长) —期望收到的数据的开始序列号。也即已经收到的数据的字节长度加1。
    • 如果含有同步化旗标(SYN),则此为最初的序列号;第一个数据比特的序列码为本序列号加一。
    • 如果没有同步化旗标(SYN),则此为第一个数据比特的序列码。
  • 报头长度 —以4字节(如果不这样根本不够)为单位计算出的数据段开始地址的偏移值。
  • 保留 —须置0
  • 标志符
    • URG —为1表示高优先级数据包,紧急指针字段有效。
    • ACK —为1表示确认号字段有效
    • PSH —为1表示是带有 PUSH标志的数据,指示接收方应该尽快将这个报文段交给应用层而不用等待缓冲区装满(很少使用)
    • RST —为1表示出现严重差错。可能需要重现创建TCP连接。还可以用于拒绝非法的报文段和拒绝连接请求。
    • SYN —为1表示这是连接请求或是连接接受请求,用于创建连接和使顺序号同步
    • FIN —为1表示发送方没有数据要传输了,要求释放连接。
  • 窗口(WIN) —表示从确认号开始,本报文的源方可以接收的字节数,即源方接收窗口大小。用于流量控制
  • 校验和 —对整个的TCP报文段,包括TCP头部和TCP数据,以16位字进行计算所得。这是一个强制性的字段。
  • 紧急指针 —本报文段中的紧急数据的最后一个字节的序号。
  • 选项字段 —最多40字节。每个选项的开始是1字节的kind字段,说明选项的类型。

序列号:

  • 序列号指的是Segment中第一个字节的编号,而不是Segment的编号
  • 建立TCP连接时,双方随机选择序列号

ACKs:

  • 希望收到的下一个字节的序列号
  • 累积确认:该序列号之前的所有字节均已被正确接收到

TCP如何处理乱序的TCP?
TCP规范中没有规定,由TCP实现者做出决策

TCP可靠数据传输

TCP可靠数据传输概述

TCP在IP层提供的不可靠服务的基础上实现可靠的数据传输服务

流水线机制

累积确定

触发重传的事件

  • 超时
  • 收到重复ACK

RTT和超时

如何设置定时器的超时时间,希望设置成大于RTT,但是RTT是动态的
如果设置的过短,会引起不必要的重传
如果设置的过长,则会对段丢失的反应慢

如何估计RTT?
SampleRTT:测量从段发出去到收到ACK的时间忽略重传
SampleRTT的变化:测量多个SampleRTT,求平均值,形成RTT的估计值EstimatedRTT

EstimatedRTT = (1-a) * EstimatedRTT + a * SampleRtt
加权指数平均,典型值: 0.125

定时器超时时间的设置:

  • EstimatedRTT + “安全边界”
  • EstimatedRTT变化大 -> 较大的边界
    测量RTT的变化值: SampleRTT与EstimatedRTT的差值
    DevRTT = (1 - B) * DevRTT + B * |SampleRTT - EstimatedRTT|

B典型值 : 0.25

TCP发送端程序

NextSeqNum = InitialSeqNum                                   
SendBase = InitialSeqNum 
 loop (forever) { 
   switch(event):
   event: data received from application above  
       create TCP segment with sequence number NextSeqNum  
       if (timer currently not running) 
            start timer 
       pass segment to IP  
       NextSeqNum = NextSeqNum + length(data)  
    event: timer timeout 
       retransmit not-yet-acknowledged segment with  
             smallest sequence number 
       start timer 
    event: ACK received, with ACK field value of y  
       if (y > SendBase) {  
            SendBase = y 
           if (there are currently not-yet-acknowledged segments) 
                  start timer  
           }  
 }

快速重传机制

TCP 的实现中,如果发生超时,超时时间间隔将重新设置,即将超时时间间隔加倍,导致其很大

  • 重发丢失的分组之前要等待很长时间
    通过重复ACK检测分组丢失

  • Sender会背靠背地发送多个分组

  • 如果某个分组丢失,可能会引发多个重复的ACK

如果sender收到对同一数据的3个ACK,则假定该数据之后的段已经丢失

  • 快速重传:在定时器超时之前即进行重传

快速重传算法

     event: ACK received, with ACK field value of y  
                if (y > SendBase) {  
                    SendBase = y 
                    if (there are currently not-yet-acknowledged segments) 
                         start timer  
                   }  
                else {  
                      increment count of dup ACKs received for y 
                      if (count of dup ACKs received for y = 3) { 
                          resend segment with sequence number y 
                      } 

TCP连接管理

TCP sender和receiver在传输数据前需要建立连接
初始化TCP变量

  • Seq.#
  • Buffer和流量控制信息

Client: 连接发起者
Server: 等待客户端请求 (具体可参见上面的java代码)

握手步骤:
1. Client发送syn 报文给Server(syn标识位置1)

  • 给出初始seq
  • 没有数据

    1. Server持有syn报文回送syn_ack报文(syn标识位置1)
  • Server分配缓冲区(syn泛洪攻击)

  • 确定Server初始的seq

    1. 客户端收到syn_ack报文,返回ack报文.这次的ack可以带有初始数据(syn标识位置0)

四次挥手步骤
1. Client向Server发送FIN控制Segment
2. Server收到FIN,回复ACK,关闭连接,发送FIN
3. Client收到FIN,回复ACK
* 等待一段时间(怕Client发出去的ACK丢失)
4. Server收到ACK,连接关闭

步骤图:

SYN泛洪攻击

原理
攻击者发送大量的syn分组但是不对该分组进行响应,让Server端开启大量buffer浪费服务器端空间

防范

  • 减少syn等待时间(不建议)
  • syn缓存.
    • 接收syn之后用hash表维护半开连接,等待下一次数据到来在开启真正的TCP缓存块.使用来源的一些信息(端口号)做hash,防止hashtable溢出
  • 增大总连接缓冲区的大小
  • 防火墙

TCP流量控制

接收方会为TCP连接分配buffer,如果发送方发的太快会导致接收方的buffer溢出,因此需要引入速度匹配机制

接收方会在Segment的头部字段将RcvWindow(接收窗口)的值告诉发送方,发送方限制自己已经发送但是还未收到ACK的数据不超过接收方的空闲RcvWindow尺寸

如果RcvWindow为0,会发生死锁.
所以其实发送方还是可以发送一个很小的段,以便捎回来一个新的RcvWindow.

拥塞控制原理

拥塞
非正式定义:”太多主机发送了太多数据或者发送速度太快,以至于网络无法处理”
表现为:
1. 分组丢失(路由器缓存溢出)
2. 分组延迟过大

拥塞的三个代价:
1. 拥塞时,分组的延时达到最大
2. 拥塞时,分组会导致路由器缓冲区溢出,导致丢失分组
3. 拥塞时,多跳网络中前几跳的努力会因为某一跳路由器的丢失分组而白费
当拥塞到一定程度时,整个网络将无法传输数据

端到端的拥塞控制方法:
1. 网络层不提供显式的支持
2. 端系统观察丢包和延迟等网络行为判断是否发生了拥塞
3. TCP采取这种方法

网络辅助的拥塞控制:
1. 路由器向发送方显式的反馈网络的拥塞信息
2. 简单的拥塞指示(1bit):SNA,DECbit,TCP/IP ECN,ATM
3. 指示发送方应该采取何种速率(定量)

ATM ABR网络中的拥塞控制

ARB:avaliable bit rate
* “弹性服务”
* 如果发送方路径”underloaded”就使用可用带宽
* 如果发送方路径拥塞就将发送速率降低到最低保障速率

RM(resource management)cells:专门用来指示网络拥塞状况的,穿插在正常的cell中发送

  • 发送方发送
  • 交换机设置RM cell位(网络辅助)
    • NI bit: rate不许增长
    • CI bit : 拥塞指示
  • RM cell由接收方返回给发送方

总结起来就是发送方发出去,交换机和接收方置位,然后接收方统一返回给发送方

RMcell中还有显式的ER字段:两个字节(定量的指示)

  • 拥塞的交换机可以将ER置为更低的值
  • 发送方获知路径所能支持的最小速率

普通的RMcell中也有一个EFCI位指示拥塞,由交换机控制
如果RM cell前面的data cell的EFCI位被设为1,那么接收方在返回的RM cell中置CI位

TCP拥塞控制

TCP使用端到端的拥塞控制而不是使用网络辅助的拥塞控制,因为IP层不会向端系统提供显式的反馈.

设cwnd为拥塞窗口的大小,并假定发送方能通过cwnd调节发送速率
MSS为最大报文段大小

如果ack以非常慢的速度到达,则拥塞窗口将以非常慢的速度增加.另一个方面,如果确认以高速率到达,则该拥塞窗口将会更为迅速的增大.因为TCP使用确认来触发增大他的拥塞窗口的长度.

TCP的拥塞控制算法包含3个部分

加性增,乘性减:AIMD

  • 慢启动
  • 拥塞避免
  • 快速恢复

慢启动

当一个TCP连接开始时,cwnd初始值为一个MSS的最小值,这时可用带宽远大于发送速率
所以,在慢启动阶段,每收到一个ACK,则拥塞窗口增加一个MSS.这样下去,每过一个RTT,拥塞窗口翻倍

什么时候结束这种指数增长呢?
* 如果检测到丢包事件,TCP将cwnd设置为1并重新开始慢启动,并且将一个变量threshold置为当前拥塞窗口的一半
* 如果当cwnd的值达到threshold时,将进入拥塞避免模式(不再翻翻,线性增加)
* 如果检测到三个ACK(并没有丢包那么严重,还能传一点东西),执行快重传并进入快恢复状态

拥塞避免

拥塞避免同样会增加cwnd,但是和慢启动不同,拥塞避免会每个RTT增加一个MSS(线性的)
如何结束拥塞避免呢?

  • 超时时,和慢启动一样将cwnd设置为1并重新开始慢启动,并且将一个变量threshold置为当前拥塞窗口的一半
  • 三个ACK时,将cwnd减半(为使测量结果更好,将threshold增加3个MSS).并且将threshold设为cwnd的一半.

快速恢复

对于引起进入快速恢复的每个冗余ACK,cwnd增加一个MSS.当最后一个ACK到达时,进入拥塞避免.如果出现超时事件,快速恢复在执行如同在慢启动和拥塞避免中相同的动作后,迁移到慢启动状态:当丢包事件发生后,cwnd被设置为一个MSS,并且threshold的值被设置为cwnd的一半.

拥塞控制总结

由于TCP Tahoe版本已经不再使用,这里只讨论Reno版本中的拥塞控制

  1. 初始状态为慢启动状态,threshold选定一个初始值(具体怎么选的依赖具体实现)
  2. 当cwnd小于threshold时,发送方慢启动状态,窗口指数增长
  3. 当cwnd大于threshold时,发送方拥塞避免状态,窗口线性增长
  4. 当发生3个ACK事件时先threshold = cwnd/2,然后cwnd = threshold,重新进入拥塞避免状态(还会加上3个ACK的)
  5. 当发生超时事件时,threshold = cwnd/2,cwnd = 1 ,然后进入慢启动状态
  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值