物理层、数据链路层以及网络层它们共同解决了将主机通过异构网络互联起来所面临的的问题,实现了主机到主机的通信
但实际上在计算机网络中进行通信的真正实体是位于通信两端主机中的进程
如何为运行在不同主机上的应用进程提供直接的通信服务是运输层的任务,运输层协议又称端到端协议
这里的端口并不是物理上看得见、摸得着的物理端口,而是指用来区分不同应用进程的标识符。
- 运输层向高层用户屏蔽了下面网络核心的细节(如网络拓扑、所采用的路由选择协议,它使应用进程看见的就好像是在两个运输层实体之间有一条端到端的逻辑通信信道等)
- 根据应用需求的不同,因特网的运输层为应用层提供了两种不同的运输协议,即面向连接的TCP和无连接的UDP,这两种协议就是本章要讨论的主要内容。
运行在计算机上的进程使用进程标识符PID来标志。
为了使运行不同操作系统的计算机的应用进程之间能进行网络通信,必须使用统一的方法对TCP/IP体系的应用进程进行标识,即端口号。
为什么不能使用进程标识符PID来区分各进程?
因为因特网上的计算机并不是使用统一的操作系统,不同的操作系统使用不同格式的进程标识符
端口号只具有本地意义,即端口号只是为了标识本计算机应用层中的各进程,在因特网中,不同计算机中的相同的端口号是没有联系的
端口号使用16比特表示,取值范围0~65535
。
IANA
把这些端口号指派给了TCP/IP
体系中最重要的一些应用协议IANA
按照规定的手续登记,以防止重复。如Microsoft RDP
微软远程桌面使用的端口是3389
发送方的某些应用进程所发送的不同应用报文,在运输层使用UDP协议进行封装,这是UDP复用;若用TCP封装则称TCP复用
运输层使用端口号区分不同进程,不管使用何种协议封装的报文,在网络层都需要使用IP协议封装成IP数据报,这是IP复用
数据报中协议字段的值用来表名封装的是何种协议数据单元。
取值为6,表示封装的TCP用户数据报;
取值为17,表示封装的UDP用户数据报。
根据协议字段的值,将IP数据报封装的协议数据单元上交运输层的过程叫IP分用
同理,UDP根据端口号将数据交给应用进程叫做UDP分用;TCP根据端口号将数据交给应用进程叫做TCP分用
常用端口号
UDP 还有 OSPF 。
**举例:**在用户PC中使用网页浏览器来访问 Web 服务器的内容
①用户通过DNS找到域名对应IP地址
用户在网页浏览器的地址栏中输入Web服务器的域名,请求访问
用户PC中的DNS客户端进程会发送一个DNS查询请求报文
其内容为“域名 www.porttest.com 所对应的IP地址是什么?
DNS查询请求报文需要使用运输层的UDP协议,封装成UDP用户数据报,
填写UDP首部中的两个端口的数值。
源端口字:在短暂端口号49151~65535中挑选一个未被占用的,用来表示DNS客户端进程,例如49152。
目的端口字段的值设置为53,这是DNS服务器端进程所使用的熟知端口号。
之后,将UDP用户数据报封装在IP数据报中,通过以太网发送给DNS服务器。
DNS服务器收到该数据报,从中解封出UDP用户数据报,交付给本服务器中的DNS服务器端进程。
UDP首部中的目的端口号为53,这表明应将该UDP用户数据报的数据载荷部分,也就是DNS查询请求报文。
DNS服务器端进程解析DNS查询请求报文的内容,然后接其要求查找对应的IP地址。
找到对应IP地址后,使用UDP协议封装成UDP数据报,设置UDP首部的两个端口值。
源端口值和目的端口值。这个值和用户源进程的端口值是相反的。
将UDP数据报封装在IP数据报中,通过以太网给用户PC发送DNS响应报文, 内容为“域名www.porttest.com所对应的IP地址是192.168.0.3”。
用户把DNS响应报文交付给DNS客户端进程,解析完响应报文,就可知道域名对应的IP地址了。
②用户通过HTTP获得网页内容。
用户PC中的HTTP客户端进程向Web服务器发送HTTP请求报文
内容为“首页内容是什么?”
HTTP请求报文需要使用运输层的TCP协议封装成TCP报文段。
填写TCP首部中的两个端口值:源端口和目的端口。
HTTP进程的端口号一般是80,即目的端口。
Web服务器收到后根据目的端口号,把数据载荷部分(HTTP请求报文)交付给本服务器中的HTTP服务器端进程。
HTTP服务器端进程解析HTTP请求报文的内容,按其要求查找首页内容,给用户PC发送HTTP响应报文。
请求报文内容是获取对应的网页内容。
此处同①中UDP的端口号设置、报文段包装、客户端解析。
这两个运输层协议的使用频率仅次于网络层的IP协议。
UDP和TCP都支持全双工通信。
通信前,UDP不需要连接。TCP**面向连接(**三握手四挥手)
UDP 支持单播、多播、广播。TCP 只能通过三次握手单独建立连接,仅支持单播。
UDP 面向应用报文,TCP 面向字节流。
UDP 对应用进程交下来的报文既不合并也不拆分,而是保留这些报文的边界。
TCP 将字节流编号存储在发送缓存中,根据发送策略,将缓存分段发送。
对于TCP:
对于收到的数据,接收方一方面取出数据载荷部分存储在接收缓存中,一方面直接将接收缓存中的一些字节交付给应用进程。
接收方收到的数据块数可能与发送方发出的数据块数不一致,但是收发双方收发的字节流数目一致
比如发送方要发送10个字节,分五个字节一块,一共两块,但接收方接收字节是3.3.4,一共三块
所以是TCP不保证一次性传完,这就要求应用进程有处理这种乱序、多次传输后还能拼接完整的能力.
面向字节流是TCP提供可靠传输、流量控制、拥塞控制的基础。
UDP向上层提供无连接不可靠传输服务(适用于IP电话、视频会议等实时应用)
TCP向上层提供面向连接的可靠传输服务(适用于要求可靠传输的应用,例如文件传输)
IP数据包向上层提供的是无连接不可靠传输服务。
UDP 用户数据报首部仅仅 8 字节,而TCP 由于要实现可靠传输等,报文段首部最小20字节,最大60字节。
一般来说,我们希望数据传输能快一些,但如果发送方把数据发送得过快,接收方就可能来不及接收,这会造成数据的丢失
流量控制就是让发送方的发送速率不要太快,要让接收方来得及接收
利用滑动窗口实现流量控制
滑动窗口:发送窗口和接收窗口。
- ACK:标志位,取值1表示这是TCP确认保温段。
- ack:确认号字段,取值201表示序号201之前的数据已全部确接收。
- rwnd:窗口字段,取值300表示自己的接收窗口大小为300。
- seq:序号字段,取值1表示TCP报文段数据载荷的第一个字节的序号是1。
一些问题:
TCP为每个连接设置一个持续计时器。只要TCP连接的一方收到对方的零窗口通知,就启动持续计时器。持续计时器超时,发送方就会发送一个
1
字节大小的零窗口探测报文(仅携带一字节数据)。对方确认这个探测报文段时,通过确认报文给出自己的接受窗口值。
如果发送方窗口大小为
0
时,发送方重新启动持续计时器。超时后重新发送零窗口探测报文。如果不是0,也就是接收方主机此时的接收缓存又有了一些存储空间,调整了窗口,那么死锁局面就可以被打破了。
TCP规定,即使接收方主机接受窗口为0,也必须接受零窗口探测报文段,确认报文段以及携带紧急数据的报文段。
不会。因为零窗口探测报文也有重传计数器,具备超时重传机制。
在某段时间,若对网络中某一资源的需求超过了该资源所能提供的可用部分,网络性能就要变坏,这种情况叫做拥塞(congestion)
在计算机网络中的链路容量(即带宽)、交换结点中的缓存和处理机等,都是网络的资源。
若出现拥塞而不进行控制,整个网络的吞吐量将随输入负荷的增大而下降
理想拥塞控制的网络:在吞吐量达到饱和之前,网络吞吐量应等于所输入的负载。故吞吐量曲线是45度的斜线。但当输入负载超过某一限度时,由于网络资源受限,吞吐量就不再增长而保持水平线。也就是吞吐量达到饱和。这就表明输入的负载中有一部分损失到了。例如输入到网络中的某些分组被某个结点丢弃了。
即便如此,网络的吞吐量仍然维持在其所能达到的最大值。
无拥塞控制的网络,输入到达一定程度会轻度拥塞,吞吐量增长变慢。严重拥塞,吞吐量甚至会不增反降,直到0。
实际的拥塞控制应该尽量接远理想的拥塞控制曲线。
下面介绍拥塞控制的四种算法:
为方便分析,下面对四种算法的描述进行了条件假设:
- 数据是单方向传送,而另一个方向只传送确认。
- 接收方总是有足够大的缓存空间,因而发送方发送窗口的大小由网络的拥塞程度来决定
- 以最大报文段MSS的个数为讨论问题的单位,而不是以字节为单位。
拥塞窗口cwnd
的维护原则:只要网络没有出现拥塞,拥塞窗口就再增大一些(确认报文段窗口大小),但只要网络出现拥塞,拥塞窗口就减少一些swnd=cwnd
cwnd < ssthresh
时,使用慢开始算法cwnd > ssthresh
时,停止使用慢开始算法而改用拥塞避免算法cwnd = ssthresh
时,既可使用慢开始算法,也可以使用拥塞避免算法1. 慢开始和拥塞避免
cwnd < ssthresh
时,拥塞窗口从1开始,根据应答报文大小来扩大拥塞窗口,也就是cwnd = cwnd * 2。
如发送方窗口
2
,应答大小2
,则下次发送大小为4
cwnd = ssthresh
时,拥塞窗口每次只扩大1,而不是向慢开始那样根据发送方的返回窗口进行增加。
超时重传:当窗口增加到一定大小,发送方发送的报文出现了超时重传,则判断网络可能出现了拥塞,此时:①将拥塞窗口初始化为1,②慢开始门限ssthresh设置为发生拥塞时窗口大小的一半
"拥塞避免"并非指完全能够避免拥塞,而是指在拥塞避免阶段将拥塞窗口控制为按线性规律增长,使网络比较不容易出现拥塞
2. 快重传和快恢复
慢开始和拥塞避免算法是1988年提出的TCP拥塞控制算法(TCP Tahoe版本)
1990年又增加了两个新的拥塞控制算法(改进TCP的性能),这就是快重传和快恢复(TCP Reno版本)
- 有时,个别报文段会在网络中丢失,但实际上网络并未发生拥塞。
- 这将导致发送方超时重传,并误认为网络发生了拥塞。
- 发送方把拥塞窗口cwnd又设置为最小值1,并错误地启动慢开始算法,因而降低了传输效率。
快重传是使发送方尽快进行重传,而不是等待超时重传计时器超时再重传
20%
发送方一旦收到3
个重复确认,就知道现在只是丢失了个别报文段。也是不启动慢开始算法,而执行快恢复算法
发送方将慢开始门限ssthresh值和拥塞窗口cwnd值调整为当前窗口的一半,开始执行拥塞避免算法
发送窗口不用一下子回到 1 了。
也有的快恢复实现是把快恢复开始时的拥塞窗口cwnd
值再增大一些,即等于新的ssthresh+3
3
个重复的确认,就表明有3
个数据报文段已经离开了网络3
个报文段。因此可以适当把拥塞窗口扩大些超时重传时间 RTO的值:
所以正常情况下,超时重传时间应该设为略大于往返时间。
但是,TCP下层是复杂的互联网环境,由于各区域的速率可能不一致,每个IP数据报的转发路由也可能不同。
因此将超时重传时间设置为一个固定值是行不通的
所以只能利用每次测量得到的RTT
样本,计算加权平均往返时间 RTTs(又称平滑的往返时间)
显然,超时重传时间RTO应略大于加权平均往返时间RTTs
在上图式子中,0≤ α< I :
- 若 α 很接近于0,则新RTT样本对RTT的影响不大;
- 若 α 很接近于1,则新RTT样本对RTT的影响较大。
已成为建议标准的RFC6298推荐的α 值为1/8,即0.125 。
用这种方法得出的加权平均往返时间RTTS就比测量出的RTT值更加平滑。
针对出现超时重传时无法测准往返时间RTT的问题,有以下解决方法
在计算加权平均往返时间RTTs时,只要报文段重传了,就不采用其往返时间RTT
样本。
也就是出现重传时,不重新计算RTTs,进而超时重传时间RTO也不会重新计算。
此方法的漏洞如下:如果报文段时延突然增大很多,并且之后很长一段时间都会保持这种时延。因此在原来得出的重传时间内,不会收到确认报文段,于是重传。根据上述算法,每次重传后,发送方都不会收到确认,但重传时间永远不会更新,发送方永远要重传,无外力作用,此过程永远不会结束,这就造成了死锁。
修正方法:报文段每重传一次,就把超时重传时间RTO增大一些,典型的做法是将RTO的值取为旧RTO的2倍
传输时滑动窗口移动的不同情况:
向后收缩、前沿移动的情况,TCP强烈不建议出现。
因为很可能发送方在收到这个通知之前,就已经发送了窗口中的许多数据,现在又要收缩窗口,不让发送这些数据,就会产生错误。
如何描述发送窗口的状态?
使用三个指针P1,P2,P3分别指向相应的字节序号
小于P1的是已发送并已收到确认的部分;
大于等于P3的是不允许发送的部分;
P3-P1=发送窗口的尺寸;
P2-P1=已发送但尚未收到确认的字节数;
P3-P2=允许发送但当前尚未发送的字节数(又称为可用窗口或有效窗口)
虽然发送方的发送窗口是根据接收方的接收窗口设置的,但在同一时刻,发送方的发送窗口并不总是和接收方的接收窗口一样大。
对于**不按序到达的数据应如何处理,**TCP并无明确规定。
如果接收方把不按序到达的数据一律丢弃,那么接收窗口的管理将会比较简单,但这样做不利于对网络资源的利用。因为发送方会重复传送较多的数据。
TCP通常对不按序到达的数据是先临时存放在接收窗口中,等到字节流中所缺少的字节收到后,再按序交付上层的应用进程。
当缺少字节还未收到时,只能对已到达的数据进行确认,而不滑动窗口。这意味着接收方发送的确认序号仍然是缺少字节的最小序号。
TCP要求接收方必须有累积确认和捎带确认机制,这样可以减小传输开销。接收方可以在合适的时候发送确认,也可以在自己有数据要发送时把确认信息顺便捎带上。
接收方不应过分推迟发送确认,否则会导致发送方不必要的超时重传,这反而浪费了网络的资源。
TCP标准规定,确认推迟的时间不应超过0.5秒。若收到一连串具有最大长度的报文段,则必须每隔一个报文段就发送一个确认[RFC 1122]。
捎带确认实际上并不经常发生,因为大多数应用程序很少同时在两个方向向TCP服务器进程发送TCP连接请求报文段上发送数据。
TCP的通信是全双工通信。通信中的每一方都在发送和接收报文段。因此,每一方都有自己的发送窗口和接收窗口。在谈到这些窗口时,一定要弄清楚是哪一方的窗口。
TCP
的运输连接管理就是使运输连接的建立和释放都能正常地进行。
TCP的连接建立要解决以下三个问题:
建立过程:
最初,两端的TCP进程都处于关团状态。
一开始,TCP服务器进程首先创建传输控制块,用来存储TCP连接中的一些重要信息。
例如,TCP连接表,指向发送和接收缓存的指针,指向重传队列的指针,当前的发送和接收序号。
此时,TCP服务器进程就进入监听状态,等待TCP客户进程的连接请求。
对于TCP服务器,TCP服务器进程是被动等待来自TCP客户进程的连接请求,而不是主动发起。因此称为被动打开连接。
对于TCP客户,由于TCP连接建立是由TCP客户主动发起的,因此称为主动打开连接。
TCP客户进程也是首先创建传输控制块。然后,在打算建立TCP连接时,并进入同步已发送状态。
进入“三报文握手”
SYN
为1
:同步位,表明这是一个TCP连接请求报文段。
该报文段不能携带数据,但会消耗一个序列号seq
ACK=1
:确认位,代表这是普通确认报文段,ack=x+1表示这是对报文段序列号seq=x的确认
ack=x+1
:这是对TCP客户进程所选择的初始序号的确认。
该报文段同样不能携带数据。同样会消耗一个序列号seq
seq
:序号字段 ,被设置了一个初始值x,作为TCP客户/服务器进程所选择的初始序号。
通信结束后,TCP通信双方都可以释放连接。现在TCP客户进程和TCP服务器进程都处于连接已建立状态。
假设使用TCP客户进程的应用进程通知其主动关团TCP连接,TCP客户进程会发送TCP连接释放报文段,并进入终止等待1状态。
FIN
:终止位
ACK
:确认位
上面两个位都为1,表明这是一个TCP连接释放报文段。
TCP规定终止位
FIN
等于1的报文段即使不携带数据,也要消耗掉一个序号。
seq
:序号字段。
ack
:它等于TCP客户选程之前已收到的、数据的最后一个字节的序号加1.
TCP服务器进程收到TCP连接释放报文段后,会发送一个普通的TCP确认报文段并进入关闭等待状态。
TCP客户进程在发送完最后一个确认报文段后,必须进入时间等待状态,2MSL后才进入关闭状态。因为要防止发给服务器的确认报文丢失。
客户端发起关闭请求,一去一回后进入半关闭状态【客户端不再发送数据,服务端可能还会发】
服务器将自己剩余的数据发送完后也发送一个关闭请求,接着客户端给予回应后服务器关闭,客户机则要等到一段时间后完全关闭。
问题:TCP客户进程在发送完最后一个确认报文段后,为什么不直接进入关闭状态,而是要进入时间等待状态,2MSL后才进入关闭状态?
回答:
因为这必然会造成TCP服务器进程反复重传TCP连接释放报文段,并一直处于最后确认状态而无法进入关闭状态。
时间等待状态以及处于该状态
2MSL
时长,可确保TCP服务器进程可以收到最后一个TCP确认报文段而进入关闭状态。另外,TCP客户进程在发送完最后一个TCP确认报文段后,再经过
2MSL
时长,就可以使本次连接持续时间肉所产生的所有报文段都网络中消失。这样就可以使下一个新的TCP连接中,不会出现旧连接中的报文段。
TCP中保活计时器的作用:
源端口:占16
比特,写入源端口号,用来标识发送该TCP报文段的应用进程
目的端口:占16
比特,写入目的端口号,用来标识接收该TCP报文段的应用进程
序号:占32
比特,取值范围[ 0 , 232 ? 1 ] ,序号增加到最后一个后,下一个序号就又回到0
。
作用是指出本TCP报文段数据载荷的第一个字节的序号
确认标志位ACK:取值为1
时确认号字段才有效,为0
时确认号字段无效
确认号:占32
比特,取值范围[ 0 , 2 32 ?1 ] ,序号增加到最后一个后,下一个序号就又回到0
。
可理解为若确认号=n,则表明到序号n-1为止的所有数据都已正确接收,期望接收序号为n的数据
数据偏移:占4
比特,并以4字节为单位
用来指出
TCP
报文段的数据载荷部分的起始处距离TCP
报文段的起始处。这个字段实际上是指出TCP报文段的首部长度
首部固定长度为20字节,因此数据偏移字段的最小值(0101)2;首部最大长度为60字节,因此数据偏移字段最大值为(1111)2
保留字段:占6比特,保留为今后使用,但是目前应置为0
窗口:占16比特,以字节为单位。指出发送本报文段一方的接收窗口
窗口值作为接收方让发送方设置其发送窗口的依据,这是以接收方的接收能力来控制发送方的发送能力,称为流量控制
检验和:占16比特,检测范围包括TCP报文段的首部和数据载荷两部分
在计算校验和时,要在TCP
报文段的前面加上12
字节的伪首部
同步标志位SYN:在TCP
连接建立时用来同步序号
终止标志位FIN:用来释放TCP
连接
复位标志位RST:用来复位TCP
连接
当RST=1
时,表明TCP
连接出现了异常,必须释放连接,然后再重新建立连接;RST
置1
还用来拒绝一个非法的报文段或拒绝打开一个TCP
连接
推送标志位PSH:接收方的TCP
收到该标志位为1的报文段会尽快上交应用进程,而不必等到接收缓存都填满后再向上交付
紧急标志位URG:取值为1时紧急指针字段有效;取值为0
时紧急指针字段无效。
紧急指针:占16
比特,以字节为单位,用来指明紧急数据的长度
当发送方有紧急数据时,可将紧急数据插队到发送缓存的最前面,并立刻封装到一个TCP
报文段中进行发送。紧急指针会指出本报文段数据载荷部分包含了多长的紧急数据,紧急数据之后是普通数据
选项:增加选项可以增加TCP
的功能
TCP
报文段数据载荷部分的最大长度RTT
PAWS
填充:由于选项长度可变,因此使用填充来保证报文段首部能被4整除