TCP&UDP详解

概述

网络协议栈一般分为5层,从下到上依次为:物理层,数据链路层,网络层,运输层,应用层。TCP和UDP都是运输层的协议,IP协议能把源主机A发送出去的分组,按照首部中的目的地址送交到目的主机B,简单的说,IP层通信的两端是主机和主机。但是真正通信的不是主机而是主机上的应用进程。通常一台主机有多个应用进程和另一台主机的多个应用进程之间通信。TCP和UDP协议就是来满足这种需求的。

应用层的所有应用进程都可以通过运输层再传输到IP层,这就是复用。运输层从IP层收到发送给各个应用进程的数据后,必须分别交付各指明的应用进程,这就是分用。显然给每个应用进程赋予一个非常明确的标志是至关重要的。解决这个问题的方法是在运输层使用协议端口号,即端口。将一个应用进程绑定到一个端口,只要把所传送的报文交到目的主机的某个端口,剩下的工作就由TCP或UDP来完成。
TCP/IP的运输层用一个16位(65535)的端口号来表示端口。也就是说,如果想实现应用进程之间的通信不仅要知道对方的IP地址,还要知道其对应的端口号。运输层的端口号分为以下两类:

  1. 服务器端使用的端口号
    1.1 熟知端口号(系统端口号) 0~1023
    1.2 登记端口号 1024~49151
  2. 客户端使用的端口号 49152~65535,因为只在客户进程运行时才动态选择,通信结束后,刚才用的客户端口号就不复存在,因此也称为短暂端口号

UDP

  • UDP是无连接的,也就是说在发送数据前不需要建立连接,结束时也没有连接要释放,因此减少了开销和发送数据之前的时延。
  • UDP使用了尽最大努力交付,即不保证可靠交付,因此主机不需要维持复杂的连接状态表。
  • UDP是面向报文的。发送方的UDP对应用进程交下来的报文既不合并也不拆分,而是保留这些报文的边界,在添加首部后就向下交付给IP层。也就是说,UDP一次交付一个完整的报文。
  • UDP没有拥塞控制,因此网络出现的拥塞不会使源主机的发送速率降低,很多实时应用要求主机以恒定的速率发送数据,并且允许在网络发生拥塞时丢失一些数据,但不允许数据有太大的时延。
  • UDP支持一对一,一对多,多对一,多对多的交互通信
  • UDP的首部开销小。只有8个字节
    用户数据报UDP有两个字段:数据字段和首部字段。首部字段很简答只有8个字节,由四个字段组成,每个字段的长度都是两个字节:
  1. 源端口:源端口号,在需要对方回信时选用。不需要时可以用全0表示。
  2. 目的端口:目的端口号。当运输层从IP层收到数据报时,根据首部中的目的端口,把UDP数据报通过相应的端口,上交至应用程序。
  3. 长度:UDP用户数据报的长度,其最小值是8(仅有首部)
  4. 检验和:检测UDP用户数据报在传输中是否有错,有错就丢弃。

TCP

  • TCP是面向连接的运输层协议,也就是说,应用程序在使用TCP协议之前,必须先建立TCP连接。在传输数据完毕之后要释放建立的连接。
  • 每一条TCP连接只能有两个端点,每一条TCP连接只能是点对点的。TCP连接的两个端口是套接字(IP地址拼接端口号就构成了套接字)。套接字的表示方法是在点分十进制的IP地址后面写上端口号,中间用冒号或逗号隔开。
  • TCP提供可靠交付的服务,通过TCP连接传输的数据,无差错,不丢失,不重复,并且按序到达。
  • TCP是全双工通信,允许通信双方在任何时候都能发送数据。
  • 面向字节流,TCP中的流指的是流入到进程或从进程中流出的字节序列。也就是说,虽然应用程序和TCP的交互是一次一个数据块(大小不等),但TCP把应用程序交下来的数据仅仅看成是一连串的无结构的字节流。

    可靠传输的工作原理

    TCP发送的报文段是交给IP层传输的。但IP层只能尽最大努力交付,也就是说,TCP下面的网络所提供的是不可靠的传输。因此TCP必须采取一些措施来保证两个运输层之间的通信变得可靠。

    停止等待协议

    停止等待就是每发送完一个分组就停止发送,等待对方的确认。在收到确认后再发送下一个分组。

    可靠传输协议是这样设计的:A只要超过了一段时间仍然没有收到确认,就认为刚才发送的分组丢失了,因而重传前面发送过的分组。这就是超时重传。要实现超时重传,应该在每发送完一个分组时设置一个超时计时器。如果在超时计时器到期之前收到了对方的确认,就撤销已设置的超时计时器。
    需要注意:
  1. A在发送完一个分组后,必须暂时保留已发送的分组的副本。只有在收到相应的确认后才能清除暂时保留的分组副本。
  2. 分组和确认分组都必须进行编号。这样才能明确是哪一个发出去的分组收到了确认,而哪一个分组还没有收到确认。
  3. 超时计时器设置的重传时间应当比数据在分组传输的平均往返时间更长一些。因为有时候网络的拥塞会导致产生一些时延。
    很容易想到这种方法的信道利用率并不高,信道在大多数时间都是空闲的。

    为了提高传输效率,可以采用流水线传输。它的原理是:发送方可以连续发送多个分组,不必每发完一个分组就停顿下来等待对方的确认。这样可以使信道上一直有数据在传输。

    使用流水线传输就要考虑一下连续ARQ协议滑动窗口协议

滑动窗口

发送方的应用程序把字节流写入TCP的发送缓存,接收方的应用进程从TCP的接收缓存中读取字节流。

滑动窗口其实就是在发送缓存和接收缓存上的一个位置动态变化的区域,在(发送方)这个区域的后面是已经接收到确认的分组,前面是还没有发送的分组,区域之间的数据都可以发送,有发送了但是还没有收到确认的分组,也有可以发送但是还没有发送的分组。
对于接收方,区域后面是已经读取并且交付主机了的分组,所以该缓存可以不再保留这些数据,区域内的数据是允许接收的,如果接收方收到的数据不是按序到达的,那么它会发送按序数据中的最高序号给出确认。TCP通常对不按序到达的数据是先临时存放在接受窗口中,等到字节流中所缺少的字节收到后,再按序交付上层的应用进程。
总结的说:
发送缓存中暂时存放的是:
1. 发送应用程序传送给TCP准备发送的数据。
2. TCP已经发送了但是还没有收到确认的数据。

接受缓存中暂时存放的是:
1. 按序到达的,但是还没有被接收应用程序读取的数据。
2. 未按序到达的数据。

TCP的流量控制

一般来说,总是希望数据传输的快一些,但如果发送发太快,接收方就可能来不及接收,这就会造成数据的丢失。所谓流量控制就是让发送方的发送速率不要太快,要让接收方来的及接收。在建立连接时,接收方会告诉发送方它的接收窗口的大小,在传输过程中,也会在确认字段中含有其此时的接收窗口的大小,发送方的发送窗口不能超过接收方给出的接收窗口的数值

可以看到,接收方的主机B进行了三次流量控制。第一次把窗口减小到300,第二次减小到100,第三次减小到0,即不允许发送方再发送数据了。
此时其实还有一个问题,如果B可以接收数据了,它会发送一个数据告诉发送方,但是如果这个数据在网络传输中丢失了,A不知道这个数据的存在,B在等A给它发数据。此时陷入一种无限等待状态。
解决这个问题的方法是,TCP为每一个连接设有一个持续计时器。只要TCP连接的一方收到对方的零窗口通知,就启动该计时器。时间到了会给接收方发送一个零窗口探测报文段(携带1字节的数据),接收方在确认这个探测报文段时给出现在的窗口值。如果是零,重启计时器,不是零则僵局打破。
TCP规定,即使设置为零窗口,也必须接收以下几种报文段:零窗口探测报文段,确认报文段和携带紧急数据的报文段。

TCP的拥塞控制

计算机网络中的带宽,交换结点中的缓存和处理机等都是网络中的资源,如果某段时间,对网络中的资源的需求超过了该资源所能提供的可用部分,网络的性能就要变坏,这种情况就叫拥塞。问题的实质是整个系统的各个部分不匹配。只有所有的部分都平衡了,问题才会得到解决。
拥塞控制与流量控制关系密切。所谓拥塞控制就是防止过多的数据流入到网络中,这样可以是网络中的路由器或链路不至于过载。拥塞控制所要做的都有一个前提,就是网络能够承受现有的网络负荷。拥塞控制是一个全局性的过程。相反,流量控制往往是指点对点的通信量的控制,是端到端的问题。流量控制锁要做的就是抑制发送端发送数据的速率,以便接收端来得及接收。

TCP进行拥塞控制的方法有4中:慢开始,拥塞避免,快重传和快恢复。
发送方维持一个叫做拥塞窗口的状态变量。拥塞窗口的大小取决于网络的拥塞程度,并且动态的在变化。发送方让自己的发送窗口等于拥塞窗口。

发送方控制拥塞窗口的原则是:只要网络没有出现拥塞,拥塞窗口就可以增大一些,只要出现拥塞,就必须把拥塞窗口减小一些。

慢开始的思路是这样的
当主机开始发送数据时,由于并不清楚网络的负荷情况,所以如果立即把大量的数据字节注入到网络,那么就有可能引起网络发生拥塞。较好的方法是先试探一下,即由小到大逐渐增大发送窗口,也就是说,从小到大逐渐增大拥塞窗口数值。

拥塞避免算法的思路是
让拥塞窗口cwnd缓慢的增大,即每经过一个往返时间就将发送方的拥塞窗口cwnd+1,而不是像慢开始那样成倍的增长。因此在拥塞避免阶段就有加法增大的特点,这表明在拥塞避免阶段,拥塞窗口cwnd按线性规律缓慢增长,比慢开始算法的拥塞窗口增长速率缓慢的多。

采用快重传算法可以让发送方尽早直到发生了个别报文段的丢失。

快重传算法首先要求接收方不要等到自己发送数据时才进行捎带确认,而是要立即发送确认,即使收到了失序的报文段也要立即发出对已收到的报文段的重复确认。快重传算法规定,只要一连收到3个重复确认,应该立即重传,这样就不会出现超时,发送方也就不会误以为出现了网络拥塞。

在图5-25的点④,发送方知道只是丢失了个别的报文段。于是不启动慢开始,而是执行快恢复算法。发送方调整门限为原来的一半,同时设置拥塞窗口不是从1开始,而是等于门限,并开始执行拥塞避免算法。


参考资料:
《计算机网络——谢希仁 7th》