运输层
运输层为运行在不同主机上的应用进程之间提供了逻辑通信
1. 运输层的服务
1.1 运输层和网络层的关系
网络层提供了主机到主机的逻辑通信,运输层提供了应用进程到应用进程之间的逻辑通信(端口到端口)
1.2 因特网运输层协议概述
两种协议:
TCP(传输控制协议) :提供一种可靠面向连接的服务
所能提供的服务:
- 进程和进程之间的数据交付
- 差错检查
- 可靠数据传输
- 拥塞控制
UDP(用户数据报协议):提供一种不可靠无连接的服务
所能提供的服务:
- 进程和进程之间的数据交付
- 差错检查
2. 多路复用和多路分解
假设你在电脑前正在下载一个web页面,但是你的电脑还运行着一个FTP程序和两个Telnet会话,当你的计算机从网络层接收到数据的时候他们是如何把数据发送到对应的某个进程
多路分解:
运输层报文段将数据交付到正确的套接字的工作
多路复用:
源主机中将不同的数据块分装上运输层首部信息(用于分解),生成报文段,交付给网络层
实际工作原理:
运输层多路复用要求:
- 套接字有唯一标识符
- 每个报文段有特殊字段来指示该报文段索要交付到的套接字
如图所示,这些特殊字段就是源端口号字段和目的端口号字段
端口号:
一个16比特的数字,范围是(0-65535),(0-1032)范围的端口号是周知端口号(被一些常见的应用使用http,ftp等)
每个套接字及对应一个端口,每一个应用程序都有一个端口
分解服务实现过程:
运输层会根据报文段中的端口字段,将报文分配给对应的进程
1. 无连接的多路复用和多路分解
UDP套接字面向无连接:
- 主机中进程A(UDP端口:10056)要给另一台主机的进程B(UDP端口:1913)发送数据
- 主机A创建一个运输层报文段(应用数据,源端口,目的端口,其他值)
- 运输层将报文段提交给网络层,网络层交付给主机B
- 主机B将报文交给运输层检查目的端口号(UDP:1913),则将数据报交给(UDP:1913)所标识的套接字
注意:
- 一个UDP套接字是一个二元组标识,包含目的IP地址和目的端口号
- 源端口号的用途:被作用返回地址的一部分
2. 面向连接的多路复用和多路分解
TCP套接字面向连接:
- TCP服务器有一个”欢迎套接字程序”,他在12000端口上等待客户建立请求
- 客户使用如下代码创建一个套接字,并发送一个连接请求
clientSocket = socket(AF_INET,SOCK_STREAM)
clientSocket.connect((servername,12000))
- 一个连接建立请求只不过是一个目的端口号为12000,TCP首部的特定”连接建立位”置位的TCP报文段,这个报文段也包含了由客户选择的源端口号
- 服务器操作系统接收到具有目的端口12000的连接请求报文后,定位服务器进程(TCP:12000),该服务器进程创建一个新的套接字
connectionSocket, addr = serverSocket.accept()
- 服务器的运输层还注意到:
- 报文段中的源端口号
- 源主机IP地址
- 报文段中的目的端口号
- 自身的IP地址
- 新创建的套接字就用这四个字段标识,当再次有新的报文时,如果四个字段都相同,则使用此链接
注意:
- 一个TCP套接字是一个四元组(源IP和源端口,目的IP和目的端口)
- 这四个元素均被用来识别服务器上的某一套接字接口
3. Web服务器和TCP
简单来说:
服务器运行着80端口的进程,我们每次访问服务器建立TCP连接都是该进程的一个子线程(轻量级进程)
持续
http连接
,只需要建立一次tcp连接
,非持续http连接
,需要建立多次tcp连接
3. 无连接运输UDP
UDP的优点:
- 运输速度快(某些实时应用需求以及DNS等)
- 无需建立连接(不会引入建立连接的时延,google浏览器)
- 无连接状态(不需要维护连接,跟踪连接参数,可以支持更多的活跃用户)
- 分组首部开销小(UDP首部仅8字节,TCP首部20字节)
因特网应用及其运输协议:
应用 | 应用层协议 | 运输协议 |
---|---|---|
电子邮件 | SMTP | TCP |
远程终端访问 | Telnet | TCP |
web | HTTP | TCP |
文件传输 | FTP | TCP |
远程文件服务器 | NFS | 通常UDP |
流式多媒体 | 通常专用 | UDP或TCP |
因特网电话 | 通常专用 | UDP或TCP |
网络管理 | SNMP | 通常UDP |
名字转换 | DNS | 通常UDP |
3.1 UDP报文段结构
长度:
UDP报文段(首部+应用数据)的字节大小
校验和:
检查报文段是否有差错
3.2 UDP校验和:
- 过程:
发送方:将报文段的所有16比特的字
的和进行反码运算,求和时遇到任何的溢出均会回卷(把进位加到后面)
接收方:将接收到的报文的所有16比特的字
(包括检验和)进行求和运算,如果没差错,则校验和是1111111111111111
,如果有一个是0,说明不正确
上面图中,3个16比特的字
求和,最后接收方需要对4个16比特的字
求和,检验是否是正确的结果(16个1)
- 处理:
UDP会将出错的报文段丢弃或者交给发出的应用程序并且发出警告
4. 可靠数据传输原理
数据可以通过一条可靠信道进行传输,借助于可靠信道传输数据比特就不会损坏或丢失而且所有数据都是按照其发送数据进行交付。
4.1 构造可靠数据传输协议:
发送方
和接收方
每个都只有一个状态
rdt
的发送端通过rdt_send
接受一个来自高层的数据,产生一个该数据的分组(经由make_pkt(data)动作)并将分组发送到信道之中。实际上,rdt_send(data)
事件是在由较高层应用的过程调用产生的在接收端,
rdt
通过rdt_rcv(packet)
事件从底层信道接受一个分组,从分组中取出数据(经由extract(packet,data)
),并将数据上传给交高层(通过diliver_data(data)动作)。
进入一种新的信道,不再完全可靠(可能会出现些许比特的错误)的传输但是数据报仍然按次序传输
发送端: 发送报文
接收端: 接收报文,判断报文是否出错,返回肯定,否定控制报文
如果报文出错,接收端会告诉发送端需要重新发送,这种基于重传机制的可靠数据传输协议称为自动重出传请求(ARQ)协议
ARQ协议
处理还需要另外三种协议处理比特差错:
- 差错检测:包括前面说到的检验和字段,后面还有其他的差错检验和纠错技术
- 接收方反馈: 报文无差错返回肯定确认(ACK)包,报文有差错,返回否定确认(NAK)包
- 重传:接收方收到有差错的分组,发送方重传分组
- Rdt2.0发送端有两个状态,最左边,发送端协议等待来自上层的数据,当
rdt_send()
事件出现时,发送方将产生一个包含带发送数据的分组(sndpkt)
,带有检验和,由udt_send(data)发送分组 - 发送方协议最右边等待来自接收方的
ACK
或者NAK
分组,收到ACK
,发送方确认已被正确接收,回到左边的状态,收到NAK
,说明出错,则进行重传上个分组,并等待接收ACK和NAK状态
注意:
在发送方处于等待ACK或NAK状态
的时候,他不能从上层获取更多的数据,也就是rdt_send()
事件不能发生,仅当接收到ACK
时,才能接收数据,rdt2.0
的这种协议被称为**”停等协议”**
- 接收方:当分组到达时,要么回答
ACK
,要么回答NAK
只有一个状态,符号rdt_rcv(rcvpkt)&&corrupt(rcvpkt)
对应于收到一个分组并发现有错
如果ACK和ANK包受损:
三种可能的情况:
- 第一种可能:
- 发送者接收到模糊不清的”OK”和“请重复一遍”,可能会向接收端发送“你说什么”的报文,但是接收端无法确定这是一个新的请求,还是因为AcK和ANK受损的反应
- 第二种可能:
- 增加足够的检验和比特,使得发送方不仅可以检测差错,还可以恢复差错
- 第三种可能:
- 无论是ACK和NAK分组,只要是受损的含糊不清的直接重发数据报,但是这样就会导致很多冗余分组,而且这种情况下,接收方无法事先知道这个分组是新的分组还是重发的分组
第三种方法的一个简单的解决办法:
每个报文添加一个字段,利用该字段对分组编号,如果接收方接收到的报文的序号与之前的序号相同,则证明是重发的报
替换NAK
针对一个数据包,如果接收方向接受正常那么发送ACK包
,如果接收不正常那么返回NAK
,但是我们可以在接收不正常(丢包,或者数据包出错)的情况下,让接收方发送对上一个数据包的ACK确认包
,证明现在的数据报出错,从而避免发送NAK
3. 具有比特差错的丢包信道的可靠数据传输:rdt3.0
1. 数据丢包的两个情况:
发送方发送的数据包,丢失
接收方发送ACK包丢失
2. 处理方式:
发送方会在发送一个数据报之后,设定一个时间段(发送方接收方之间的往返时延以及接收方处理的时间),如果在这个时间段之内没有接受到ACK包,则会重发数据报
注意:
- 由于某些特殊的情况,时间不准确,数据报正确到达了接收方,但是超过了时延,导致出现了
冗余数据报
,此时我们就可以用序号
处理
3. 基于时间的重传机制
发送方:
- 重传可以解决绝大多数的问题
- 实现重传,需要做到以下几点:
- 每次发送一个分组,启动一个定时器
- 响应定时器中断
- 终止定时器
4.2流水线可靠数据传输协议:
rdt3是一个停等协议,经过计算之后(深入理解计算机系统的143页),即使很大带宽的链路在一段时间只能发送很少的字节,这种协议就限制了底层硬件所能提供的能力
解决办法就是不以停等方式运行
,发送方可以发送多个分组而不需要等待接收确认,就像一条流水线
- 流水线技术对数据传输协议的影响:
- 必须增大序号范围,每个传输的序号必须有一个唯一的序号,而且有多个在输送中未确认的报文
- 协议的发送方和接收方必须能缓冲多个分组
- 所需要序号的范围和缓冲的要求,取决于数据传输协议如何处理丢失,顺坏以及延时过大的分组(两种处理方式:回退N步,重新传输)
4.3回退N步(GBN)
允许发送方发送多个分组,不需要等待确认,当然也受限于流水线中未确认的分组数,不能超过某个最大的允许数N
将基序号定义为最早未确认分组的序号,将下一个序号定义为最小的为使用的序号(即下一个带分发的分组的序号),则可将序号范围分割成4段,在[0-bse-1]段对应的分组已经发送并被确认。[base,nextseqnum-1]段对应已经发送但未被确认的分组。[nextseqnum,base+N-1]段内的序号能用于那些立即发送的分组,如果有数据来自上层的话。大于或等于base+N的序号是不能使用的,直到当前流水线中未被确认的分组(特别是序号为base的分组)已得到确认位置
GBN发送当必须相应三种类型的事件:
- 上层的调用:
- 首先检查窗口是否已满,即是否有N个已发送但未被确认的分组,如果窗口未满则产生一个分组并将其发送并相应地更新变量,如果已满则指将数据返回给上层
- 水中不会立刻发送而是缓冲一会过一会再尝试
- 收到一个ACK:
- 在GBN协议中,对序号为n的分组的确认采取
累计确认
的方式
- 在GBN协议中,对序号为n的分组的确认采取
- 超时事件:
- 如果出现超时,发送方重传所有已发送的但还未被确认过的分组
4.4 选择重传(SR)
很显然上一种方式可能会导致大量的分组出现多次传送和接收
发送方:
- 重新传输哪些怀疑在接收方出错的分组,避免了不必要的重传
接收方:
- 确认接受一个正确接收的分组而不管其是否按序,失序的分组会被缓存直到所有的丢失分组都被收到为止
5. 面向连接的运输:
5.1 TCP连接:
TCP是面向连接的,这种链接是一种逻辑链接,即不是真正的通信连接电路,只是两个端系统在通信之前互相发送某些报文段(双方的一些信息),由对方机器接收后建立数据传输的参数
TCP连接是双工的:两个端系统A,B。A传给B报文的同时B也能把报文传给A
python
中通过这样一条命令,让客户端于服务端建立连接请求
clientSocket.connect((serverName,serverPort))
serverName服务器的名字,serverPort标识了服务器上的进程。
简单理解三次握手:
- 客户端首先发送一个特殊的TCP报文字段
- 服务器用另一个TCP报文端响应
- 客户再用第三个特殊的报文段作为响应(承载有效载荷)
由于两台主机发送了三个报文端,所以这种连接也被称为
三次握手
客户进程通过套接字传递数据流,一旦通过这道门,数据将会由TCP控制,TCP将这些数据引到该连接的(发送缓冲)
中,三次握手期间设置,之后TCP会从缓冲中提取数据。TCP
可以缓冲中取出并放入报文段的数据数量受限于最大报文段长度
(MSS1460字节),MSS
最初确定的有本地发送方主机发送的最大链路层帧长度(最大传输单元MTU1500字节
)
5.2 TCP报文段结构
在传送较大的文件块时,通常分割成多分(MSS),最后一块通常不是
- 32比特的序号字段和32比特的确认号字段,被TCP和发送方和接收方用来实现可靠数据传输服务
- 16比特的接受窗口字段,用于流量控制,指示接收方愿意接受的字节数量
- 4比特的首页v一长度字段,该字段指示了以32比特的字为单位的TCP首部长度,由于选项字段的原因,TCP首部长度是可变的(通常选项字段为空,所以TCP首部的典型长度是20字节)
- 可选与变长的选项字段,改字段用于发送方和接收方协商报文段长度(MSS)时
- 6比特的标志字段,ACK比特用于指示确认字段中的值是有效的,即该报文段包括对一个已被成功接收的报文段的确认。
RST,SYN和FIN
比特用于连接建立和拆除
1. 序号和确认号
TCP吧数据看成一个无结构的有序的字节流,
序号是建立在传送的字节流之上为不是报文的序列之上
比如说一个文件500000字节大小,而一个报文段的MSS是1000字节,那么就需要500个报文段,,给第一个报文段分配u的序号0,则第二个报文段分配序号是1000,第三个分配序号是20000
累计确认:
TCP值确认流中至第一个丢失字节为止的字节
2. Telnet: 序号和确认号的学习案例:
Telnet可以在一个主机A连接到另一个主机B,能在主机A看到主机B的桌面,我们输入一个字符,主机B会将字符返回给被连接的远程桌面
主机A在主机B发送一个字符C的过程(已经建立了TCP连接):
客户端主机A发送一个报文段给服务器,在他的数据字段里包含了一个字节的字符‘C’,第一个报文段的序号是42,确认序号是79
第二个报文段有服务器发送给客户:
- 首先他为该服务器收到的数据提供一个确认,通过
ACK=43
,服务器告诉他已经成功收到字节42,期待收到字节43的出现 - 第二个目的就是回显’C’字符,79是服务器到客户的数据流的起始序号
显然,第二个报文是为了回显字符C,捎带确认报文
- 首先他为该服务器收到的数据提供一个确认,通过
第三个报文从客户发往服务器,唯一目的是确认已从服务器收到的数据
4.可靠数据传输
TCP有3个与发送和重传有关的事件:
- 上层应用层序接收数据
- 定时器超时
- 收到ACK
第一个主要事件:
TCP
从应用层序中接受数据,将数据分装在一个报文段中,并把报文段交给IP
,如果定时器没有为某些其他报文段而运行,则启动定时器
第二个主要事件:超时
TCP重传
引起超时的报文段,且重启定时器
第三个主要事件:来自接收方的确认报文段
TCP
的SendBase
是最早未被确认的字节的序号,TCP采用累计确认,当有一个ACK
报文到达,那么编号为y的ACK(y>SendBase)
就证明y之前的所有字节被全部接受,发送方更新他的SendBase
变量
一些有趣的情况:
- 主机A向主机B发送一个报文段,假设该报文段的序号是92,而且是8个字节。在发出该报文段之后主机A,等待主机B序号为100的确认报文段,虽然A发送的报文已被接受,但是B发送的确认报文丢失,那么就会触发A超时重传,主机B接收到发现已经正确接受过该序号,会丢掉该报文
- 主机A连续发送了两个报文段。。。。。(161页)
超时间隔加倍:
- 在主机A发送数据报后0.75秒发生超时,则主机A重发该数据报并设置超时时间是1.5秒,若还发生超时,则继续重发设置超时为3秒以此类推
快速重传:
超时重传可能会出现超时周期过长,导致过长的时延。
冗余ACK:
- 再次确认某个报文段的ACK,而发送方先前已收到对应的ACK,接收端有一个期望收到的序号,但是如果这次接受到的序号大于期望的序号,则证明期望的序号数据报已经丢失,因为接收方不适用否定确认,那么TCP就会发送一个ACK确认包确认上一个已经接受到的数据报,如果发送方接受到3次荣誉ACK,则证明这个已被确认的报文段已经丢失 ,TCP就开始重传(快速重传)
流量控制
之前提到发送方和接收方都有一个缓冲窗口,TCP是双工的,所以每一端都会管理一个接收窗口
主机端接收数据报放在缓冲中等待应用程序提取数据,如果来不及提取就会放在缓冲(RcvBuffer)里,但是接收缓冲有一定的大小,如果数据报过多缓冲放不下,就会导致缓冲溢出
LastByteRead
: 主机b上的应用进程从缓存中读出的数据流的最后一个字节的编号LastByteRcvd
: 从网络中到达的并且已放入主机接收缓存的数据流的最后一个字节的编号rwnd:
LastByteRcvd-LastByteRead主机B通过把当前的rwnd
值放入他发给的主机A的报文段中,通知A他在该连接的缓冲中还有多少可用空间
由TCP不允许已分配的缓存溢出:
LastByteRcvd-LastByteRead<=RcvBuffer
另LastByteRcvd-LastByteRead=rwnd
,则主机A发送到连接但未被确认的数据量就是rwnd
若是主机B缓冲已满,但rwnd=0
,告诉主机A之后,A就不会发送数据给B,但是B有了新的缓存之后,A不能确定是否有新的缓存空间,就向B发送一个一字节的报文,那么此时B就会发送一个rwnd值不为0
报文
6. TCP连接管理
本节介绍一个TCP连接的创建和删除
创建TCP连接
第一步:
- 将报文段的首部的标志为SYN比特放置为1
- 客户端的TCP随机选择一个序号
(client_isn)
,将其放在TCP报文段的序号字段中 - tCP报文段被方在IP数据报中
第二部L:
服务器收到IP据报,服务器从IP数据包中提取TCPSYN报文段,为该TCP连接分配TCP缓冲和变量,像客户端发送允许链接的报文段
- SYN比特被置为1.
- 该TCP报文段的确认号字段被置
client_isn+1
。 - 服务器选择自己的出啊是序号
(server_isn)
,并将起置于手部的序号字段中
该报文称为
SYNACK
报文段第三步:
客户收到SYNACK报文段之后,客户也要给连接分配缓存和变量。
- 对服务器的允许连接报文进行确认(将
server_isn+1
放置到TCP报文首部的确认字段) - 因为连接已经建立,SYN比特置为0
- 可以在报文段的负载中携带客户到服务器的数据
- 对服务器的允许连接报文进行确认(将
上面三个报文段被称为三次握手
关闭TCP连接:
- 关闭连接的一方:
- 发送一个
FIN
标志位,置为1 的特殊TCP报文段。
- 发送一个
- 服务器:
- 发送确认字段
- 发送自己的终止报文段
- 关闭连接的一方:
- 对服务器的终止报文段进行确认
连接结束之后所有的资源都会被释放
拥塞控制原理
拥塞控制方法:
- 端到端拥塞控制:
- TCP报文段的丢失(通过超时或者3次冗余确认而得之)被认为是一个网络拥塞的现象,TCP会相应的减少其窗口长度
- 使用增加的往返时延值作为网络拥塞成都增加的指示
- 网络辅助的拥塞控制:
- 路由器向发送提供关于拥塞状态的显示反馈信息
- 在ATM可用比特率拥塞控制中路由器显示地通知发送方它(路由器)能在输出链路上上支持的最大主机发送速率
7 TCP拥塞控制
TCP必须使用端到端的拥塞控制不是使用网络辅助的拥塞控制
要球发送方能够感知连路上的拥塞程度而控制自己的发送速率
三个问题:
- 一个TCP发送方如何控制发送方向连接发送流量的速率
- 一个TCP 发送如何感知他到目的地之间的路径上存在拥塞呢
- 当发送方感知到端到端的拥塞是采用何种算法来改变其发送速率呢
TCP连接的每一段都是有一个接受缓存,一个发送缓存和几个变量组成的。运行在发送方的TCP用色控制机制跟踪一个额外的变量,即*拥塞控制窗口
拥塞窗口标志为
cwnd
,他对一个TC发送方能像网络中发送流量的速率进行了限制
TCP如何感知它与目的地之间的路径上出现了拥塞的:
- 出现丢包事件(要么超时要么收到3个荣誉ACK),发送方就认为出现了拥塞的指示
- 没有丢包的情况下,TCP会通过接收到的
ACK包
的速率来增大窗口的长度,ACK速率越快,发送方增大窗口的速率也快,因此TCP被说成是自计时放
发送方怎样确定他应当发送的速率:
发送方怎么让更高的速率发送,不会是网络拥塞,同时又能充分利用带宽
一个丢失的报文段意味着拥塞,减小窗口长度以减小发送速率
一个确认报文段指示该网络正在向接收方交付发送方的报文段,因此,当兑现钱未确认的报文段的确认到达时,能够增加发送方的速率
带宽检测:为探测拥塞出现的速率,TCP发送方会一直增加他的速率,从该速率后退,进而再次检测
TCP拥塞控制算法;
- 慢启动:
- 拥塞避免
- 快速恢复
在慢启动状态:
cwnd的值以一个MSS开始并且每当传输报文段的首次被确认就增加一个MSS,很显然满启动是以指数增长的
何时结束增长:(三种情况)
若果存在一个由超时指示的丢包事件(即拥塞),TCP发送方将
cwnd
设置为1并重新开启慢启动过程将第二个状态的变量的值ssthresh(满启动阀值)设置为
cwnd/2
当检测到拥塞是
ssthresh
设为c w n d
的值一半,当等于ssthresh
的值时,结束慢启动并且TCP转移到拥塞避免模式如果检测到三种冗余ACK这是TCP执行一种快速重传并进入快速恢复状态
拥塞避免状态:
进入避免状态之后cwnd
的只大约是上次拥塞时的只的一般,之后每个RTT
只将cwnd
的值增加一个MSS
做法:
- 对于TCP发送饭无论何时到达一个新的确认,就将
cwnd
增加一个MSS(MSS/cwnd)
字节
快速恢复状态
- 对于引起快速恢复状态的却是报文段,对收到的每个冗余的
ACK
。cwnd
的只增加一个MSS
。最终对丢失报文段的一个ACK
到达时,TCP再降低cwnd
后进入拥塞避免状态 - 超时事件,快速恢复在执行如同在满启动和拥塞避免中相同的动作之后,迁移到慢启动状态
- 丢包事件出现时,
cwnd
的值被设置为1个MSS
,并且ssthresh
的值设置为cwnd
的一半