TCP(Transmission Control Protocol)和UDP(User Datagram Protocol)是传输层的两个协议,旨在建立可靠的通信传输连接。

1、面向有连接型和面向无连接型

通过网络发送数据的方式可以分为两种:面向有连接型和面向无连接型。
(1)面向有连接型
面向有连接型在传输时主要分为三个步骤:

  1. 建立连接
  2. 传输数据
  3. 断开连接

面向有连接除了上面的三个基本步骤外,还包括窗口、保证传包顺序、回执ACK等保证可靠性传输的手段,典型的面向有连接型传输比如TCP协议。
(2)面向无连接型
面向无连接型传输仅有传输数据这一过程,发送端可于任何时候自由发送数据,接收端也不知道何时会从哪里接收到数据,即使接收端不存在,无连接型传输也能将数据发送出去。常见的面向无连接型传输有IP、UDP协议等。

2、UDP介绍

UDP仅提供了最基本的数据传输功能,至于传输时连接的建立和断开、传输可靠性的保证这些UDP统统不关心,而是把这些问题抛给了UDP上层的应用层程序去处理,自己仅提供传输层协议的最基本功能。传输可靠性UDP不能保证的主要表现为:

  • 传输途中即使丢包UDP也不负责重发;
  • 包到达服务端的顺序乱掉时UDP也不负责纠正;
  • 传输过程中的流量控制UDP不负责保证。

看似UDP仅提供了传输功能,很不完善,但UDP在现实生活中应用还是很广泛的,比如多媒体即时通信。

3、TCP介绍

TCP相比UDP,采取了多种措施保证传输的可靠性:

  • 有丢包时的重发机制;
  • 可以对次序乱掉的分包进行顺序控制;
  • 对传输时的流量进行控制;
  • 拥塞控制;

此外,TCP作为一种面向有连接的协议,只有在确认通信对端存在时才会发送数据,会在传输开始前建立连接,传输结束后断开连接。

3.1 TCP和UDP的区别

总结为以下几点:

  • TCP是面向有连接型,UDP是面向无连接型;
  • TCP是一对一传输,UDP支持一对一、一对多、多对一和多对多的交互通信;
  • TCP是面向字节流的,即把应用层传来的报文看成字节流,将字节流拆分成大小不等的数据块,并添加TCP首部;UDP是面向报文的,对应用层传下来的报文不拆分也不合并,仅添加UDP首部;
  • TCP支持传输可靠性的多种措施,包括保证包的传输顺序、重发机制、流量控制和拥塞控制;UDP仅提供最基本的数据传输能力。

    3.2 TCP 保证可靠传输的策略

    TCP协议为了保证传输的可靠性采取了停止等待、ARQ协议、流量控制和拥塞控制等策略。

    3.2.1 停止等待

    停止等待协议是为了保证传输的可靠性的,具体是指在传输时每发送一个分组后就停止发送,等待对方确认收到,在收到了对方发送的确认回执(ACK)后再发送下一个分组,这样能确保发送方发送的每一个分组接收端都能收到。

    3.2.2 ARQ协议

    ARQ协议,即自动重传请求(Automatic Repeat-reQuest),意思是如果发送方在发送后一段时间之内没有收到确认回执,它通常会重新发送。ARQ协议包括停止等待ARQ协议和连续ARQ协议。
    (1)停止等待ARQ协议
    停止等待ARQ协议是指,在停止等待中如果接收端没有收到发送端发来的分组,接收端就不会给发送端发送确认回执,此时发送端会重新发送之前的报文分组。发送端会维护一个超时计时器,超时时间会设置的比数据在传输往返过程的时间要长一些。
    (2)连续ARQ协议
    连续ARQ协议是指,发送端维护一个“窗口”,“窗口”内可以有多个分组,窗口的大小就是窗口中分组的个数,凡是位于“窗口”内的分组可以连续发送出去而不必等待接收端返回的确认回执,对按序到达的最后一个分组,接收端会向发送端发送确认回执,如果有分组没有正确到达,会返回最后一个正确达到的分组序号,该序号后面的分组会重新发送给接收端。
    举个例子,窗口大小为4,发送时第1、2、4号分组均成功发送,3号分组发送失败,接收端会给发送端发送2号分组的确认回执,然后发送端会把2号分组之后的数据(3号分组和4号分组)重新再发送一遍,即使4号分组是发送成功的。
    在连续ARQ协议中,发送端会维护一块发送端的数据缓存,“窗口”里的分组都会在这个缓存中,当需要重新发送“窗口”中的分组报文时,便会从缓存里读取分组并发送。
    连续 ARQ 协议可提高信道利用率。

    3.2.3 流量控制

    流量控制是为了控制发送端发送数据的速率,保证接收端能将本应接收的所有报文分组接收成功,否则会触发自动重传机制造成网络流量的浪费。
    流量控制的具体操作是:接收端会通知发送端自己能接收的数据大小,于是发送端会发送不超过这个数据量的数据,这个大小被称为“窗口”的大小,在TCP首部中专门有一个字段表示“窗口”的大小,该值越大代表网络的吞吐量越高。

    3.2.4 拥塞控制

    计算机网络都处在一个共享的环境,在通信开始时如果立即把大量数据注入到网络,可能会引起网络阻塞,甚至带来网络瘫痪。TCP为了防止该问题的出现,采用了拥塞控制的策略,常见的拥塞控制策略有慢启动、拥塞避免、快重传与快恢复,这里以慢启动为例做简单介绍。
    在通信开始时,定义一个“拥塞窗口”,窗口大小为1,意思是开始时只发送一个分组,之后每收到一个确认回执(ACK),拥塞窗口的大小就加1(即逐渐增大窗口大小),发送端在发送数据时,将拥塞窗口的大小与接收端流量控制窗口的大小作比较,取二者中较小的值,然后实际发送的数据量比这个最小值还要小。

    3.2.5“窗口”

    上面介绍了很多种“窗口”,连续ARQ协议中有“窗口”,流量控制中有“窗口”,拥塞控制中也有“拥塞窗口”,一般说的“滑动窗口”是指流量控制中的“窗口”。

    3.3 TCP粘包

    这一部分参考的连接2里的内容。

    3.3.1 什么是粘包?

    如果客户端连续不断的向服务端发送数据包时,服务端接收的数据会出现两个数据包粘在一起的情况。
    1. TCP 是基于字节流的,虽然应用层和 TCP 传输层之间的数据交互是大小不等的数据块,但是 TCP 把这些数据块仅仅看成一连串无结构的字节流,没有边界;
    2. 从 TCP 的帧结构也可以看出,在 TCP 的首部没有表示数据长度的字段。
    基于上面两点,在使用 TCP 传输数据时,才有粘包或者拆包现象发生的可能。一个数据包中包含了发送端发送的两个数据包的信息,这种现象即为粘包。

    3.3.2 粘包是怎样产生的?

    (1)发送方产生粘包
    采用 TCP 协议传输数据的客户端与服务器经常是保持一个长连接的状态(一次连接发一次数据不存在粘包),双方在连接不断开的情况下,可以一直传输数据。但当发送的数据包过于的小时,那么 TCP 协议默认的会启用 Nagle 算法,将这些较小的数据包进行合并发送(缓冲区数据发送是一个堆压的过程);这个合并过程就是在发送缓冲区中进行的,也就是说数据发送出来它已经是粘包的状态了。
    一句话:要发送的数据小于 TCP 发送缓冲区的大小,TCP 将多次写入缓冲区的数据一次发送出去,将会发生粘包。
    (2)接收方产生粘包
    接收方采用 TCP 协议接收数据时的过程是这样的:数据到接收方,从网络模型的下方传递至传输层,传输层的 TCP 协议处理是将其放置接收缓冲区,然后由应用层来主动获取(C 语言用 recv、read 等函数);这时会出现一个问题,就是我们在程序中调用的读取数据函数不能及时的把缓冲区中的数据拿出来,而下一个数据又到来并有一部分放入的缓冲区末尾,等我们读取数据时就是一个粘包。(放数据的速度 > 应用层拿数据速度)。
    一句话:接收数据端的应用层没有及时读取接收缓冲区中的数据,将发生粘包。

    3.3.3 怎样解决粘包?

    有以下两个措施:

  • 在每个包的末尾加上特殊字符,用以区分连续的两个包;

  • 在报文首部添加包的长度。

    参考

    herongwei:一文搞定 UDP 和 TCP 高频面试题! zhuanlan.zhihu.com
    老刘:计算机网络太难?了解这一篇就够了 zhuanlan.zhihu.com
    TCP可靠传输的工作原理-停止等待&连续的ARQ(一)_网络_turn__back的博客-CSDN博客 blog.csdn.net
    TCP连续ARQ协议和滑动窗口协议 - blythe - 博客园 www.cnblogs.com
    https://www.cnblogs.com/blythe/articles/7348812.html www.cnblogs.com
    herongwei:一文搞定 UDP 和 TCP 高频面试题! zhuanlan.zhihu.com