运输层向上层【应用层】提供端到端的逻辑通信服务,即应用到应用的通信服务。只有两个主机之间的协议栈才会有传输层,网络核心部分中只用到下面的三层【网络层,数据链路层,物理层】
上述中逻辑通信的意思是:
运输层之间的通信好像是沿着水平方向传送数据,但事实上两个运输层之间没有水平方向的物理连接,需要按照虚线的方向多次传送。
如下图所示。
因特网(一般是TCP/IP网络)为上层提供两个不同的传输层协议。
TCP传输控制协议 | UDP用户数据报协议 | |
---|---|---|
可靠性 | 可靠 | 不可靠 |
连接性 | 面向连接 | 无连接 |
传输单位 | 报文段 | 用户数据报 |
效率 | 满 | 快 |
双工性 | 全双工 | 一对一,一对多,多对多 |
流量控制 | 滑动窗口 | 无 |
拥塞控制 | 满开始,拥塞避免,快重传,快恢复 | 无 |
优点 | 保证传输质量可靠 | 灵活、轻量、传输速度快 |
缺点 | 传输速度慢 | 不保证传输质量 |
适用场景 | 用于在传输层有必要实现可靠传输的情况 | 用于那些对高速传输和实时性有较高要求的通信或广播通信 |
使用UDP和TCP协议的各种网络应用如下所示
应用 | 应用层协议 | 运输层协议 |
---|---|---|
域名解析 | DNS | UDP |
文件传输 | TFTP | UDP |
IP地址配置 | DHCP | UDP |
网络管理 | SNMP | UDP |
远程文件服务器 | NFS | UDP |
多播 | IGMP | UDP |
电子邮件 | SMTP | TCP |
远程终端接入 | TELNET | TCP |
万维网 | HTTP | TCP |
文件传输 | FTP | TCP |
注: HTTP1.0和HTTP2.0使用TCP协议 HTTP3.0使用UDP协议
复用指同一个发送端主机中的多个应用层使用同一个运输层协议传输数据。
分用指在同一个接收端主机传输层剥去报文的首部之后将数据正确的交付给目的应用程序
复用和分用的前提是能够分辨同一个主机中不同的应用程序。在TCP/IP中,使用一种和操作系统无关的协议端口号。
端口号用16位(2个字节)来表示,能表示的最大范围是0~65535.
-
熟知端口
0~1023 由因特网赋号管理局负责分配给一些常用的应用。
部分端口如下
应用程序 FTP TELNET SMTP DNS TFTP HTTP SNMP SNMP(trap) 端口号 21 23 25 53 69 80 161 162 -
登记端口
1024~49151 可在IANA注册登记,防止重复使用。
-
动态端口
49152~65535 由系统动态生成
-
提供无连接服务
发送数据之前不需要建立连接。因此减少了传输开销,降低了传输时延。
-
最大努力交付
不保证传输质量,即不保证可靠交付。
-
无拥塞控制机制
出现网络拥塞不会使源主机的发送速率降低,对某些实时应用很重要。比如IP电话,视频会议等。
-
面向报文
应用层交给一个报文,UDP就会将其发送出去。如果过大,底部的网络层会将其分片,会降低效果,如果过小,则降低了网络层的传输效率。
-
支持一对一,一对多,多对多。
-
首部8字节,比TCP协议的20个字节少。
UDP的首部共8个字节
-
源端口,目标端口各2个字节。
-
长度:UDP用户数据报的长度
-
检验和:差错检测码,防止UDP用户数据报在传输中出错。
如何计算检验和:
1. 在UDP首部添加12个字节的伪首部,只是为了计算检验和,不向下传送也不向上递交。
- 将检验和字段置0
- 将伪首部,UDP首部,数据部分看成由许多16位的二进制,按二进制反码求和计算,将结果取反码写入检验和字段。
- 接收方将同样的多个16位二进制反码求和,如果无差错,则结果应是1.
关于伪首部
-
源IP与目标IP各占4字节
-
第三个字段固定0,占一个字节
-
第四个字段为协议号,当协议为TCP时,此字段是6.
-
第四个字段是UDP用户数据报的长度。
这样的检验和,既检查了UDP用户数据报信息,又检查了IP地址。
-
面向连接
在传输数据之前,会先建立连接。具体来说,数据收发双方的内存中都建立一个用于维护数据传输状态的对象,比如双方 IP 和端口是多少?现在发送了多少数据了?状态健康吗?传输速度如何?等。所以,连接是网络行为状态的记录。
-
一对一
建立连接之后,连接被通信两端的端点确定。
-
全双工
TCP 是一个双工协议,数据任何时候都可以双向传输。
-
可靠交付
由于发送数据之前建立了连接,并且接收端接收到数据之后会返回一个确认,所以TCP传输的数据是可以保证无差错,不丢失,不充分,有序到达的。
-
面向字节流
应用程序交给TCP的是大小不等的数据块,但是TCP会认为是一串无结构的字节流,TCP会取出特定大小的数据陆续写入TCP发送缓存中。
为什么要这么处理呢?
-
为了稳定性,一次发送的数据越多,出错的概率越大。
-
为了效率,网络中有时候存在着并行的路径,拆分数据包就能更好地利用这些并行的路径。
-
大量的应用频繁地通过网卡收发数据,这个时候,网卡只能一个一个处理应用的请求。当网卡忙不过来的时候,数据就需要排队,也就是将数据放入缓冲区。如果每个应用都随意发送很大的数据,可能导致其他应用实时性遭到破坏。
因此,TCP会按照应用交给的数据块进行拆包和封包处理。
-
-
拆包
数据经过拆分,然后传输,然后在目的地重组,俗称拆包。
-
封包
如果发往一个目的地的多个数据太小了,为了防止多次发送占用资源,TCP 协议有可能将它们合并成一个 TCP 段发送,在目的地再还原成多个数据,这个过程俗称粘包。
TCP报文段首部的前20个字节是固定的,后面有4N个字节是根据需要增加的选项。
各字段含义如下
-
源端口/目标端口
各占2字节,用于传输层的复用和分用。
-
序号
占4字节,在发送数据时,TCP会为每一个字节的数据都按顺序编号,该字段表示这个TCP报文段中数据部分的第一个字节的序号。
-
确认号
占4字节, 期望收到对方的下一个报文段的第一个字节的序号。
-
数据偏移
占4位。单位是4字节。因此,最大值是2^4=15 TCP Header 部分的长度是可变的,因此需要一个数值来描述数据从哪个字节开始。
也就是最大偏移为15*4=60个字节 即TCP首部的最大长度为60个字节。
-
保留
用于日后扩展能力。
-
标志位 各占1位
- URG 代表这是一个紧急数据,比如远程操作的时候,用户按下了 Ctrl+C,要求终止程序,这种请求需要紧急处理。
- 确认ACK 代表响应,所有的消息都必须有 ACK,这是 TCP 协议确保稳定性的一环。只有此字段为1时,首部的确认号才有意义。
- PSH 代表数据推送,也就是在传输数据的意思。出于效率的原因,TCP可能会延迟发送数据,这样可以一次处理多个数据。当此字段为1时,TCP不会等待,会立即发送。 现在TCP会根据情况自动设置此字段的值。不会交给应用处理。
- RST 重置位,当连接中断时,将此置1,表示需要重新连接。
- SYN 同步请求,也就是申请握手。用来建立一个连接。当SYN=1,ACK=0时,表示是一个连接请求。当SYN=1,ACK=1时,表示是一个接收方同意连接的响应。
-
窗口
占2字节。表示发送端的接收窗口的大小,用来控制对方发送的数据量。单位是字节。 计算机网络经常用接收方的窗口大小来控制自己的数据发送量。
-
检验和
2字节。和UDP一样,会加上伪首部然后计算。此时,伪首部中的协议字段应该是6.长度应该是TCP报文段的长度。
-
紧急指针
指向最后一个紧急数据的序号(Sequence Number)。它存在的原因是:有时候紧急数据是连续的很多个段,所以需要提前告诉接收方进行准备。
-
选项
Options 中存储了一些可选字段,比如MSS。表示发送方的缓存能接受的报文段的最大长度是MSS个字节。它是一个协商字段(Negotiate)。协议是双方都要遵循的标准,因此配置往往不能由单方决定,需要双方协商。过大,接收方会拒绝,并且会占用网络资源。过小那头部的数据占比会上升,会浪费传输资源,降低吞吐量。因此,MSS设置为不超过IP层分片的最大长度即可。
-
填充
因为 Options 的长度不固定,需要 Pading 进行对齐为整数字节。
-
TCP是面向字节的,会将应用层传递下来的报文传递下来的报文切分为报文段,然后看成是一个字节一个字节的字节流,将其用递增的序号编号,在连接开始时,就会确定这个序号的初始值。发送时,TCP报文段首部的ack字段就是期望接收到的字节的序号,也就是在这个序号之前的全部已经确认接收完毕。
-
滑动窗口的单位为字节。下图为滑动窗口的概念
发送缓存中分为已经发送并收到确认的报文段,滑动窗口部分,不允许发送的报文段。 滑动窗口内的为允许发送的报文段。
当收到报文的确认之后,滑动窗口向右滑动,直到滑动窗口的左侧正好包含确认序号的字节。 然后发送缓存就会将已经发送并确认的字节从缓存中移除,让接下来的数据使用。
在滑动窗口中,系统维护一个发送指针,每发送一个报文段,指针就向前移动一位。当移动到滑动窗口的最右部分,就无法继续发送,必须等待收到之前报文段的确认,滑动窗口向右滑动。
滑动窗口和发送缓存的关系
-
发送窗口只是发送缓存的一部分。已发送但未被确认数据大小<=发送窗口的大小。
-
发送缓存都应该是环形队列,并且是循环使用的。
-
当收到确认之后,滑动窗口左侧会按照确认号滑动到该字节,同时发送缓存也会将发送并成功收到确认的字节从缓存中删除。右侧会按照返回的确认首部中的窗口大小调整到对应的位置。
-
发送应用程序必须控制写入缓存的速率,不能太快,否则发送缓存会没有存放数据的空间。
滑动窗口和接收缓存的关系
-
滑动窗口只是接收缓存的一部分。
-
接收缓存都应该是环形队列,并且是循环使用的。
-
当收到按序到达的报文段时,滑动窗口左侧向右移动。右侧应该和接收缓存重合
-
当收到未按序到达时,会放入接收窗口中,等待接收正确序号,然后滑动窗口向右移动。
-
当收到的报文段根据首部的检验和计算出发送差错时,会丢弃。
-
当应用程序从接收缓存中读取到已经按序到达的数据之后,接收缓存会将这些数据删除,因为是一个环形队列,所以接收缓存和滑动窗口的右侧都会向右移动读取的字节数。
-
如果接收应用程序来不及读取收到的数据,接收缓存最终会被填满,使接收窗口减少到0
-
如果接收应用程序能够及时从接收缓存中读取收到的数据,接收窗口可以增大,但最大不能超过接收缓存的大小。
-
-
当TCP每发送一个报文段,就会在重传队列中缓存这个报文段的副本,并且设置一个计时器,当收到确认号后会将其从重传队列中移除。当计时器时间到了还没有收到确认,就会重新发送这个报文段。
超时重传的时间选择
-
时间过长:大量的丢失的报文段不会即使的重传,降低传输效率。
-
时间过短: 很多报文还没来的及传输,就会被认为丢失,引起不必要的重传,加大网络负荷。
-
时间计算:
超时重传的时间应该取决于当前报文段的往返时间(Round-trip Time RTT) 稍微长一些。
RTT的计算采用指数加权平均移动算法来计算,得出报文段的平均往返时间RTT(s)
新的RTT(s) = (1-α)*旧的RTT(s) + α * 上一个RTT(s) (典型的α取1/8)
超时重传时间(Retransmission Time-Out RTO )应当略大于上边的RTT(s)即可。
-
-
快速重传是对超时重传的一种补充
当超时重传的时间设置过长的时候,发送方并不会马上知道需要重新发送,因此,接收方在接收到后续的报文段而没有收到之前的某个报文段的时候,会将之前没收到的报文段的开始需要放入后续报文段的确认号中,当发送方一连接收到3个同样的确认号时,认为这个报文段已经丢失,立即重新发送。
-
如上快速重传中所示,后续的报文段接收方已经收到了,但是发送方并不知道,他们的确认中填写的是之前没有收到的报文段的序号,所以,这些已经收到的报文段会等超时之后再次发送,选择确认可以解决这个问题。通过报文段中的选项字段添加SACK字段,存放已经收到的报文段的字节开始序号和结束序号。
**接收窗口的大小可以用来控制 TCP 协议的流速。**这样,就可以避免发送方发送太快而接收方的接收缓存溢出的问题。
具体实现:
发送端的发送窗口在连接建立时由双方商定。但在通信的过程中,接收端可根据自己的资源情况,随时动态地调整对方的发送窗口上限值(可增大或减小)。发送方收到的确认中的窗口大小是接收方的滑动窗口大小。发送方的滑动窗口必须小于等于这个值。接收方根据自己的接收能力控制发送方的发送速率。因此,流量控制是一个速度匹配服务,可以保证发送方的发送速率和接收方的程序的读取速率保持一致。
这种由接收方来控制发送方的做法,在计算机网路中经常使用。
窗口探测
当应用程序读取速度过慢,导致接收缓存中全部均为按序到达需要读取时,接收窗口大小被挤压为0,此时,返回给发送方的确认首部窗口大小为0,则发送方的滑动窗口的右侧会和左侧重叠,发送方的滑动窗口也变为0。发送方会一直等下去。为避免发生这种死锁状态,发送方会周期性(默认为60s)的发送一个字节数据的窗口探测报文段,以便强制接收方返回即时的窗口大小。当此时发送方的接收窗口依然为0,则接收方会丢弃这个字节并重复以前的数据进行确认。如果此时窗口大小不为0,则收到这个窗口探测的一个字节的数据并返回发送方确认消息。
综上所述,TCP的流量控制协议实现了发送应用程序的发送速率和接收应用程序的接受速率的匹配。
-
具体步骤、
-
第一次握手
客户端向服务端发送一个连接请求,在请求头中的SYN为1,表示这是一个连接请求。seq=x,x为一个随机数,表示接下来发送的数据从此序号开始递增。即下一个报文的序号应该是X+1。
-
第二次握手
服务器收到客户端的连接请求之后,如果同意,则发回一个连接请求确认。在这个报文段首部中,SYN=1,ACK=1。表示这是一个连接请求确认报文。,seq=y,y也是一个随机数,表示下一个返回数据的报文的序号应该是y+1。ack=x+1,表示希望下一次收到的数据是x+1。
-
第三次握手
客户端收到服务器的连接请求确认报文段之后,还需要向服务器发送一个确认,此时,SYN=0,ACK=1,序号seq=x+1。确认号ack=y+1,表示希望收到服务器的下一个数据序号为y+1。
此时,连接已经建立。
为什么要进行三次握手呢?
为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误。
-
当采用两次握手
客户端发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。本来这是一个早已失效的报文段。但server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求。于是就向client发出确认报文段,同意建立连接。假设不采用“三次握手”,那么只要server发出确认,新的连接就建立了。由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送数据。但server却以为新的运输连接已经建立,并一直等待client发来数据。这样,server的很多资源就白白浪费掉了。
-
当采用三次握手 采用“三次握手”的办法可以防止上述现象发生。例如刚才那种情况,client不会向server的确认发出确认。server由于收不到确认,就知道client并没有要求建立连接。”。主要目的防止server端一直等待,浪费资源。
-
-
-
第一次挥手
当客户端的数据都传输完成后,客户端向服务端发出连接释放报文(当然数据没发完时也可以发送连接释放报文并停止发送数据),释放连接报文包含FIN标志位(FIN=1)、序列号seq=1101(100+1+1000,其中的1是建立连接时占的一个序列号)。需要注意的是客户端发出FIN报文段后只是不能发数据了,但是还可以正常收数据;另外FIN报文段即使不携带数据也要占据一个序列号。
-
第二次挥手
服务端收到客户端发的FIN报文后给客户端回复确认报文,确认报文包含ACK标志位(ACK=1)、确认号ack=1102(客户端FIN报文序列号1101+1)、序列号seq=2300(300+2000)。此时服务端处于关闭等待状态,而不是立马给客户端发FIN报文,这个状态还要持续一段时间,因为服务端可能还有数据没发完。
-
第三次挥手
服务端将最后数据(比如50个字节)发送完毕后就向客户端发出连接释放报文,报文包含FIN和ACK标志位(FIN=1,ACK=1)、确认号和第二次挥手一样ack=1102、序列号seq=2350(2300+50)。
-
第四次挥手
客户端收到服务端发的FIN报文后,向服务端发出确认报文,确认报文包含ACK标志位(ACK=1)、确认号ack=2351、序列号seq=1102。注意客户端发出确认报文后不是立马释放TCP连接,而是要经过2MSL(最长报文段寿命的2倍时长)后才释放TCP连接。而服务端一旦收到客户端发出的确认报文就会立马释放TCP连接,所以服务端结束TCP连接的时间要比客户端早一些。
-
每一个方框表示一个状态,箭头表示状态变迁,箭头上的文字表示引起状态变迁的原因。 绿色粗线表示客户端, 红色虚线表示服务器,红色细线表示非正常。
CLOSED:无连接是活动的或正在进行 LISTEN:服务器在等待进入呼叫 SYN_RECV:一个连接请求已经到达,等待确认 SYN_SENT:应用已经开始,打开一个连接 ESTABLISHED:正常数据传输状态 FIN_WAIT1:应用说它已经完成 FIN_WAIT2:另一边已同意释放 ITMED_WAIT:等待所有分组死掉 CLOSING:两边同时尝试关闭 TIME_WAIT:另一边已初始化一个释放 LAST_ACK:等待所有分组死掉
-
如果网络中的负载(load),即发送到网络中的分组数量,超过了网络的容量,即网络中能处理的分组数量,那么在网络中就会发生拥塞(congestion)。
-
所谓拥塞控制(congestion control)就是防止过多的数据注入到网络中,这样可以使网络中的路由器或链路不致过载。
-
开环控制方法就是在设计网络时事先将有关发生拥塞的因素考虑周到,力求网络在工作时不产生拥塞。
-
-
监测网络系统以便检测到拥塞在何时、何处发生。
-
将拥塞发生的信息传送到可采取行动的地方。
-
调整网络系统的运行以解决出现的问题。
-
如何检测网络的堵塞
-
丢包率
-
平均队列长度
-
超时重传分组数
-
平均分组时延
闭环控制的分类
-
显示反馈算法
从拥塞点向源点发送有关网络拥塞的显示反馈信息。比如ICMP中的源点抑制报文。
-
隐示反馈算法
根据对网络行为的观察(分组丢失和往返时间等),推测网络是否发生拥塞。
-
-
发送方根据所感知的网络拥塞的程度,来限制其向连接发送流量的速率。
-
只要网络没有出现拥塞,增大发送速率,以便把更多的分组发送出去。
-
如果网络出现拥塞,就减小发送速率,以减少注入到网络中的分组数。
发送方维持一个叫做拥塞窗口 cwnd (congestion window)的状态变量。
拥塞窗口的大小取决于网络的拥塞程度,并且动态地在变化。
发送方的发送窗口大小不能超过拥塞窗口。
接收窗口和拥塞窗口的区别
发送方的发送窗口的上限值应当取为接收方窗口 rwnd 和拥塞窗口 cwnd 这两个变量中较小的一个
即应按以下公式确定:
发送窗口的上限值 = Min [rwnd, cwnd]
当 rwnd < cwnd 时,是接收方的接收能力限制发送窗口的最大值。
当 cwnd < rwnd 时,则是网络的拥塞限制发送窗口的最大值。
-
重传计时器超时 严重
-
收到三个重复确认 不是很严重
-
在主机刚刚开始发送报文段时可先将拥塞窗口 cwnd 设置为一个最大报文段 MSS 的数值。即一个报文段。
-
在每收到一个对新的报文段的确认后,将拥塞窗口增加至多一个 报文段的数值。
-
用这样的方法逐步增大发送方的拥塞窗口 cwnd,可以使分组注入到网络的速率更加合理。
慢启动门限
为了防止拥塞窗口 cwnd 的增长引起网络拥塞,还需要另一个状态变量,即慢启动门限 ssthresh,其用法如下:
l当 cwnd < ssthresh 时,使用上述的慢启动算法。
l当 cwnd > ssthresh 时,停止使用慢启动算法而改用拥塞避免算法。
l当 cwnd = ssthresh 时,既可使用慢启动算法,也可使用拥塞避免算法。
-
拥塞避免算法使发送方的拥塞窗口 cwnd每经过一个往返时延 RTT 就增加一个MSS 的大小(而不管在时间 RTT 内收到了几个 ACK)。
-
拥塞窗口 cwnd 按线性规律缓慢增长,比慢启动算法的拥塞窗口增长速率缓慢得多。
当发送方收到连续三个重复的ACK时,说明拥塞情况并不严重,因此采用能更快恢复发送速率的算法
1. 当发送方收到连续三个重复的 ACK 时,就重新设置慢启动门限 ssthresh为原发送窗口一半
2.与慢启动不同之处是拥塞窗口 cwnd 不是设置为 1,而是设置为慢启动门限。
3.执行拥塞避免,使拥塞窗口按照线性增长
-
对于长时间的TCP连接,在稳定时的拥塞窗口大小呈锯齿状变化“加性增、乘性减”
-
发送方的平均发送速率始终保持在较接近网络可用带宽的位置(慢启动门限之上)。