第五章 传输层
5.1传输层
- 传输层概述
- 传输层两个协议:TCP、UDP
- TCP协议
- 可靠传输
- 流量控制
- 拥塞控制
- UDP协议
- 端口号
- 套接字
- TCP与UDP的差别
- 多路复用与多路分解
传输层概述
为应用层提供通信服务,使用网络层的服务
网络层:主机之间的逻辑通信
传输层:进程之间的逻辑通信
(注:通信的实质:主机间进程的相互通信。)
传输层功能
- 提供进程与进程之间的逻辑通信
- 复用和分用
- 传输层对收到的报文进行差错检测
传输层协议运行方式
首先,应用层里是报文,网络层里是数据段。
发送方:
报文段——>数据段:将应用程序的报文拆分成数据段传递给网络层
接受方:
数据段——>报文段:将数据段重新组装成报文传递到应用层
面向连接的传输控制协议TCP
- 传送数据之前必须建立连接,数据传送结束后要释放连接。
- 不提供广播或多播服务。
- 由于TCP要提供可靠的面向连接的传输服务,因此不可避免增加了许多开销:确认、流量控制、计时器及连接管理等。
- 可靠,面向连接,时延大,适用于大文件。
无连接的用户数据报协议UDP
- 传送数据之前不需要建立连接,收到UDP报文后也不需要给出任何确认。
- 不可靠,无连接,时延小,适用于小文件。
传输层的动作
发送方:
- 传递一个应用层消息
- 确定报文段头部域值,并创建报文段 【T:Transport | H:Head】
- 传递报文段到 IP 层
接收方:
- 从 IP 层接收报文段,并检查头部值【确定发送到哪个应用程序】
- 提取应用层消息
- 通过套接字多路分解消息到应用层
传输层的寻址
复用:应用层所有的应用进程都可以通过传输层再传输到网络层。 (每个人都可以写信,交给邮差)
分用:传输层从网络层收到数据后交付指明的应用进程。 (邮差会分发邮件)
端口
- 端口是传输层的SAP,标识主机中的应用进程。
- 【 服务访问点 (service access point, SAP):实际就是逻辑接口,是一个层次系统的上下层之间进行通信的接口,N层的SAP就是N+1层可以访问N层服务的地方。】
- 端口号只有本地意义,在因特网中不同计算机的相同端口是没有联系的。
- 端口号长度为16 bit,能表示65536个不同的端口号
端口号
- 服务端使用
- 熟知端口号:给TCP/IP最重要的一些应用程序,让所有用户都知道。0~1023
- 登记端口号:也就是为不被人熟知的应用程序准备的端口号:1024~49151
- 客户端使用
- 仅在客户进程运行时才动态选择的端口号:49152~65535
以上是需要记住的熟知端口号,就像谈恋爱:21岁(FTP)发现了TA,23岁开始(TELNET)谈恋爱,25岁吵架,(SMTP)删好友,结果53岁了还在(DNS)打电话,最后80岁了(HTTP)还要再见。【HTTPS 443 老妖怪!】
套接字
在应用层与传输层直接有一个接口,就叫套接字。
在网络中采用发送方和接收方的套接字组合来识别端点,套接字唯一标识了网络中的一个主机和它上面的一个进程。
套接字(Socket) = (主机IP地址,端口号)
当接收主机接收UDP报文段时:
- 检查报文段中的目的端口号
- 用端口号指示UDP报文段属于哪个套接字
- 只要具有相同目的端口号,在目的端将指向相同的套接字
TCP与UDP的套接字要求
- TCP套接字由四元组标识: (源IP、PORT,目标IP、PORT)
- UDP由二元组标识: (目标IP、PORT)
为什么有这种区别?
- UDP套接字使用二元组来标识,是因为UDP是无连接的,源端和目的端无需建立关联并对应起来,接收方无需区分/考虑发送方。
- 而TCP是面向连接的,需要和发送方建立对应关系(注意不一定是一一对应,服务器可以并行处理)。
注意:
UDP套接字使用二元组来标识,并不是说客户端不需要传送自己的IP地址和端口给对方,而是在UDP中 源IP和端口由操作系统来决定。
在创建UDP套接字后,UDP报文段中同样有源端口号,到了网络层,IP数据报中也有源IP,源IP和源端口号同样需要发送给服务器,否则服务器无法回应请求。
使用UDP进行传输,在服务器上对应的进程,不用考虑分组是从哪个客户端来的,所有来自客户的请求都在同一个套接字处理,处理完了再根据源端口号和源 IP 地址,把应答信息发送给客户端。
TCP四元组的好处
由于TCP使用两个端点(四元组)来识别连接,一个机器上的某个TCP端口号可以被多个连接所共享。
多路复用和多路分解
多路复用、多路分解:基于报文段、数据报头部字段值,且发生在所有层
- UDP:仅使用目的端口号进行多路分解
- TCP:使用四元组进行多路分解:
以Web服务器为例:对每个连接的客户,甚至是不同的浏览器,都有不同的套接字,非持续 HTTP 对每个请求有一个不同的套接字
5.2 UDP协议
UDP只在IP数据报服务之上增加了很少功能,即复用分用(书上是端口)和差错检测功能。
注:
在使用UDP进行网络传输的过程中,UDP只负责数据传输。首先,UDP只负责将数据发出,但是不保证数据一定到达目的;而且,如果传输出现故障,UDP不负责重传数据,数据是否重传将由应用程序控制;其次,当数据正确到达后,UDP协议的接收方不负责发送“数据已经到达”的确认信息。而确认信息将由接收方的应用程序负责。
UDP在网络层使用IP层提供的不可靠的数据服务,仅通过端口号指明发送程序端口和接收程序端口,不保证数据一定到达目的主机。因此,对应用层而言,UDP提供的数据传输服务称为是无连接的、不可靠的用户数据报服务。
UDP的主要特点:
-
是无连接的,减少开销和发送数据之前的时延。
-
使用最大努力交付,即不保证可靠交付。就是说,可能会丢失,也可能会将失序的报文交付
-
面向报文的,适合一次性传输少量数据的网络应用。
-
发送方 UDP 对应用程序交下来的报文,在添加首部后就向下交付 IP 层。UDP 对应用层交下来的报文,既不合并,也不拆分,而是保留这些报文的边界。
应用层交给 UDP 多长的报文,UDP 就照样发送,即一次发送一个报文。
接收方 UDP 对 IP 层交上来的 UDP 用户数据报,在去除首部后就原封不动地交付上层的应用进程,一次交付一个完整的报文。
应用程序必须选择合适大小的报文。
-
-
无拥塞控制,适合很多实时应用,传输快(如网络电话,重点在于实时,临时卡顿丢失数据影响不大)
- UDP常用于一次性传输数据量较小的网络应用,如SNMP、DNS应用数据的传输。因为对于这些一次性传输数据量较小的网络应用,若采用TCP服务,则所付出的关于连接建立、维护和拆除的开销是非常不合算的。
-
UDP首部开销小,只有8B,TCP的占20B。
UDP动作
UDP 发送方动作:
- 传递应用层消息
- 确定 UDP 段头部字段值
- 创建 UDP 报文段
- 传递报文段给 IP
UDP 接收方动作:
- 接收来自 IP 的数据报
- 检查 UDP 头部校验和
- 提取应用层消息
- 通过套接字多路分解到应用程序
UDP首部格式
分用时,找不到对应的目的端口号,就丢弃报文,并给发送方发送 ICMP “端口不可达”差错报告报文。
用户数据报 UDP 有两个字段:数据字段和首部字段。
首部字段有 8 个字节!!
- 1.源端口: 源端口号,需要对方回信时选用,不需要时全部置0.
- 2.目的端口:目的端口号,在终点交付报文的时候需要用到。
- 3.长度:UDP的数据报的长度(包括首部和数据)其最小值为8(只有首部)
- 4.校验和:检测UDP数据报在传输中是否有错,有错则丢弃。
UDP数据报
伪首部12B,UDP首部8B,数据长度可变
UDP校验
Internet 校验码,为什么是叫Internet校验码?
因为在TCP、UDP中都用了这个
校验码计算 是哪两个相加-----整个数据报的所有按16bit成一个字,每个字相加
- 伪首部只有在计算检验和时才出现,伪首部仅仅是为了计算检验和,所以不向下传送也不向上递交。
- 17:封装UDP报文的IP数据报首部协议字段是17(表示为UDP协议)。
- UDP长度:UDP首部 8B + 数据部分长度(不包括伪首部)。
- 但是 !
- 错误检测不是100%可靠!
- 协议有可能漏掉一些错误,但很少
在发送端:
1.填上伪首部
2.全0填充检验和字段
3.全0填充数据部分(UDP数据报要看成许多4B的字串接起来)
4.伪首部+首部+数据部分采用二进制反码求和
5.把和求反码填入检验和字段
6.去掉伪首部,发送
在接收端:
1.填上伪首部
2.伪首部+首部+数据部分采用二进制反码求和
3.结果全为1则无差错,否则丢弃数据报/交给应用层附上出差错的警告。
校验和的计算步骤
- 1.把伪首部添加到UDP上;
- 2.计算初始时是需要将检验和字段添零的;
- 3.把所有位全部化成二进制
- 4.把所有16位的字相加,如果遇到进位,则将高于16字节的进位部分的值加到最低位上
- 5.将所有字相加得到的结果应该为一个16位的数,将该数取反则可以得到检验和checksum。
特殊:校验码计算为0时
- 如果检验和的计算结果为0,则存入的值为全1 (65535),这在二进制反码计算中是等效的。因为如果传送的检验和为0,说明发送端没有计算检验和。
- 如果发送端没有计算检验和而接收端检测到检验和有差错,那么UDP数据报就要被悄悄地丢弃, 不产生任何差错报文(当IP层检测到IP首部检验和有差错时也做同样处理)
例
- 如:累加和为,11111111 11111111
- 则,校验和为,00000000 00000000 ->写入的是 111111111 11111111
- 在接收方,累加和 + 校验和 = 11111111 11111111,全1,表明传输正确。
校验和:弱保护!
(注意:UDP和TCP使用16比特来计算校验和)
所有的1位错误都将被检测到,但是2位错误可能不被检测到(例如,如果第一个字节的最后一位变成了0,而第二个字节的最后一位变成1)。
5.3 TCP协议特点 和TCP报文段
TCP协议的特点
- TCP是面向连接(虚连接)的传输层协议。【打电话】
- 每一条TCP连接只能有两个端点,每一条TCP连接只能是点对点的。
- TCP提供可靠交付的服务,无差错、不丢失、不重复、按序到达。【可靠有序,不丢不重】
- TCP提供全双工通信。
- 发送缓存 按序到达但尚未被接受应用程序读取的数据&不按序到达的数据
- 接收缓存 准备发送的数据&已发送但尚未收到确认的数据
- TCP面向字节流: TCP把应用程序交下来的数据看成仅仅是一连串的无结构的字节流。
- 流:流入到进程或从 进程流出的字节序列
TCP报文段首部格式
- 序号:在一个TCP连接中传送的字节流中的每一个字节都按顺序编号,本字段表示本报文段所发送数据的第一个字节的序号。
- 确认号:期望收到对方下一个报文段的 第一个数据字节的序号。若确认号为N, 则证明到序号N-1为止的所有数据都已正 确收到。
- 数据偏移(首部长度):TCP报文段的 数据起始处距离TCP报文段的起始处有多远,以4B位单位,即1个数值是4B。
- 窗口:指的是发送本报文段的一方的接收窗口,即现在允许对方发送的数据量。
- 检验和:检验首部+数据,检验时要加 上12B伪首部,第四个字段为6。
- 紧急指针:URG=1时才有意义,指出 本报文段中紧急数据的字节数。
- 选项:最大报文段长度MSS、窗口扩 大、时间戳、选择确认…
6个控制位
- 紧急位URG: URG=1时,标明此报文段中有紧急数据,是高优先级的数据,应尽快传送,不用在缓存里排队,配合紧急指针字段使用。
- 复位RST: RST=1时,表明TCP连接中出现 重差错,必须释放连接,然后再重新建立传输链接。
- 确认位ACK: ACK=1时确认号有效,在连接建立后所有传送的报文段都必须把ACK置为1。
- 推送位PSH: PSH=1时,接收方尽快交付接收应用进程,不再等到缓存填满再向 上交付。
- 同步位SYN:SYN=1时,表明是一个连接请求/连接接受报文。**
- 终止位FIN: FIN=1时,表明此报文段发送方数据已发完,要求释放连接。
5.4 TCP 连接
三个阶段:
- 连接建立
- 数据传送
- 连接释放
TCP连接的建立采用客户服务器方式,主动发起连接建立的应用进程叫做客户,而被动等待连接建立的应用进程叫服务器。
TCP的连接建立:三 次 握 手
A:有件事不知当讲不当讲——客户机发送一个TCP连接请求报文
B:请讲——服务器回送一个TCP确认响应报文
A:好的!#\(%!#\)%——客户机向服务器发送一个包含“ HTTP请求”与“TCP确认”的报文
客户机中的TCP会用以下步骤与服务器中 的TCP建立一条TCP连接:
ROUND 1:
- 客户端发送连接请求报文段,无应用层数据。
- SYN=1,seq=x(随机)
ROUND 2:
- 服务器端为该TCP连接分配缓存和变量,并向客户端返回确认报文段,允许连接,无应用层数据。
- SYN=1,ACK=1,seq=y(随机),ack=x+1
ROUND 3:
- 客户端为该TCP连接分配缓存和变量,并向服务器端返回确认的确认,可以携带数据。
- SYN=0,ACK=1,seq=x+1,ack=y+1
SYN洪泛攻击
- SYN洪泛攻击发生在OSI第四层(传输层),这种方式利用TCP协议的特性,就是三次握手。
- 攻击者发送TCP SYN,SYN是TCP三次握手中的第一个数据包,而当服务器返回ACK后,该攻击者就不对 其进行再确认,那这个TCP连接就处于挂起状态,也就是所谓的半连接状态,也就是不发送第三次的握手。
- 服务器收不到 再确认的话,还会重复发送ACK给攻击者。这样更加会浪费服务器的资源。
- 攻击者就对服务器发送非常大量的这种TCP连接,由于每一个都没法完成三次握手,所以在服务器上,这些 TCP连接会因为挂起状态而消耗CPU和内存,最后服务器可能死机,就无法为正常用户提供服务了。
解决办法 SYN cookie
TCP的连接释放
参与一条TCP连接的两个进程中的任何一个都能终止该连接,连接结束后,主机中的“资源”(缓存和变量)将被 释放。
A:我说完了
B:好的,到我了,balabala
B:bye
A:OK,bye
ROUND 1:
- 客户端发送连接释放报文段,停止发送数据,主动 关闭TCP连接。
- FIN=1,seq=u
ROUND 2:
- 服务器端回送一个确认报文段,客户到服务器这个方向的连接就释放了——半关闭状态。
- ACK=1,seq=v,ack=u+1
ROUND 3:
- 服务器端发完数据,就发出连接释放报文段,主动关闭TCP连接。
- FIN=1,ACK=1,seq=w,ack=u+1
ROUND 4:
- 客户端回送一个确认报文段,再等到时间等待计时器设置的2MSL(最长报文段寿命,若不等待,将导致服务器B的连接一直不关闭)后,连接彻底关闭。
- ACK=1,seq=u+1,ack=w+1
TCP可靠传输
何谓可靠?
保证接收方进程从缓存区读出的字节流与发送方发出的字节流是完全一样的
传输层——使用TCP实现可靠传输
网络层——提供尽最大努力交付,不可靠传输
TCP实现可靠传输的机制
- 1.校验(与UDP校验一样, 增加伪首部)
- 2.序号
- 3.确认
- 4.重传
序号
并且要等到对方收到了123过后,A才会删除自己的123副本。
确认
这里即使得到了1、2、3、7、8,但是由于4、5、6还是没有抵达,TCP还惦记着的,故报文段首部确认号字段为4
重传
确认重传不分家,TCP的发送方在规定的时间内没有收到确认就要重传已发送的报文段
重传时间:TCP采用自适应算法,动态改变重传时间RTTS (加权平均往返时间)(若重传时间长,负载大,时间短,难以确定是否收到。)
冗余确认
冗余ACK(冗余确认)
每当比期望序号大的失序报文段到达时,发送一个冗余ACK,指明下一个期待字节的序号。
如:发送方已发送1,2,3,4,5报文段
- 接收方收到1,返回给1的确认(确认号为2的第一个字节)
- 接收方收到3,仍返回给1的确认(确认号为2的第一个字节)
- 接收方收到4,仍返回给1的确认(确认号为2的第一个字节)
- 接收方收到5,仍返回给1的确认(确认号为2的第一个字节)
- ==> 发送方收到3个对于报文段1的冗余ACK —— 认为2号报文段丢失,重传2号报文段
5.5 TCP流量控制&拥塞控制【重点】
流量控制:让发送方慢点,要让接收方来得及接收。
流量控制原理——滑动窗口机制
-
在通信过程中,接收方根据自己接收缓存的大小,动态地调整发送方的发送窗口大小。
-
即接收窗口rwnd (接收方 设置确认报文段的窗口字段来将rwnd通知给发送方)
-
发送方的发送窗口大小取值为 min{接收窗口rwnd,拥塞窗口cwnd}
例子
A向B发送数据,连接建立时,B告诉A:“我的rwnd=400(字节)”,设每一个报文段100B,报文段序号初始值为1。
- TCP为每一个连接设有一个持续计时器,只要TCP连接的一方收到对方的零窗口通知【rwnd=0】,就启动持续计时器。
- 若持续计时器设置的时间到期,就发送一个零窗口探测报文段。 接收方收到探测报文段时给出现在的窗口值。
- 若窗口仍然是0,那么发送方就重新设置持续计时器。
5.6 TCP拥塞控制
出现拥塞的条件: 对资源需求的总和 > 可用资源
拥塞控制: 防止过多的数据注入到网络中。 (防止网络性能变坏)
拥塞控制的四种算法
- 慢开始
- 拥塞避免
- 快重传
- 快恢复
假定:
1.数据单方向传送,而另一个方向只传送确认
⒉接收方总是有足够大的缓存空间,因而发送窗口大小取决于拥塞程度
发送窗口=Min{接收窗口rwnd,拥塞窗口cwnd}
接收窗口:接收方根据接受缓存设置的值,并告知给发送方,反映接收方容量。
拥塞窗口:发送方根据自己估算的网络拥塞程度而设置的窗口值,反映网络当前容量。
慢开始和拥塞避免
一个传输轮次: 发送了一批报文段并收到它们的确认的时间。
阶段
慢开始阶段:第n轮次,其拥塞窗口cwnd就是2^n【n是从开始那一刻算0起始,n++】
拥塞避免阶段:24/2=12得到新的ssthresh值,即网络拥塞时的最大窗口数量/2,得到新的最大值。
重复下一回合——
慢开始阶段
拥塞避免阶段
快重传和快恢复
慢开始阶段:第n轮次,其拥塞窗口cwnd就是2^n
快恢复:从新的ssthresh值开始,加法增大,cwnd++
拥塞避免阶段:24/2=12得到新的ssthresh值,
重复下一回合——
慢开始阶段
拥塞避免阶段
5.7 可靠数据传输原理
r d t——reliable data transmission
版本
- rdt1.0: 完全可靠信道上的可靠数据传输
- rdt2.0: 具有 bit 差错的信道
- rdt2.1: 发送方,处理含混不清的 ACK/NAKs
- rdt2.2: 一个无NAK的协议
- rdt3.0: 具有差错和丢失的信道
规则
- 发送方、接收方分离的 FSMs(模型罢了):
- 发送方发送数据到下层信道
- 接收方从下层信道接收数据
rdt1.0: 完全可靠信道上的可靠数据传输
- 在完美可靠的信道上
- 无 bit 差错
- 无分组丢失
操作
最简单——实际上所谓的不可靠的信道是,是完美的信道——没有报文段丢失、损坏、重复或重新排序的情况。
发件人只是发送,它完美地在另一端弹出(也许经过一些延迟)。
rdt2.0: 具有 bit 差错的信道
- 底层信道模型使分组中的比特可能受损
- 利用Internet校验和来检测比特差错
- 问题是:如何从错误中恢复?
注意:除非发送方以某种方式在接收方与发送方之间进行通信,否则发送方不知道接收方的“状态”(接收方是否正确收到了我的消息?)
操作
- 确认 acknowledgements (ACKs): 接收方明确告诉发送方,分组接收正确
- 否定确认 negative acknowledgements (NAKs): 接收方明确告诉发送方,分组接收出错。发送方收到NAK后,重发这个分组
rdt2.0 有一个致命缺陷
- 如果ACK / NAK损坏了怎么办?
- 发送方不知道接收方发生了什么!
- 不能只是重发:可能导致重复(冗余)
处理重复:
- 如果ACK / NAK损坏,发送方重传当前的分组
- 发送方给每个分组增加一个序号 (sequence number )
- 接收方丢弃(不交付)重复的分组
停-等协议 (stop and wait )
发送方发送一个分组,然后等待接收方响应。
发送方不就是着两个状态吗:等待上层的调用、发送后等待ACK或是NAK
一调用过后就组装,然后发送数据
然后进行等待,得到回应,根据回应,一旦是确认就进入下一步,如果是没收到的回复那就重发
rdt2.1: 发送方,处理含混不清的 ACK/NAKs
rdt2.1假设:
- 分组在传输过程中可能出错
- ACK 和 NAK也有可能出错,但不会丢失
- rdt2.1: 接收方,处理含混不清的 ACK/NAKs
操作
-
发送方:
- 序号 (seq) 添加到分组中,并且两个序号 (0, 1) 就足够了
- 必须检查收到的 ACK/NAK 是否已损坏
- 当前状态必须“记住”期望的分组应该是 0 还是 1
-
接收方:
- 必须检查是否接收到重复的分组
- 状态指示 0 或 1 是否是所期待的分组序号
- 注意:接收方并不知道它的上一个 ACK/NAK 是否被发送方正确收到
rdt2.2: 一个无NAK的协议
就像我们将看到的,TCP使用这种方法来消除 NAK。
rdt2.2假设:
- 报文在传输过程中可能出错
- ACK传输可能出错
- ACK可能丢失
- 与rdt2.1一样的功能,但仅使用 ACK
操作
- 不用 NAK,接收方对最后正确接收的分组发送 ACK
- 发送方收到重复 ACK 将导致和 NAK一样的处理:重传当前分组
- 接收方必须给出ACK号,发送方必须检查收到的ACK号
rdt3.0: 具有差错和丢失的信道
新假设:
- 下层信道也可能丢失分组(数据,ACK)
- 校验和, 序号, 确认, 重发 将会有帮助,但是不够
Q:人们如何处理对话中丢失的发送方到接收方的话语?
操作
- 发送方,为 ACK 等待“合理” 的时间 ,如果在这段时间内没有收到确认就重发
- 如果分组(或者ACK)只是延迟 (没有丢失):
- 重发将导致重复,但是使用序号已经处理了这个问题!
- 接受方必须指定被确认的报文序号
- 使用倒数计时器在“合理”的时间后中断
rdt3.0: 运行