运输层

物理层,数据链路层 ,网络层,实现了主机到主机的通信

但实际上,通信的真正实体其实是通信进程

P2P(端到端)运输层的协议

两种主要协议

面向链接的TCP

无连接的UDP

AP(Applications Process)

由于因特网上会出现不同的操作系统,不同格式的进程标识符,就需要统一的方法对TCP/IP体系的应用进程进行标识

端口(Port)

实际上是区分应用进程的标识符(PID),并不是物理端口

端口号(PID)

TCP/IP体系的运输层使用端口号来区分应用层不同的应用进程

  • 16比特表示,取值为0~65535
  • 熟知端口号:0~1023,IANA把这些端口号指派给TCP/IP体系中最重要的一些应用协议,例如:FTP使用21/20,HTTP适用80,DNS使用53.
  • 登记端口号:1024~49151,为没有熟知的端口号使用,这类端口号必须在IANA按照规定的手续登记,以防止重复,例如:Microsft RDP微软远程桌面使用的端口3389。
  • 短暂端口号:49152~65535,留给客户进程选择暂时使用。当服务器进程收到客户进程的报文是,就知道客户进程所使用的动态端口号。通信结束后,这个端口号可供其他客户进程以后使用。

复用与分用

发送方的复用

应用报文根据所选的端口号判断是UDP协议进行复用封装成用户数据报

同上,应用报文根据所选的端口号判断是TCP进行复用封装成报文段。

无论是数据报,还是报文段,都封装为IP数据报(协议字段不同),这个操作称为IP复用

最后发送给接收方

接收方的分用

接收方对IP数据报进行解析,根据协议字段,分别解析出用户数据报和报文段,分别进行UDP分用,TCP分用,再通过端口号解析为应用报文传递给上层

image-20220727092643417

常见的熟知端口号

image-20220727093153322

UDP与TCP

用户数据报协议UDP(User Datagram Protocol)

  • 可以随时发送数据

  • 无连接,支持一对一,一对多,一对全的通信

  • 面向应用报文

  • 提供的也是无连接不可靠的服务,仅仅丢弃数据报,不做任何处理,尽最大努力交付,无流量控制和拥塞控制

  • UDP数据报首部格式

传输控制协议TCP (Transmission Control Protocol)

  • 必须使用三报文握手建立连接
  • 必须使用四报文挥手释放连接
  • 面向连接,仅支持单播:一对一的通信
  • 面向字节流(数据流),不保证大小关系对应,实现可靠传输的基础
  • 提供的事面向连接的可靠传输服务,使用流量控制和拥塞控制
  • TCP数据报格式

TCP的流量控制

为了保证可靠的传输,控制数据的发送速率的操作被称为流量控制

关键点:

  • seq是数据的序号字段

  • 原理实际上跟SR有点相似

  • 也有发送窗口和接受窗口,但是也有GBN的累计确认。
  • 流量控制的是接受窗口,接受窗口控制的接受多少数据,而接受窗口的大小呢由接受端的数据缓存大小决定
  • 发送窗口随着接受窗口进行变化,接受方告诉发送方接受窗口的大小,发送方保持发送窗口大小跟接受窗口一致

例子如下:

出现死锁的局面:

通俗的语言来解释TCP的流量控制(小作文了属于是)

  1. A有16个神奇的苹果(报文段),B的袋子可以放4个苹果(这苹果的神奇之处在于,递出去之后,必须要知道是否接受到才会彻底消失,薛定谔的苹果
  2. A问B一次袋子能装多少个,B回答4个(接收窗口)
  3. A就连续的给B递4个苹果,并给每个苹果标上序号,可是当B放第3个时,把袋子撑破了,第3苹果掉在了地上烂了(报文段丢失
  4. B就先拿回家处理了一下(流量控制),把接受到的苹果们放入了冰箱,发现袋子只能放3个苹果了,这时,B告诉A,现在我的袋子只能装3个了,并且第三个苹果烂了且只拿到前两个苹果
  5. B表示知道了,与此同时A这里的确认收到的苹果彻底消失了,从之前没消失的第三个(就是内个摔烂的没有确认收到的苹果)开始连续的给B递3个苹果,此时序号也从第三个开始,递完之后,A等待B告诉是否收到的信息(设定计时器
  6. B接过了所有的苹果,但是,突然大脑呆滞阿巴阿巴,忘记给A回复了,也忘记回家放苹果了(累计确认报文丢失
  7. A只好再次把之前的苹果们 的第一个苹果传递给B(超时重传),再次进行等待
  8. B收到了重新传送的苹果,发现重复了序号3的苹果,就把重复的丢弃给A回复了,这个时候发现拿三个回家,原本应该拿四个的才对,却想越气,决定再空出一只手再拿一个苹果。这时,B回复A都收到了这三个苹果,并且表示我还能再拿一个(流量控制)
  9. A知道后表示ok,之前的三个消失了,从最新的一个开始拿,想起来B说还能再拿一个,就只递给B一个,然后等待B回复是否收到,B表示额外的一个已经把B塞满了,就先别递了(再次流量控制),A说OK,等你回复什么时候再给你递
  10. B回家放苹果,当把袋子里的都放好,想起来手上还有一个苹果,也放好了,干脆再重新拿个袋子,顺带告诉A我又可以拿3个苹果了(发现之前袋子实际上装不了4个,最多装三个)
  11. A啊等啊等,迟迟等不到B给他回信息,为啥呢,发现了 B回的信息A没看见(不要在意为啥看不见,问就是ACK丢失),因为A不知道B到底能不能拿,就再也没有递苹果。(但是在心里暗自决定再等10s)(持续计时器
  12. B呢以为A知道了可以递苹果了,在傻傻的等(无计时器),实际上却是:两边都在等,出现了死锁局面
  13. 这样的局面怎么打破呢?A还是等不下去了(计时器超时),向B打了一个问号 “?” (一个字节的0窗口探测报文
  14. B说啊,我现在可以拿3个,A表示OK,就开始向B就递苹果了,就打破了这个死锁的情况
    • 假设:B这会打LOL,回复还是拿不了,A只能行叭,只好等一段时间就向B 打个问号 “?” 。(每收到一个0,就启动持续计时器)
    • 再假设:这个B玩的亚索0-17,队友也一直再给他打问号,B没发现A给打的问号,也就没有给A回复,那么这种情况,A的也是有忍耐时间的(0窗口探测报文的计数器),见到B还没有回复,就再打个问号(超时重传

注意,以上情况没有考虑出现拥塞控制

小结

TCP的拥塞控制

四个字,供不应需

需求远远超过已有资源就会出现拥塞,若不进行控制,整个网络的吞吐量将随着输入的负荷增大而下降,降为0就进入死锁状态

需要进行需求控制,也被称为拥塞控制,是相当有必要的

四种拥塞算法

发送方维护一个拥塞窗口cwnd,取决于网络的拥塞程度,并且动态变化

拥塞判断的依据是,发生超时重传

发送方将拥塞窗口作为发送窗口swnd,

发送方维护这一个慢开始门限ssthresh状态变量:

  • 当cwnd<ss thresh,使用慢开始算法
  • 当cwnd>ss thresh,停止使用慢开始算法该用拥塞避免算法
  • 当cwnd=ss thresh ,即可以使用慢开始算法,也可以使用拥塞避免算法

(TCP Tahoe)

  • 慢开始(slow-start)

    • 拥塞窗口值按照指数规律增长,按传播轮次
  • 拥塞避免(congestion avoidance)

    • 拥塞窗口值线性+1,按传播轮次
    • 假设出现拥塞,将ss thresh值更新为发生拥塞时cwnd的一半,cwnd回到默认值,重新开始执行按开始算法

当出现超时重传时不一定会出现拥塞,如果直接判断产生拥塞,cwnd就会回到默认值重新开始,那么会极大的降低传输效率,为了提升TCP性能,引入了新的拥塞控制算法(TCP Reno)

  • 快重传(fast retransmit)
    • 使发送方尽快进行重传,而不是等超时重传计时器超时再重传,目的是为了让发送方尽早知道发生了个别报文端的丢失
    • 出现丢失,发送方依旧不管不顾的继续发送,在超时重传计时器还没超时之前,每接收到一个报文,接收方会提醒一次我接受到了一个,但是之前的丢的还没给我补发(重复的确认我只收到了丢失的前一个),发送方连续收到三次重复确认丢失之前一个的报文的确认,立刻重传丢失的报文,这就是快重传

  • 快恢复(fast recovery)
    • 发送方一但收到三个重复确认,就知道只是丢失了个别的报文段,并不是出现拥塞,转而执行快恢复算法
    • 发送方讲慢开始文献ssthresh 和拥塞窗口cwnd调整为当前窗口的一半,开始执行拥塞避免算法
    • 也有的块恢复实现是把快恢复开始时的拥塞窗口cwnd再增大一些 至少加3
      • 既然发送方收到了三个重复的确认,说明有三个数据报文段已经离开了网络,不需要消耗资源,就可以增加拥塞窗口,尽可能扩大TCP的传输速率

四者结合动态实现拥塞控制

超时重传时间的选择

这是TCP最复杂的问题之一

太小不行,会出现重复

太大,会浪费传输效率

而且,RTT ,数据传输时间是受各层影响的

所以不能直接使用某次测量的RTT样本超时重传时间RTO

利用每次测量的到的RTT样本,计算加权平均往返时间RTT,计算一个平滑的往返时间

在上式中$0\leq a < 1$:

  • 若很接近0,则新的$RTT$样本$RTT_S$影响不大;
  • 若很接近1,则新的$RTT$样本$RTT_S$影响较大;

建议标准的RFC6298推荐的值为1/8,即0.125.

  • 该方法得到的值就比测量的RTT的值更加平滑,因此超时重传的时间就应该略大于$RTT_S$

image-20220728105335061

即使如此,对于RTT样本的测量一样会出现很多问题

出现以上情况会出现计算差错

对此,karn提出一个算法:出现报文段重传,就不采用这段往返时间RTT作为样本

但是这有引起了新的问题:实际传播的时延突然增大,并且不再减小,就会一直出现超时重传的情况,那么RTO就无法再进行更新,就会一直重复发送数据报文段

进而对Karn算法进行修正,加入报文段每重传一次,就把超时重传时间RTO增大一些。典型的做法是:将RTO的值取为旧值得两倍。

​ 举例说明

TCP可靠传输的实现

  • 字节为单位的滑动窗口来实现可靠传输
  • 发送窗口,出现拥塞采用拥塞窗口cwnd,未出现拥塞采用接受窗口值rwnd
  • image-20220728111043844

TCP的运输连接管理

TCP的三次握手

  • 建立TCP连接
  1. TCP客户端和TCP服务端都处于CLOSED状态

  2. TCP服务端需要建立一个传输控制块

    1. TCP连接表

    2. 指向发送和接受缓存的指针

    3. 当前发送和接收的序号

      ……

    4. 建立好之后准备接受TCP客户的连接请求进而变更状态为监听LISTEN状态(该状态也称为被动打开连接状态)

  3. TCP客户进程同样首先创建传输控制块

    1. TCP连接表
    2. 指向发送和接受缓存的指针
    3. 当前发送和接收的序号
    4. …….
    5. 发送TCP连接请求并更行状态为SYN-SENT(同步已发送)(主动打开连接)发送第一个报文(该报文用来请求TCP服务器的SYN-RCVD同步状态
    6. 来简单的说明这个报文:发送的是一个带着SYN标志的报文,该值为1,说明这个报文是专门用来请求连接建立的,seq=x,这个X其实可以为任意值,由客户决定,表示的是序号
  4. TCP服务器收到了第一条请求报文,为了表示请求成功,状态变为SYN_RCVD,回应了第二条新的报文 :标志ack=x+1(序号+1,表示上一个序号为x的报文确认收到了,请求序号为x+1的报文段)SYN=1 同时也表示这是用来建立连接的报文,不能携带数据,ACK=1标志表示这是一个确认的报文 seq=y(同理第一条报文段,这个值可以由服务端自由设定)

  5. 当TCP客户端收到第二条报文,根据报文表示没问题,变为连接建立状态,并且发送第三条报文端,:该报问段是普通报文段 没有SYN标志,ACK=1表明这个是用来确认服务器的状态,seq=x+1,是该报文段的序号,ack=y+1则表示请求下一条服务器报文段的序号

  6. TCP服务器收到第三条报文,明白了TCP客户端是想建立连接,将自己状态改为连接已建立状态。

其中建立连接用了三个报文,因此被成为三报文握手

假说不进行确认同步状态,直接双方一起建立连接,去掉第三个报文,改为两报文建立连接,就会出现第一报文丢失重发导致已关闭的TCP服务器误开,浪费网络资源。

TCP的四次挥手

  • 释放TCP连接的过程

    小可:我要走了

    过了一会

    小符:你确定你要走吗

    小符,思考了一会,再次问:

    你真的确定你要走了么?

    (这时可以扔一些小石头之类的(数据)给小可)

    过了一会

    小可:嗯

    小符听到后,小声嘟囔着一句

    ​ 笨蛋

    ,然后头也不回的走了

    小可有点怅然若失。

    等了一会,最后也走了

    如图所示:

    急着下班的小可(如果少了最后一次握手)

    小可最后回复时,一阵大风,

    小符没有听到小可最后的回复

    而且小可直接溜了,

    小符一直等啊等,等小可的最后回答

    每等一段就问,

    你真的要回去了吗?

    ……

    可是小可早就run了。

    即使听到了什么也不再理踩。

如图所示

  • 不想活的小可

    小可突然不想活了,吊在大本钟下

    小符等了一会,发现小可没有再说话

    就每等一会问一次

    你特么还活着么?

    连续问了十次

    小符知道了,

    小可估计是寄了

    小符走了。

才,才不是因为想偷懒呢

TCP报文段的首部格式

  • 面向字节流

  • 发送缓存中一部分或者全部字节给其添加一个首部成为TCP报文段然后发送

  • 一个TCP报文段由首部和数据载荷两部分构成

  • TCP的全部功能都体现在它首部中个字段的作用

  • 源端口,目的端口

    • 源端口:顾名思义,进程端口,协议进程的端口,主机自己设定的暂时端口等
  • 序号

    • 取值 32比特,循环的,当最后一个值加一,回到0重新继续加,数据载荷的第一个字节的序号
  • 确认号(ack),标志位(ACK/URG/PSH/RST/SYN/FIN)

    • 确认号取值 32比特,循环的,当最后一个值加一,回到0重新继续加,搭配确认标志号ACK取值为1时才生效
    • TCP协议其实有规定,在建立连接后,ACK都必须为1
    • ack表示请求序号的下一个,并且表明我已经收到了之前的全部数据
    • 标志位:(URG/ACK/PSH/RST/SYN/FIN):表明报文段类型
      • RST复位,表示TCP连接异常,必须释放连接,再重新建立,也可以拒绝非法报文段,禁止打开一个TCP连接
      • PSH推送,尽快上交,不用等待发送缓存
      • URG紧急标志,与紧急指针搭配,1生效,0无效
  • 数据偏移,保留,窗口

    • 数据偏移:占4个比特,表示数据载荷部分起始处距离报文段起始的值,以四个字节为单位
    • 保留:占6比特,默认为0;
    • 窗口:占16比特,就是发送本报文段的一方的接收窗口
  • 校验和,紧急指针

    • 检验和:一种检错的数据
    • 紧急指针与标志位搭配,指明出紧急的数据载荷部分长度,VIP指针,也不用排队上交给应用层
  • 选项(可选)

    • 最大报文段长度MSS选项:TCP报文段数据载荷部分的最大长度
    • 窗口扩大选项:扩大窗口,提高吞吐
    • 时间戳选项
      • 计算往返时间RTT
      • 处理序号超过范围的情况,防止序号绕回
    • 选择确认选项:选择确认功能
  • 填充

    • 用来保证首部能被4整除

总结

这部分还挺简单的,接下来就即将到达计网最高层了捏