# TCP、UDP 的比较

> 网络协议是每个工程师都需要了解和掌握的知识。 TCP/IP 中有2个最具代表性的传输层协议：TCP、UDP。


## 一、TCP/IP 网络模型

计算机与网络设备要相互通信，双方就必须基于相同的方法。比如，如何探测到通信目标、由哪一边先发起通信、使用哪种语言进行通信、怎样结束通信等规则都需要事先确定。不同的硬件、操作系统之间的通信，所有的这一切都需要一种规则。而我们就把这种规则称为协议（protocol）。

TCP/IP 是协议簇，比如：TCP、UDP、IP、FTP、HTTP、ICMP、SMTP 等都属于 TCP/IP 簇内的协议。

TCP/IP模型是互联网的基础，它是一系列网络协议的总称。这些协议可以划分为四层，分别为链路层、网络层、传输层和应用层。

- 链路层：负责封装和解封装 IP 报文，发送和接受 ARP/RARP 报文等。
- 网络层：负责路由以及把分组报文发送给目标网络或主机。
- 传输层：负责对报文进行分组和重组，并以 TCP 或 UDP 协议格式封装报文。
- 应用层：负责向用户提供应用程序，比如HTTP、FTP、Telnet、DNS、SMTP等。


| OSI 七层模型 |  TCP/IP 概念层模型 |  功能 |  TCP/IP 协议簇 |
|-|-|-|-|
|应用层 |应用层 |文件传输、电子邮件、文件服务、虚拟终端 | FTP、SMTP、TELNET、DNS|
|表示层 |应用层 |数据格式化、代码转换、数据加密 | 没有协议|
|会话层 |应用层 |解除或建立别的节点的联系 | 没有协议 |
|传输层 | 传输层 |提供端对端的接口 | UDP、TCP |
|网络层 |网络层 |为数据包选择路由 | IP、ICMP、RIP、OSPF、BGP、IGMP|
|物理链路层 |链路层 |传输有地址的帧以及错误检测功能 | SLIP、CSLIP、PPP、ARP、RARP、MTU|
|物理层 |链路层 |以二进制数据形式在物理媒体上传输数据 | ISO2110、IEEE802、IEEE802.2|


在网络体系结构中网络通信的建立必须是在通信双方的对等层进行，不能交错。 在整个数据传输过程中，数据在发送端时经过各层时都要附加上相应层的协议头和协议尾（仅数据链路层需要封装协议尾）部分，也就是要对数据进行协议封装，以标识对应层所用的通信协议。接下去介绍 TCP/IP 中有两个具有代表性的传输层协议：TCP 和 UDP。



## 二、UDP

UDP（User Data Protocol）协议全称是用户数据报协议，在网络中它与  TCP 协议一样用于处理数据包，是一种无连接的协议。在 OSI 模型中，位于第四层即传输层，处于 IP 协议的上一层。UDP 有不提供数据包分组、组装和不能对数据包进行排序的缺点，也就是说，当报文发送之后，是无法得知其是否安全完整到达的。

特点：

### 1.面向无连接

首先 UDP 是不需要和 TCP一样在发送数据前进行三次握手建立连接的，想发数据就可以开始发送了。并且也只是数据报文的搬运工，不会对数据报文进行任何拆分和拼接操作。

具体来说就是：
- 在发送端，应用层将数据传递给传输层的 UDP 协议，UDP 只会给数据增加一个 UDP 头标识下是 UDP 协议，然后就传递给网络层了
- 在接收端，网络层将数据传递给传输层，UDP 只去除 IP 报文头就传递给应用层，不会任何拼接操作
  
### 2.有单播、多播、广播的功能

UDP 不止支持一对一的传输方式，同样支持一对多，多对多，多对一的方式，也就是说 UDP 提供了单播，多播，广播的功能。

### 3.UDP是面向报文的

发送方的UDP对应用程序交下来的报文，在添加首部后就向下交付IP层。UDP对应用层交下来的报文，既不合并，也不拆分，而是保留这些报文的边界。因此，应用程序必须选择合适大小的报文

### 4.不可靠性

- 首先不可靠性体现在无连接上，通信都不需要建立连接，想发就发，这样的情况肯定不可靠。
- 并且收到什么数据就传递什么数据，并且也不会备份数据，发送数据也不会关心对方是否已经正确接收到数据了。
- 再者网络环境时好时坏，但是 UDP 因为没有拥塞控制，一直会以恒定的速度发送数据。即使网络条件不好，也不会对发送速率进行调整。这样实现的弊端就是在网络条件不好的情况下可能会导致丢包，但是优点也很明显，在某些实时性要求高的场景（比如电话会议）就需要使用 UDP 而不是 TCP。

![UDP传输示意图](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/2019-06-13-UDP.gif)

从上面的动态图可以得知，UDP只会把想发的数据报文一股脑的丢给对方，并不在意数据有无安全完整到达。

### 5.头部开销小，传输数据高效

![UDP报文头部结构](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/2019-06-13-UDPHeader.png)

- 两个十六位的端口号，分别为源端口（可选字段）和目标端口
- 整个数据报文的长度
- 整个数据报文的检验和（IPv4 可选 字段），该字段用于发现头部信息和数据中的错误

因此 UDP 的头部开销小，只有八字节，相比 TCP 的至少二十字节要少得多，在传输数据报文时是很高效的


## 三、TCP

当一台计算机想要与另一台计算机通讯时，两台计算机之间的通信需要畅通且可靠，这样才能保证正确收发数据。例如，当你想查看网页或查看电子邮件时，希望完整且按顺序查看网页，而不丢失任何内容。当你下载文件时，希望获得的是完整的文件，而不仅仅是文件的一部分，因为如果数据丢失或乱序，都不是你希望得到的结果，于是就用到了TCP。

TCP协议全称是传输控制协议是一种面向连接的、可靠的、基于字节流的传输层通信协议，由 IETF 的RFC 793定义。TCP 是面向连接的、可靠的流协议。流就是指不间断的数据结构，你可以把它想象成排水管中的水流。

![TCP传输示意图](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/2019-06-13-TCPAnimation.gif)


### 三次握手

HTTP 协议是建立在请求相应模型上的。首先客户端建立一条与服务器的 TCP 链接，并发送请求到服务器，包含请求方法、URI、协议版本以及相关的 MIME 信息。服务器响应一个状态行，包含协议版本、一个成功和失败码、以及相关的 MIME 信息。  

HTTP/1.0 为每次 HTTP 请求/相应都建立一条新的 TCP 链接。因此一个包含图片和多媒体的网页将建立多次的短期 TCP 链接。且一次 TCP 链接都需要三次握手、四次挥手。

![TCP三次握手](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/2019-06-13-TCPThreeShakeHandle.png)

- 第一次握手：客户端将 SYN 置为1，选择一个 **seq=x**（序号，起始发送位）。SYN 报文段不能携带数据，但要消耗掉一个序号。此时客户端进入 **SYN_SENT** （同步已发送）状态。SYN（Synchronize Sequence Number）：同步序列编号
- 第二次握手：服务端收到报文段后，若同意建立请求则向客户端发送确认。在确认报文中把 SYN 和 ACK 都置为1，确认号是 **ack=x+1**，同时也选择一个初始序号 **seq=y**。这个报文段也不能携带数据，但同样需消耗掉一个序号。此时服务器进入 **SYN_RECV**  状态；ACK（Ackonwledgement）：确认字符
- 第三次握手：客户端收到服务端 ACK+SYN 包，需要向服务端确认。确认报文段的 ACK 置为1（建立连接，2端的ACK都为1），确认号 **ack=y+1**，而自己的序号 **seq=x+1**。客户端和服务端进入 **ESTABLISHED** （TCP 连接成功）状态，完成三次握手。


### 四次挥手

![TCP四次挥手](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/2019-06-13-TCPFourShakeHands.png)

- 第一次挥手：客户端应用进程先向其 TCP 发出连接释放报文段，并停止发送数据，主动关闭 TCP 连接（此时关闭的是自己与客户端的连接）。FIN 置为1，序号 seq=u，它等于前面已传送过的数据的最后一个字节的序号加1。这时客户端进入 **FIN_WAIT_1** （终止等待1）状态，等待服务端的确认。TCP 规定，FIN 报文段即使不携带数据段，它也会消耗掉一个序号。
- 第二次挥手：服务端收到连接释放请求后，会告诉应用层要释放 TCP 链接。发出确认，确认号 ack=u+1，序号为 seq=v，等于服务端前面已经传输过的数据的最后一个字节的序号加1。然后服务端就进入了 CLOSE_WAIT（关闭等待）状态。TCP 服务器进程通知高层应用数据，因而从客户端到服务端这个芳香的连接就释放了。此时 TCP 处于半关闭状态。即客户端已经没数据要发送了，服务端还在发送数据，但是客户端仍需接收数据。也就是说从服务端到客户端的连接尚未关闭
- 第三次挥手：客户端收到来自服务端的消息后进入了 FIN_WAIT_2 (终止等待2)状态。等待服务端发出的连接释放报文段。若服务端已经没有要向客户端发送数据，其应用进程就通知 TCP 释放连接。这时候服务端发出的报文段必须 FIN=1。假设服务端序号为 W（在在关闭状态下服务端可能又发送了一些数据，因此与 V 有一定距离）。服务端还必须重复上次发送过的确认号 ack=u+1。这时服务端就进入 LAST_ACK（最后确认）状态，等待客户端的确认
- 第四次挥手：客户端收到服务端发送的连接释放报文段后，必须对此发出确认。在确认报文段中把 ACK 置1，确认号为 ack=w+1，而自己的序列号 seq=u+1（根据 TCP 标准，前面发送过的 FIN 报文段要消耗一个序号）。然后进入到 TIME_WAIT（时间等待）状态。现在 TCP 还没有释放掉。必须经过时间等待计时器设置的时间 2MSL 后，客户端才可以进入到 CLOSED 状态。时间 MSL 叫做最长报文段寿命。


### TCP 协议的特点

- 面向连接
  面向连接，是指发送数据之前必须在两端建立连接。建立连接的方法是三次握手，这样能建立可靠的连接。建立连接是为数据的可靠传输打下了基础。
- 仅支持单向传输
  每条 TCP 传输连接只能有2个端点，只能进行点对点的数据传输，不支持多播和广播传输方式
- 面向字节流
  TCP 不像 UDP 那样一个个报文独立传输，而是在不保留报文边界的情况下以字节流方式进行传输
- 可靠传输
  对于可靠传输，判断丢包，误码靠的是 TCP 的段编号以及确认号。TCP 为保证报文传输的可靠，给每个包一个序号，同时序号也保证了传输到接收端实体的包的按序接收。然后接收端实体对已成功收到的字节发回一个相应的确认 ACK；如果发送端实体在合理的往返时延（RTT）内未收到确认，那么对应的数据将被重传。
- 提供拥塞控制
  当网络出现拥塞时，TCP 能够减小向网络注入数据的速率和数量，缓解拥塞
- TCP 提供全双工通信
  TCP 允许通信双方的应用程序在任何都能发送数据，因为 TCP 连接的两端都设有缓存，用来临时存放双向通信的数据。当然，TCP 可以发送一个数据段，也可以缓存一段时间一边一次发送更多的数据段（最大的数据段大小取决于 MSS）

## TCP、UDP 对比

1. 对比

|  |  UDP |  TCP |
| - | - | - |
|是否连接| 无连接 | 面向连接 |
|是否可靠| 不可靠传输（不存在流量控制、拥塞控制） | 可靠传输（使用流量控制、拥塞控制） |
|连接对象个数| 一对一、一对多、多对一、多对多互相通信 | 只可一对一通信 |
|传输方式| 面向报文 | 面向字节流 |
|首部开销| 开销小，仅8字节 | 开销大，20字节 |
|使用场景| 实时应用，比如IP电话、视频会议、直播 | 要求可靠传输的应用，比如文件传输 |

2. 使用场景

基于上面的优缺点，那么： 什么时候应该使用TCP： 当对网络通讯质量有要求的时候，比如：整个数据要准确无误的传递给对方，这往往用于一些要求可靠的应用，比如HTTP、HTTPS、FTP等传输文件的协议，POP、SMTP等邮件传输的协议。 在日常生活中，常见使用TCP协议的应用如下： 浏览器，用的HTTP FlashFXP，用的FTP Outlook，用的POP、SMTP Putty，用的Telnet、SSH QQ文件传输 ………… 什么时候应该使用UDP： 当对网络通讯质量要求不高的时候，要求网络通讯速度能尽量的快，这时就可以使用UDP。 比如，日常生活中，常见使用UDP协议的应用如下： QQ语音 QQ视频 TFTP ……





