计网复习05-传输层

这里的传输层指的是原理体系结构的传输层,对应OSI七层体系结构中的传输层,对应TCP/IP四层体系结构中的传输层。它为应用层提供服务。

传输层协议概述

计网复习05-传输层

复用和分用

因为在一台主机中经常有多个应用进程同时分别和另一台主机中的多个应用进程通信。这表明运输层有一个很重要的功能——复用 (multiplexing)和分用 (demultiplexing)。

应用层->传输层基于端口的TCP/UDP复用,整合为TCP报文段/UDP用户数据报。传输层->网络层是IP复用,整合为IP数据报。在接收端进行分用处理。

用户数据报协议UDP

计网复习05-传输层

UDP只在IP数据报服务之上增加了很少功能,即复用分用和差错检测功能。

UDP的主要特点

  1. UDP是无连接的,减少开销和发送数据之前的时延。
  2. UDP使用最大努力交付,即不保证可靠交付。
  3. UDP是面向报文的,适合一次性传输少量数据的网络应用。
  4. UDP无拥塞控制,适合很多实时应用。
  5. UDP的首部开销小,只有八字节

UDP的报文格式

计网复习05-传输层

源端口号是可有可无的(如果没有想收到回复的需求),可以填写全0。

分用时,找不到对应的目的端口号,就丢弃报文,并给发送方发送ICMP“端口不可达”差错报告报文。

校验和的计算

计网复习05-传输层

计算校验和时,会先抽象出一个“伪首部”,从IP数据报的首部获取信息。

伪首部只有在计算检验和时才出现,不向下传送也不向上递交。

计网复习05-传输层

在计算校验和时,将每组对齐的2字节对应的16位相加,得到的结果求反码。这样就产生了校验码,发送端将它填入。

接收端的验证也是将将每组对齐的2字节对应的16位相加,得到的结果求反码,若全为1说明校验通过,否则说明出错。

传输控制协议TCP

计网复习05-传输层
  • 发送缓存:准备发送的数和已发送但尚未收到确认的数据
  • 接收缓存:按序到达但尚未被接受应用程序读取的数据和不按序到达的数据

可靠传输的工作原理

计网复习05-传输层

这部分的协议我用到的数据单位是“帧”,是因为这部分也可以由数据链路层来控制,传输层的思想与其一致。

停止-等待协议

为什么要有停止等待协议?

  • 除了比特出差错,底层信道还会出现丢包问题。
  • 为了实现流量控制。

每发送完一个帧就停止发送,等待对方的确认,在收到确认后再发送下一个帧。停止等待协议是一种特殊的滑动窗口协议。

如果未收到确认,就要有超时重传机制,通常这个超时时间比平均RTT更长一些,如果超时还没有收到接收方发来的确认帧,就重新发送一次上一帧。

发送帧和确认帧都有编号,这样即使帧重复,接收方也能知道是收到了重复帧。

  • 停止等待协议:发送窗口大小=1,接收窗口大小=1;
  • 后退N帧协议(GBN):发送窗口大小>1, 接收窗口大小=1:
  • 选择重传协议(SR):发送窗口大小>1,接收窗口大小>1;

滑动窗口协议

后退N帧协议(GBN)

计网复习05-传输层

发送方有一个发送窗口,接收方有一个接收窗口(大小为1),发送方可以发出发送窗口范围内允许的发出的帧,当接收方收到一帧之后,接收窗口向后滑动一格,响应一个确认帧,发送方收到确认帧之后将发送窗口也向后滑动一格。

对于发送窗口内的发送帧都要有备份,为了超时重传。发送帧和确认帧都要有编号,为了区别传送中发生的错误。

如果接收方收到了编号不连续的帧,说明中途发生了帧丢失,那么从此刻开始,将所有接收到的的帧丢弃,只响应上一个连续帧序列中最后一个帧的编号对应的确认帧,直到再次收到能形成连续编号的帧。

若采用n个比特对帧编号,那么发送窗口的尺寸WT应满足: 1≤WT≤2n-1。因为发送窗口尺寸过大,就会使得接收方无法区别新帧和旧帧。

选择重传协议(SR)

选择重传协议的发送窗口大小和接收窗口大小均大于1。

计网复习05-传输层

发送窗口内某个帧的超时时间一过还没收到确认的,就进行重传。一旦发送窗口左侧有连续被确认的发送帧,就进行滑动,滑动到具有最小序号的未确认帧处。

接收方并不要求接收的帧是顺序的,只要是在接收窗口内的帧序号就接收。

发送窗口最好等于接收窗口,不大于2n-1

TCP报文格式

计网复习05-传输层
  • 序号:在一个TCP连接中传送的字节流中的每一个字节都按顺序编号,本字段表示本报文段所发送数据的第一个字节的序号。
  • 确认号:期望收到对方下一个报文段的第一个数据字节的序号。若确认号为N,则证明到序号N-1为止的所有数据都已正确收到。
  • 数据偏移(首部长度) : TCP报文段的数据起始处距离TCP报文段的起始处有多远,以4B为单位,即1个数值是4B。
  • 六个控制位:
    • 紧急位URG: URG=1时, 标明此报文段中有紧急数据,是高优先级的数据,应尽快传送,不用在缓存里排队,配合紧急指针字段使用。
    • 确认位ACK: ACK=1时确认号有效, 在连接建立后所有传送的报文段都必须把ACK置为1。
    • 推送位PSH: PSH=1时,接收方尽快交付接收应用进程,不再等到缓存填满再向上交付。
    • 复位RST: RST=1时, 表明TCP连接中出现严重差错,必须释放连接,然后再重新建立传输链接。
    • 同步位SYN: SYN=1时, 表明是一个连接请求/连接接受报文。
    • 终止位FIN: FIN=1时, 表明此报文段发送方数据已发完,要求释放连接。
  • 窗口:指的是发送本报文段的一方的接收窗口,即现在允许对方发送的数据量。
  • 检验和:和UDP中的检验和类似,检验首部+数据,检验时要加上12B伪首部,第四个字段为6。
  • 紧急指针: URG=1时才有意义,指出本报文段中紧急数据的字节数。
  • 选项:最大报文段长度MSS、窗口扩大、时间戳、选择确认...

TCP实现可靠传输的机制

  • 累计确认——和首部中的确认号相关,接收方可以在合适的时候发送确认,也可以在自己有数据要发送时把确认信息顺便捎带上。
  • 超时重传——TCP采用自适应算法,动态改变重传时间RTTs (加权平均往返时间)
  • 选择确认(累计确认的改进,明确指出自己只收到了哪些数据)——接收方可以在合适的时候发送确认,也可以在自己有数据要发送时把确认信息顺便捎带上。接收方收到了和前面的字节流不连续的两个字节块。如果这些字节的序号都在接收窗口之内,那么接收方就先收下这些数据,但要把这些信息准确地告诉发送方,使发送方不要再重复发送这些已收到的数据。如果要使用选择确认,那么在建立 TCP 连接时,就要在 TCP 首部的选项中加上“允许 SACK”的选项,而双方必须都事先商定好。

TCP的流量控制

计网复习05-传输层

TCP利用滑动窗口机制实现流量控制。

在通信过程中,接收方根据自己接收缓存的大小,动态地调整发送方的发送窗口大小,即接收窗口rwnd(接收方设置确认报文段的窗口字段来将rwnd通知给发送方),发送方的发送窗口取接收窗口rwnd和拥塞窗口cwnd的最小值。发送窗口=Min{接收窗口rwnd,拥塞窗口cwnd}

计网复习05-传输层

假设B向A发送了零窗口的报文段后不久,B的接收缓存又有了一些存储空间。于是B向A发送了rwnd = 400的报文段。

但这个报文段在传送过程中丢失了。A一直等待收到B发送的非零窗口的通知,而B也一直等待 A 发送的数据。

如果没有其他措施,这种互相等待的死锁局面将一直延续下去。

为了解决这个问题,TCP 为每一个连接设有一个持续计时器 (persistence timer)。

只要TCP连接的一方收到对方的零窗口通知,就启动持续计时器。若持续计时器设置的时间到期,就发送一个零窗口探测报文段。接收方收到探测报文段时给出现在的窗口值。若窗口仍然是0,那么发送方就重新设置持续计时器。

TCP的拥塞控制

计网复习05-传输层

假定:
1.数据单方向传送,而另一个方向只传送确认
2.接收方总是有足够大的缓存空间,因而发送窗口大小取决于拥塞程度

拥塞控制所起的作用

拥塞控制的一般原理

在某段时间,若对网络中某资源的需求超过了该资源所能提供的可用部分,网络的性能就要变坏。这种现象称为拥塞 (congestion)。

若网络中有许多资源同时产生拥塞,网络的性能就要明显变坏,整个网络的吞吐量将随输入负荷的增大而下降。

开环控制方法就是在设计网络时事先将有关发生拥塞的因素考虑周到,力求网络在工作时不产生拥塞。

闭环控制方法是基于反馈环路的概念。属于闭环控制的有以下几种措施:
1. 监测网络系统以便检测到拥塞在何时、何处发生。
2. 将拥塞发生的信息传送到可采取行动的地方。
3. 调整网络系统的运行以解决出现的问题。

TCP只能使用闭环控制,发送方维护一个拥塞窗口,是根据自己估算的网络拥塞程度而设置的窗口值,反映网络当前容量。只要网络没有出现拥塞,拥塞窗口就可以再增大一些,以便把更多的分组发送出去,这样就可以提高网络的利用率。但只要网络出现拥塞或有可能出现拥塞,就必须把拥塞窗口减小一些,以减少注入到网络中的分组数,以便缓解网络出现的拥塞。

如何判断网络拥塞?
+ 重传定时器超时
+ 收到三个相同(重复)的 ACK

慢开始&拥塞避免

计网复习05-传输层

由小到大逐渐增大拥塞窗口数值。用来确定网络的负载能力。在每收到一个对新的报文段的确认后,可以把拥塞窗口增加最多一个 SMSS 的数值,此时cwnd就是翻倍增长的

新的 RFC 5681 把初始拥塞窗口 cwnd 设置为不超过2至4个SMSS的数值。

慢开始门限 ssthresh(状态变量):防止拥塞窗口cwnd 增长过大引起网络拥塞。到达这个上限使用拥塞避免算法增大cwnd,使用“加法增大”。一旦发生网络拥塞,此时的swnd/2得到新的ssthresh,再重新开始慢开始。

“拥塞避免”并非指完全能够避免了拥塞。利用以上的措施要完全避免网络拥塞还是不可能的。

“拥塞避免”是说在拥塞避免阶段把拥塞窗口控制为按线性规律增长,使网络比较不容易出现拥塞

快重传&快恢复

计网复习05-传输层

采用快重传 FR (Fast Retransmission) 算法可以让发送方尽早知道发生了个别报文段的丢失。快重传算法首先要求接收方不要等待自己发送数据时才进行捎带确认,而是要立即发送确认,即使收到了失序的报文段也要立即发出对已收到的报文段的重复确认。

发送方只要一连收到三个重复确认,就知道接收方确实没有收到报文段,因而应当立即进行重传(即“快重传”),这样就不会出现超时,发送方也不就会误认为出现了网络拥塞。此时发送方认为网络很可能没有发生拥塞,因此现在不执行慢开始算法,而是执行快恢复算法 FR (Fast Recovery) 算法

直接将当前cwnd/2作为新的ssthresh值,并直接从这个值开始拥塞避免的“加法增大”。

TCP的传输连接管理

计网复习05-传输层

连接建立

TCP连接的建立采用客户服务器方式,主动发起连接建立的应用进程叫做客户,而被动等待连接建立的应用进程叫服务器。

计网复习05-传输层

假设运行在一台主机(客户)上的一个进程想与另一台主机(服务器)上的一个进程建立一条连接,客户应用进程首先通知客户TCP,他想建立一个与服务器上某个进程之间的连接,客户中的TCP会用以下步骤与服务器中的TCP建立一条TCP连接:

  1. 客户端发送连接请求报文段,无应用层数据。SYN=1,seq(首部中的序号)=x(随机)
  2. 服务器端为该TCP连接分配缓存和变量,并向客户端返回确认报文段,允许连接,无应用层数据。
    SYN=1,ACK=1,seq=y(随机), ack=x+1
  3. 客户端为该TCP连接分配缓存和变量,并向服务器端返回确认的确认,可以携带数据。SYN=0,ACK=1,seq=x+1,ack=y+1

第三次握手失败&SYN洪泛攻击

当客户端收到服务端的 SYN+ACK 应答后,其状态变为 ESTABLISHED,并会发送 ACK 包给服务端,准备发送数据了。如果此时 ACK 在网络中丢失,过了超时计时器后,那么 Server端会重新发送 SYN+ACK 包,重传次数根据/proc/sys/net/ipv4/tcp_synack_retries 来指定,默认是 5 次。如果重传指定次数到了后,仍然未收到 ACK 应答,那么一段时间后,Server 自动关闭这个连接。但是 Client 认为这个连接已经建立,如果 Client 端向 Server 写数据,Server端将以 RST 包响应,方能感知到 Server 的错误。

SYN洪泛攻击发生在OSI第四层,这种方式利用TCP协议的特性,就是三次握手。攻击者发送TCP SYN,SYN是TCP三次握手中的第一个数据包,而当服务器返回ACK后,该攻击者就不对其进行再确认,那这个TCP连接就处于挂起状态,也就是所谓的半连接状态,服务器收不到再确认的话,还会重复发送ACK给攻击者。这样更加会浪费服务器的资源。攻击者就对服务器发送非常大量的这种TCP连接,由于每一个都没法完成三次握手,所以在服务器上,这些TCP连接会因为挂起状态而消耗CPU和内存,最后服务器可能死机,就无法为正常用户提供服务了。

如何应对SYN洪泛攻击?这里可以使用linux的两个参数:

第一个参数 tcp_synack_retries = 0 是关键,表示回应第二个握手包(SYN+ACK 包)给客户端 IP 后,如果收不到第三次握手包(ACK 包)后,不进行重试,加快回收“半连接”,不要耗光资源。

修改这个参数为 0 的副作用:网络状况很差时,如果对方没收到第二个握手包,可能连接服务器失败,但对于一般网站,用户刷新一次页面即可。这些可以在高峰期或网络状况不好时tcpdump 抓包验证下。

之所以可以把 tcp_synack_retries 改为 0,因为客户端还有 tcp_syn_retries 参数,默认是 5,即使服务器端没有重发 SYN+ACK 包,客户端也会重发 SYN 握手包。

第二个参数tcp_max_syn_backlog,从字面上就可以推断出是什么意思。在内核里有个队列用来存放还没有确认 ACK 的客户端请求,当等待的请求数大于 tcp_max_syn_backlog 时,后面的会被丢弃。

所以,适当增大这个值,可以在压力大的时候提高握手的成功率。手册里推荐大于 1024。使用服务器的内存资源,换取更大的等待队列长度,让攻击数据包不至于占满所有连接而导致正常用户无法完成握手。

当半连接的请求数量超过了 tcp_max_syn_backlog 时,内核就会启用 SYN cookie 机制,不再把半连接请求放到队列里,而是用 SYN cookie 来检验。

启用之前,服务器在接到 SYN 数据包后,立即分配存储空间,并随机化一个数字作为 SYN号发送 SYN+ACK 数据包。然后保存连接的状态信息等待客户端确认。启用 SYN Cookie 之后,服务器不再分配存储空间,而且通过基于时间种子的随机数算法设置一个 SYN 号,替代完全随机的 SYN 号。发送完 SYN+ACK 确认报文之后,清空资源不保存任何状态信息。直到服务器接到客户端的最终 ACK 包,通过 Cookie 检验算法鉴定是否与发出去的 SYN+ACK报文序列号匹配,匹配则通过完成握手,失败则丢弃。当然,前文的高级攻击中有 SYN 混合 ACK 的攻击方法,则是对此种防御方法的反击,其中优劣由双方的硬件配置决定。

连接释放

参与一条TCP连接的两个进程中的任何-一个都能终止该连接,连接结束后,主机中的“资源”(缓存和变量) 将被释放。

计网复习05-传输层
  1. 客户端发送连接释放报文段,停止发送数据,主动关闭TCP连接。FIN=1,seq=u
  2. 服务器端回送一个确认报文段,客户到服务器这个方向的连接就释放了——半关闭状态。ACK=1,seq=v,ack=u+1
  3. 服务器端发完数据,就发出连接释放报文段,主动关闭TCP连接。FIN=1,ACK=1,seq=w,ack=u+1
  4. 客户端回送一一个确认报文段,再等到时间等待计时器设置的2MSL (最长报文段寿命)后,连接彻底关闭。

这个过程也被称为“四次挥手”

为什么要有time_wait?

  1. 可靠的终止 TCP 连接,若处于 time_wait 的 client 发送给 server 确认报文段丢失的话,server将在此又一次发送 FIN 报文段,那么 client 必须处于一个可接收的状态就是 time_wait 而不是 close 状态。
  2. 保证迟来的 TCP 报文段有足够的时间被识别并丢弃,linux 中一个 TCPport 不能打开两次或两次以上。当 client 处于 time_wait 状态时我们将无法使用此 port 建立新连接,假设不存在 time_wait 状态,新连接可能会收到旧连接的数据。

为什么建立连接协议是三次握手,而关闭连接却是四次握手呢?

这是因为服务端的 LISTEN 状态下的 SOCKET 当收到 SYN 报文的建连请求后,它可以把 ACK和 SYN(ACK 起应答作用,而 SYN 起同步作用)放在一个报文里来发送。但关闭连接时,当收到对方的 FIN 报文通知时,它仅仅表示对方没有数据发送给你了;但未必你所有的数据都全部发送给对方了,所以你可以未必会马上会关闭 SOCKET,也即你可能还需要发送一些数据给对方之后,再发送 FIN 报文给对方来表示你同意现在可以关闭连接了,所以它这里的 ACK 报文和 FIN 报文多数情况下都是分开发送的。

TCP状态机

计网复习05-传输层

原创文章,作者:彭晨涛,如若转载,请注明出处:https://www.codetool.top/article/%e8%ae%a1%e7%bd%91%e5%a4%8d%e4%b9%a005-%e4%bc%a0%e8%be%93%e5%b1%82/

发表评论

电子邮件地址不会被公开。