从网络层来说,通信的两端是两台主机,但通信的真正端点并不是主机而是主机中的进程,端到端之间的通信指的是应用进程之间的通信。
网络层为主机之间提供逻辑通信,而运输层为应用进程之间提供端到端的逻辑通信,逻辑通信指再应用进程眼中,看起来两个运输层实体之间存在端到端的逻辑信道,但实际上是运输层向高层用户屏蔽了下面网络核心的细节,数据的传送还是要经过多个层次的。
根据应用程序的不同需求,运输层需要两种不同的运输协议,面向连接的TCP和无连接的UDP
1 UDP
UDP: User Datagram Protocol, 用户数据报协议
UDP在传送数据之前不需要建立连接。远地主机的运输层收到UDP报文之后也不需要给出确认。虽然UDP不提供可靠交付,但在某些情况下UDP仍然是一种最有效的工作方式。
UDP的主要特点如下:
- UDP是无连接的,发送数据之前不需要建立连接,发送数据结束后自然也没有连接的释放,减少了开销和发送数据之前的时延
- UDP尽最大努力交付,不保证可靠交付,主机也不需要维持复杂的连接状态表
- UDP是面向报文的,应用程序给UDP交付多长的报文,UDP就在该报文的基础上添加UDP首都然后交付给IP层,不会合并也不会拆分,如果太长IP层会需要分片,如果太短IP层增加的首部会显得过长,两者都会降低IP层的效率
- UDP没有拥塞控制,网络拥塞不会让源主机的发送速率降低,对于实时应用(IP电话、实时视频会议)很重要。这些应用通常要以恒定的速率发送数据,允许网络拥塞时丢失一些数据,但不允许数据存在太大的时间延迟
- UDP支持一对一、一对多、多对一和多对多的交互通信
- UDP首部开销小,只有8个字节,源端口、目的端口、长度、检验和各自占据两个字节
2 TCP
TCP:Transmission Control Protocol传输控制协议
TCP提供面向连接的服务,在传送数据之前必须先建立连接,数据传送结束后要释放连接。TCP不提供广播或者多播服务。由于TCP要提供可靠的、面向连接的运输服务,因此不可避免地增加了许多开销,比如确认、流量控制、计时器以及连接管理等。这不仅使协议数据单元首部增大很多,还要占用许多的处理机资源
TCP的主要特点如下:
- TCP是面向连接的运输层协议。应用程序在使用TCP协议之前,需要建立TCP连接,传输数据完毕之后,需要释放TCP连接
- 每一条TCP连接只能有2个端点,每条TCP连接只能是点对点的(一对一)
- TCP提供可靠交付的服务。通过TCP连接传送的数据,无差错、不丢失、不重复,并且按序到达
- TCP提供全双工通信。TCP连接允许通信双方的应用进程在任何时候都能发送数据。TCP连接的两端都设置了发送缓存和接收缓存据。发送时应用程序将数据传送到TCP的缓存后,就可以做自己的事,TCP在合适的时候把数据发送出去;接收时TCP把接收到的数据放入缓存,上层应用进程在合适的时间读取缓存中的数据
- 面向字节流。应用程序和TCP交互是一次一个数据块(大小不等),TCP把这些数据块看作一连串无结构字节流,TCP不保证收到的数据块的和发送的数据块具有大小对应关系,TCP有可能重新划分大小,但是对方收到的字节流和发送方应用程序发出的字节流完全一样。TCP不关心应用程序一次将多少缓存发送到TCP的缓存当中,而是根据对方给出的窗口值和当前网络拥塞程度决定当前一个报文段包含多少个字节,如果应用程序缓存到TCP的数据块太长,TCP可以把它划分地短一些再传送,如果应用进程一次缓存的数据块太短,TCP也可以积累有足够多的字节后再组成报文段发送出去。
2.1 TCP的可靠传输工作原理
2.1.1 停止等待协议
注意,这里说停止等待协议是在计算机网络发展初期的数据链路层的协议,这里提到是抛砖引玉,在运输层的可靠传输协议要复杂很多。
每发送完一个分组之后就停止发送,等待对方的确认,收到确认后再发送下一个分组。这里的分组指传送的数据单元,用于讨论可靠传输原理而不考虑数据在哪一个层级。
现假设A为发送方,B为接收方。A只要超过一段时间没有收到确认,就认为刚刚发送的分组丢失了,然后会重新发送前面发送过的分组,称为超时重传。
- A发送一个分组后必须保存已经发送的分组的副本,用于重传的时候使用,在收到确认后删除副本
- 分组和确认都需要编号,用于确认哪个分组收到了确认,哪个分组没有收到确认
- 超时重传的时间要比数据在分组当中传送的平均往返速度更长一些。如果时间设置过长,通信的效率会很低,如果时间设置过短,会引起不必要的重传
ARQ:自动重传请求(Automatic Repeat reQuest),重传的请求是自动进行的,不需要请求发送方重传某个出错的分组,具体如下
在A设置的超时重传的时间内没有收到确认,无法得知是否是自己发送的分组出错、丢失,或者是B发送的确认丢失,因此A在超时重传计时器过期后就要重传分组。
对于B来说,如果此时又收到了A重传的分组(A发送的分组B收到了,但B的确认丢失了A没有收到,A重传分组),B会有两个动作:
- 丢弃该分组并不向上层交付
- 向A重新发送确认。B收到了并且确认了是一码事,既然A重传了,就代表A没有收到确认,B收到重传的分组就有必要重新确认
对于A来说,如果收到B对于同一分组的重复确认(A发送的分组B收到了,但B的确认滞留了A没有收到,A重传分组,B再次确认,B滞留的确认到达A),A会直接丢弃该确认
如果A总是重传分组但收不到确认,那么就认为通信线路差到不能进行通信
2.1.2 连续ARQ协议和滑动窗口协议
信道利用率的计算
- TD:A发送一个分组用到的时间
- 假定B收到A发送的分组,处理时间忽略不计
- TA: B发送对于A的分组的确认花费的时间,TA往往远远低于TD
- 假定A收到B的确认后的处理时间忽略不计
- RTT:一个往返耗费的时间 很容易得到A这边处理一个分组的发送信道利用率为 TD / (TD + TA + RTT),但RTT远远大于TD的时候,信道利用率就会特别低,所以我们会想到,能不能在A等待确认的时候做一些别的事情,于是发送方抛弃了低效率的停止等待协议,转而使用流水线传输的方式。
滑动窗口
- 发送窗口:位于发送窗口当中的数据可以连续发送出去,不需要等待对方的确认
- 发送窗口的组成
- 已经发送但是没有收到确认的数据
- 允许发送但是尚未发送的数据(可用窗口)
- 发送窗口的移动
- 发送窗口前沿不动
- 没有收到新的确认
- 收到了新的确认但对方通知窗口缩小了
- 发送窗口前沿向前(向右)移动:收到新的确认
- 发送窗口前沿后移:TCP标准强烈不赞成这样做,很可能对方收到这个通知以前就已经发送了窗口中的许多数据,收缩窗口不让发送这些数据会产生一些错误
- 发送窗口前沿不动
- 发送窗口的组成
- 接收窗口:用于接收A发送的分组
- 发送缓存:存放应用程序传送给发送方TCP准备的数据和TCP已经发送但是还没有收到确认的数据
- 接收缓存:存放按序到达的、但尚未被接收应用程序读取的数据和未按序到达的数据
- 累计确认:接收方不必针对收到的分组逐个确认,而是收到几个分组之后对按序到达的最后一个分组发送确认。表示这个分组以及这个分组之前都收到了。如果只收到部分,那么只确认连续的部分,滑动窗口进行回退N的操作,表示N个分组需要重新发送
注意:
- 当发送窗口的可用窗口大小为0时,A需要停止发送,超过一段时间过后A还是没有收到来自B的任何确认,A只能认为这些全部丢失了,需要全部重传,直到收到B的确认
- A的发送窗口根据B的接收窗口设置,A的发送窗口不能大于B的接收窗口,但同一时刻A的发送窗口不一定总是和B的接收窗口一样大,因为网络传输窗口值还需要经历一定的时间滞后,发送方的窗口还可能受网络拥塞影响而减小
- 对于不按序到达的数据,如果直接丢弃,虽然很省事但是对网络资源的利用不利,会造成数据重复发送多次;一般先临时存放到接收窗口当中,等到缺少的字节收到后再交付给上层应用
- 累计确认不是过分推迟确认,否则会导致发送方不必要的重传,确认推迟的时间一般不应该超过5s
2.1.3 TCP流量控制
流量控制指的是让发送方的发送速率不要太快,要让接收方来得及接收
TCP的接收方在发送确认报文段时,会带上自己的接收窗口(rwnd)的大小,让发送方改变发送的速度,通过接收窗口大小和确认号,发送方能清楚地知道自己应该发送多少数据,发送哪些数据
如果B向A发送的rwnd=0,一段时间后rwnd=任意值的报文丢失,此时会有A等待B告知可以发送数据,B等待A发送数据到其窗口,形成互相等待的死锁。为了解决这个情况,TCP每一个连接都设有一个持续计时器,只要TCP连接的一方收到了对方的零窗口通知,就启动持续计时器。时间到了后会向接收方发送一个零窗口的探测报文段,对方确认这个报文段时给出窗口值,如果还是0那么计时器重置。这样就确保不会有上述死锁的僵局
2.1.4 TCP的拥塞控制
网络资源: 计算机网络中的贷款,交换节点中的缓存和处理机等,都是网络的资源
拥塞:在某个时间,若对网络中的某一资源的需求超过了该网络资源所能提供的可用部分,网络的性能就要变坏,这种情况叫做拥塞
拥塞控制与流量控制
- 拥塞控制:防止过多的数据注入的网络中,这样可以使网络中的路由或者链路不至于过载。拥塞控制是一个全局性的过程,涉及到所有的主机,所有的路由器,以及与降低网络传输性能相关的所有因素
- 流量控制 指的是点对点通信量的控制,是一个端到端的问题(接收端控制发送端),流量控制要做的就是抑制发送端发送数据的速率,以便使接收端来得及接收
拥塞控制相关概念引入
- cwnd: 拥塞窗口,大小取绝于网络的拥塞程序,发送方让自己的发送窗口等于拥塞窗口
- ssthresh: 慢开始门限,为了防止cwnd增长过大引起网络拥塞
- 判断网络拥塞的依据是是否出现了超时,网络状况不好时,路由器会丢弃分组,发送方会没有按时收到确认报文,出现超时,可以猜想是网络拥塞。现在通信线路的传输质量一般都很好,传输出现差错而丢失分组的概率是非常低的。
拥塞控制的算法
-
慢开始: cwnd < ssthresh时,由小到大逐渐增大发送窗口,即由小到大逐渐增大拥塞窗口。cwnd的初始值是规定的2-4个最大报文段SMSS的数值,之后每次的增加量 = min(N,SMSS),N代表原先未被确认的被刚收到的报文确认的字节数。假设一开始cwnd = 1,每次都确认没有丢失,增加量就是1,2,4,8,16,...,遭遇网路拥塞会重新回到慢开始,cwnd也会回到初始值
-
拥塞避免:cwnd > ssthresh时,停止使用慢开始算法,改用拥塞避免算法,让拥塞窗口缓慢地增大,加法增大,每经过一个往返时间 cwnd + 1
-
快重传:让发送方尽早知道个别报文段的丢失,而不会误以为网络发生了拥塞,导致回到慢开始。一旦有一个报文段丢失,收到失序的其他报文段,接收方向发送方确认丢失的报文段的前一个报文段(确认号是已经收到的字节的序号 + 1,表示这个序号之前都已经收到,希望下一个报文段的序号是 已经收到的+1),当发送方一连收到3个重复的确认,就知道接收方确实没有收到丢失的报文段,就会重新发送
-
快恢复:发送方收到3个重复的确认,知道不是网络拥塞,不会慢开始,而是乘法减小,把sstresh设置为当前的cwnd的一半,cwnd变为改变后的sstresh,之后执行拥塞避免算法(加法增大)
2.2 TCP连接的建立和释放(3报文握手和4报文挥手)
具体可以参考我之前写的当输入网址后回车发生了什么
简单说明如下:
- 三报文握手:
- A向B发送建立连接请求
- B向A确认收到其连接建立请求
- A向B确认收到B的确认
- 四报文挥手:
-
A向B发出终止连接的报文请求,之后不再向B发送数据
-
B向A确认收到A的终止报文请求,B将剩余数据发送给A
-
B所有数据发送完毕,B向A发出终止连接的报文请求,表示自己没有数据要发送了
-
A收到B的终止连接的报文请求,向B确认自己收到了B的终止连接的报文请求,A在这个确认发送后等待一段时间自动关闭,B在收到这个确认后直接进入关闭状态
-
3 总结
3.1 TCP和UDP的区别
- UDP是无连接的,不需要用到套接字;而TCP是面向连接的,会依靠套接字建立一条全双工的逻辑信道,使用前建立连接,使用后释放连接
- UDP是面向报文的,上面传下的包装一下就往下发,把大小调整·交给了IP层;而TCP是面向字节流的,对于上面交付的几个数据块看作一个字节流来处理,重新划分大小,对面收到处理后也能得到同样的字节流
- UDP不保证可靠传输,尽最大努力交付,TCP提供可靠交付的服务,无差错、不丢失、不重复且按序到达
- UDP支持一对一、一对多、多对一、多对多,TCP只能是一对一
- UDP要求快,UDP适用于不过分要求质量(允许丢失部分报文),但要求实时,比如视频、语音,TCP要求准,TCP适用于整个数据要准确无误的送达给对方,比如HTTP,HTTPS,FTP
3.2 TCP的可靠运输靠的是什么
-
连续自动重传ARQ协议和滑动窗口
-
流量控制
-
拥塞控制(慢开始、拥塞避免、快重传、快恢复)