《计算机网络:自顶向下方法》笔记3 运输层

第三章

概述和运输层服务

网络层提供了主机之间的逻辑通信,而运输层为不同主机上的进程提供了逻辑通信。

tcp和udp最基本的责任是将两个端系统间的ip交付服务扩展为运行在端系统上两个进程之间的交付服务。这被称为是运输层的多路复用和多路分解。

tcp提供可靠数据传输和拥塞控制。

多路复用与多路分解

在接收端,将运输层报文段中数据交付到正确的套接字叫多路分解。

在源主机中从不同套接字中收集数据块,并为每个数据块封装上首部信息而生成报文段,然后传递给网络层,这叫多路复用。(回忆:套接字是从应用层到运输层的接口。然后思考一下为什么是复用和为什么是分解)

要求

  • 套接字有唯一标识符
  • 每个报文段有特殊字段指示报文段要交付的套接字

特殊字段是源端口号字段和目的端口号字段。0-1023是周知端口号。

无连接的多路复用与多路分解

1
2
clientSocket = socket(AF_INET, SOCK_DGRAM)
clientSocket.bind(('', 12000))

第一行是创建一个udp socket并且自动给它分配一个端口号。第二行是给它钦定一个。一般来说服务器端都是钦定,客户端都是自动分配端口号。

一个udp套接字由二元组(目的ip地址,目的端口号)全面标识。只要两个udp报文段有同样的目的ip地址和目的端口号,就会通过同样的目的套接字定向到同样的目的进程。

面向连接的多路复用与多路分解

一个tcp套接字由四元组(源ip,源端口,目的ip,目的端口)全面标识。

考虑服务器上有一个欢迎套接字位于12000,那收到一条请求创建连接的套接字以后就会创建一个新的套接字

1
connectionSocket, addr = serverSocket.accept()

所以,以后运输层再看到和(该报文段中源ip,源端口,目的ip,目的端口12000)一样的报文段,就分配到相应的connectionSocket。

仔细研读这个链接,可以纠正认识。

web服务器与tcp

连接套接字和进程并非总是一一对应,现在常用的做法是只用一个进程,为每个客户连接创建一个具有新连接套接字的新线程。

频繁创建关闭套接字也影响性能。

无连接运输:UDP

udp好处:

  • 关于发送什么数据以及何时发送的应用层控制更为精细
  • 无需连接建立
  • 无连接状态
  • 分组首部开销小

应用层协议和snmp和dns就常用udp。

使用udp的应用也可能实现可靠数据传输。比如quic。

udp报文段

udp首部有源端口号、目的端口号、长度、检验和四个字段,每个字段2字节。

检验和是把所有16bit的字求和然后反码。任何溢出都回卷(把前面多出来的1加到最后)。

可靠数据传输原理

借助可靠信道,传输数据比特就不会损坏或丢失,所有数据都是按照其发送顺序交付。tcp是在不可靠的(ip)端到端网络层上实现的可靠数据传输协议。

然后搓一个rdt协议:

rdt

rdt1.0

经完全可靠信道的可靠数据传输

发送和接收方的有限状态机FSM如下

rdt1.0

rdt2.0

信道也许会有bit差错。

除了肯定确认和否定确认,自动重传请求ARQ协议还需要差错检测、接收方反馈、重传三种协议功能。

rdt2.0

发送方将不会发送新数据,除非发送方确信接收方已经正确接收分组。这叫停等协议。

rdt2.1

但是……要是ack或者nak受损了呢?

解决方法是发送方添加数据分组编号。对于停等协议只需要1bit,这便足以让接收方知道是在重传还是发新分组。

rdt2.1send

rdt2.1-recv

这张图着重理解receiver的FSM的六种转移。

rdt2.2

其实没有nak也行。把nak改成对上一次正确接收的分组再发一次ack,效果一样。但是现在ack要带上分组序号了。

rdt2.2send

rdt2.2recv

rdt3.0

现在辣鸡信道学会了丢包。

一种做法是让发送方负责检测和恢复丢包。发送方明智地选择一个时间值,过了就是丢包了。如果一个分组经历了特别长的时间 ,那发送方就可能重传。即使它和ack都没丢失。不过rdt2.2已经能应对冗余数据分组了。

为了实现基于时间的重传机制,需要一个倒计数定时器。

rdt3.0

分组序号在0和1之间交换,所以rdt3.0有时候也称为比特交替协议。

流水线可靠数据传输协议

rdt3.0太慢辣!

然后来条流水线。影响是必须增加序号范围,发送接收两方不得不缓存多个分组。

解决序号范围和缓冲的要求两种基本方法:回退N步和选择重传。

回退n步

回退N步协议GBN。

gbn

在gbn协议中发送方看到的序号范围如上。base是最早未确认分组的序号,nextseqnum是最小的未使用序号。N是窗口长度,所以gbn协议也常称为滑动窗口协议。

gbn协议对分组的确认采取累积确认方法,即接收方已经正确地接受n及以前包括n的所有分组。

出现超时,发送方重新发送所有发送但没有确认的分组。收到ack但还有这样的分组就重启计时器。没有这样的分组就停止计时器。

接收方按序正确接收到编号为n的分组时,为分组n发送一个ack并将分组数据交付上层。其他任何时候,丢弃分组并且给最近按序接收的分组重新发送ack。

gbn

选择重传

选择重传sr。

sr

sr协议让发送方仅重传那些它怀疑在接收方出错的分组而避免不必要的重传。现在每个分组都必须有自己的逻辑定时器了。

面向连接的传输:TCP

tcp连接

tcp

tcp是全双工的。

tcp有发送缓存和接收缓存。tcp可以从缓存中取出并放入报文段的数据数量受限于最大报文段长度MSS。mss通常由发送主机的最大传输单元MTU来设置(最大链路层帧)。mtu典型值是1500,tcp/ip首部字段通常为40,mss的典型值为1460。

tcp报文

tcp

tcp首部的典型长度是20字节(选项为空)。接收窗口字段用于流量控制。

一个报文段的序号是报文段首字节的字节流编号。例如数据流是包含500000字节的文件组成,MSS是1000字节,那么tcp会为该数据流构建500个报文段。第一个序号0,第二个1000……当然起始序号也不一定是0。

确认号是主机期望从对面收到的下一字节的序号。

这是一个telnet例子:

telnet

往返时间和超时

在一个时刻,未发送但尚未确认的报文段估计样本rtt即samplertt。(不给重传的计算)

一旦获取新的samplertt,估计rtt即estimatedrtt=0.875*estimatedrtt+0.125*samplertt(这个数字是推荐值)。

同样,rtt偏差即devrtt=0.75*devrtt+0.25*|samplertt-estimatedrtt|。

然后tcp的超时间隔timeoutinterval=estimatedrtt+4*devrtt。出现超时就加倍,收到报文并更新estimatedrtt就再次计算。

重传

要是发送方收到对相同数据的三个冗余ack,就说明这之后的报文段丢失,执行快速重传。

流量控制

让发送方维护一个接收窗口,用于指示发送方接收方还有多少可用的缓存控件空间。因为是全双工的,所以两端都维护一个。

定义lastbyteread:主机B应用从缓存读出最后一个字节编号;lastbytercvd:网络中到达并且存入B接收缓存的最后一个字节的编号。因为tcp不允许分配的缓存溢出,所以必有lastbytercvd-lastbyteread$\leq$rcvbuffer。接受窗口rwnd=rcvbuffer-(lastbytercvd-lastbyteread)。

B通过把rwnd值放到给A的报文来通知A。而A要保证lastbytesend-lastbyteacked$\leq$rwnd。

但是rwnd=0以后,A继续发送只有一个字节数据的报文段。不然A不会知道B的接收缓存有新的控件:因为tcp仅当有数据或者确认要发的时候才发送(B到A)。顺带一提udp不提供流量控制。

tcp连接管理

传说中滴三次握手来辣

tcp3

  1. 客户端发一个特殊报文。SYN 比特置为1,随机选择一个初始序号client_isn
  2. 服务器提取tcp syn报文段,分配tcp缓存和变量,向客户发送允许的报文。这个是SYNACK报文段。
  3. 客户端也分配缓存和变量。进行确认。此时可以携带客户到服务器的数据了。

四次挥手:

tcp4

如图。

SYN洪泛攻击

如果有攻击者大量发送tcp syn报文段但是不ack,而且服务器还要给他们分配大量资源,那就白给了。

所以当服务器收到一个syn报文段的时候,它不会生成一个连接,而是通过一个关于源和目的ip地址和端口号以及只有本服务器知道的一个神秘数的一个复杂函数生成初始TCP序列号,这个就是cookie。服务器发送具有这种特殊初始序列号的SYNACK分组。注意:服务器并不记忆cookie或者任何对应这个syn的其他状态信息。

接着服务器收到ack。怎么判断呢?服务器再生成一下cookie。要是是一个合法的ack,那它的确认字段中的值应该等于cookie+1。不然就不合法。

奇怪的报文段

如果主机收到了不匹配任何套接字的tcp报文段,就会向源发送一个特殊重置报文段(RST标志置1)。就是让它别发了。至于UDP的话,会发送一个特殊的icmp数据报。

拥塞控制原理

拥塞的代价

假设路由器缓存无限:

分组的到达速率接近链路容量时,分组经历巨大的排队时延。

假设路由器缓存有限:

发送方在遇到大时延时进行的不必要重传会引起路由器利用其链路带宽转发不必要的分组副本。

当一个分组沿一条路径被丢弃时,每个上游路由器用于转发该分组到丢弃该分组而使用的传输容量浪费了。

拥塞控制方法

  • 端到端拥塞控制。网络层没有为运输层控制提供显式支持。tcp用的这个。
  • 网络辅助的拥塞控制。最近也能选择性地使用这个。

TCP拥塞控制

tcp的方法是让每一个发送方根据所感知到的网络拥塞程度来限制其能向连接发送流量的速率。

tcp拥塞控制机制跟踪一个额外的变量拥塞窗口cwnd,使lastbytesent-lastbyteacked$\leq$min{cwnd, rwnd}。

指导原则:

  • 一个丢失的报文段意味着拥塞。丢失报文段时应降低tcp发送方的速率。
  • 一个确认报文段指示该网络正在向接收方交付发送方的报文段。因此,当对先前未确认的报文段确认到达时能增加发送方的速率。
  • 带宽探测。ack和丢包事件充当了隐式信号。

TCP拥塞控制算法三铳士:慢启动、拥塞避免、快速恢复。第三个不是强制的。

慢启动

tcp连接开始时,cwnd值通常初始置为一个mss较小值。使得初始发送速率大约为mss/rtt。

cwnd的值以一个mss开始并且每当传输的报文段首次被确认就翻倍。慢启动过程是指数增长的。

何时结束慢启动?

  • 存在超时指示的丢包事件。ssthresh(慢启动阀值)设置为cwnd/2,cwnd设置为1,重新开始慢启动。
  • 到达或超过ssthresh,结束慢启动,转移到拥塞避免模式。
  • 检测到3个冗余ack,执行快速重传并进入快速恢复状态。

拥塞避免

现在不翻番了,每个rtt只将cwnd值增加一个mss。一种方法是发送方无论何时到达一个新的确认就将cwnd增加一个MSS(MSS/cwnd)字节(这儿看看书吧)。

  • 超时时,ssthresh=cwnd/2,cwnd=1
  • 三个冗余ack,ssthresh=cwnd/2,cwnd值减半,进入快速恢复

快速恢复

对收到的每个冗余ack,cwnd增加一个mss。最终当对丢失报文段的一个ack到达时,tcp降低cwnd后进入拥塞避免。

丢包时间出现时,ssthresh=cwnd/2,cwnd=1

tcp

上面是tcp拥塞控制的FSM。

tcp拥塞控制也常常成为加性增、乘性减(AIMD)拥塞控制方式。

吞吐量和公平性

一条连接的平均吞吐量:$\dfrac{1.22\mathrm{MSS}}{\mathrm{RTT}\sqrt L}$,其中L是丢包率。

已经表明多条连接共享一个瓶颈链路时,那些具有较小rtt的连接能在链路空闲时更快抢到可用带宽。

明确拥塞通告

tcp

如图。

打赏
  • © 2018-2020 poorpool
  • Powered by Hexo Theme Ayer
    • PV:
    • UV:

请我喝杯草莓芝士奶盖吧~

支付宝
微信