1. TCP头
- 序列号: 在建立连接时由计算机生成的随机数作为其初始值,通过 SYN 包传给接收端主机,每发送一次数据,就「累加」一次该「数据字节数」的大小。用来解决网络包乱序问题。
- 确认应答号: 指下一次「期望」收到的数据的序列号,发送端收到这个确认应答以后可以认为在这个序号以前的数据都已经被正常接收。用来解决丢包的问题。
- ACK: 该位为1时,确认应答号有效
- RST: 该位为1时,表示TCP中出现异常必须强制断连
- SYN: 该位为1时,表示希望建立连接,并在其「序列号」的字段进行序列号初始值的设定
- FIN: 该位为1时,表示今后不会再有数据发送,希望断开连接
2. 概念
IP 层是「不可靠」的,它不保证网络包的交付、不保证网络包的按序交付、也不保证网络包中的数据的完整性。
如果需要保障网络数据包的可靠性,那么就需要由传输层的TCP协议来负责。
TCP 是面向连接的、可靠的、基于字节流的传输层通信协议。
- 面向连接: 一定是「一对一」才能连接,不能像 UDP 协议可以一个主机同时向多个主机发送消息,也就是一对多是无法做到的
- 可靠的: 无论的网络链路中出现了怎样的链路变化,TCP 都可以保证一个报文一定能够到达接收端
TCP只负责传输层的可靠,因此数据到了接收端的传输层之后,能不能保证到应用层,TCP并不管。
比如输入一条信息,信息成功走到了TCP的接收缓冲区,此时接收端回复了一个ack,发送端收到这个ack后就会将自己发送缓冲区里的消息给扔掉。到这里TCP的任务就结束了。
但是聊天软件还需要将数据从TCP的接收缓冲区里读出来,如果在读出来这一刻,手机由于内存不足或其他各种原因,导致软件崩溃闪退了,那么就会导致信息丢失。
- 基于字节流: 用户消息通过 TCP 协议传输时,消息可能会被操作系统「分组」成多个的 TCP 报文,如果接收方的程序如果不知道「消息的边界」,是无法读出一个有效的用户消息的。并且 TCP 报文是「有序的」,当「前一个」TCP 报文没有收到的时候,即使它先收到了后面的 TCP 报文,那么也不能扔给应用层去处理。
当两个消息的某个部分内容被分到同一个 TCP 报文时,就是我们常说的 TCP 粘包问题。
一般通过将特殊字符作为边界来解决粘包问题,比如HTTP通过设置回车符、换行符作为 HTTP 报文协议的边界。
建立一个TCP连接需要服务器和客户端达成这些共识:
- Socket: 由IP地址和端口号组成(源地址,源端口,目的地址,目的端口)(源地址和目的地址在IP头部;源端口和目的端口在TCP头部)
- 序列号: 用来解决乱序问题
- 窗口大小: 用来做拥塞控制
3. 和UDP的区别
3.1 主要区别
UDP不提供那么多复杂的机制,提供面向无连接,基于报文的通信服务。
UDP头部格式相较于TCP非常简洁,如下:
当用户消息通过 UDP 协议传输时,操作系统不会对消息进行拆分,在组装好 UDP 头部后就交给网络层来处理,所以发出去的 UDP 报文中的数据部分就是完整的用户消息,也就是每个 UDP 报文就是一个用户消息的边界,这样接收方在接收到 UDP 报文后,读一个 UDP 报文就能读取到完整的用户消息。
两种传输层协议主要区别如下:
- 连接
- TCP 是面向连接的传输层协议,传输数据前先要建立连接
- UDP 是不需要连接,即刻传输数据
- 服务对象
- TCP是一对一的
- UDP可以一对一,一对多,多对多
- 可靠性
- TCP能够可靠交付数据,数据可以无差错、不丢失、不重复、按序到达
- UDP 是尽最大努力交付,不保证可靠交付数据(但是我们可以基于 UDP 传输协议实现一个可靠的传输协议,比如 QUIC 协议)
- 拥塞控制、流量控制
- TCP 有拥塞控制和流量控制机制,保证数据传输的安全性
- UDP 则没有,即使网络非常拥堵了,也不会影响 UDP 的发送速率
- 传输方式
- TCP 是流式传输,没有边界
- UDP 是一个包一个包的发送,有边界
- 分片
- TCP 的数据大小如果大于 MSS 大小,则会在传输层进行分片,目标主机收到后,也同样在传输层组装 TCP 数据包,如果中途丢失了一个分片,只需要传输丢失的这个分片。
- UDP 的数据大小如果大于 MTU 大小,则会在 IP 层进行分片,目标主机收到后,在 IP 层组装完数据,接着再传给传输层。
3.2 应用场景
由于 TCP 是面向连接,能保证数据的可靠性交付,因此经常用于:
- FTP文件传输
- HTTP/HTTPS
由于 UDP 面向无连接,它可以随时发送数据,再加上 UDP 本身的处理既简单又高效,因此经常用于:
- 包总量较少的通信,如 DNS 、SNMP 等
- 视频、音频等多媒体通信
- 广播通信
4. TCP分片
MTU: 一个网络包的最大长度,以太网中一般为 1500 字节;
MSS: 除去 IP 和 TCP 头部之后,一个网络包所能容纳的 TCP 数据的最大长度;
如果把TCP的整个报文交给IP层进行分片会怎么样呢?会导致如果一个 IP 分片丢失,整个 IP 报文的所有分片都得重传,因为 IP 层本身没有超时重传机制,它由传输层的 TCP 来负责超时和重传。
当某一个 IP 分片丢失后,接收方的 IP 层就无法组装成一个完整的 TCP 报文(头部 + 数据),也就无法将数据报文送到 TCP 层,所以接收方不会响应 ACK 给发送方,因为发送方迟迟收不到 ACK 确认报文,所以会触发超时重传,就会重发「整个 TCP 报文(头部 + 数据)」。
因此,可以得知由 IP 层进行分片传输,是非常没有效率的。
所以,为了达到最佳的传输效能,TCP 协议在建立连接的时候通常要协商双方的 MSS 值,当 TCP 层发现数据超过 MSS 时,则就先会进行分片,当然由它形成的 IP 包的长度也就不会大于 MTU ,自然也就不用 IP 分片了。
通过这种TCP层分片的方式,如果一个分片丢失,只用重新传MSS即可,不用把头部也重传了,大大提高了重传的效率。
5. TCP是如何确保可靠性的?
TCP连接确保可靠性⽅法如下:
- 数据块大小控制: 应⽤数据被分割成TCP认为最合适发送的数据块,再传输给⽹络层,数据块被称为报⽂段或段。
- 序列号: TCP给每个数据包指定序列号,接收⽅根据序列号对数据包进⾏排序,并根据序列号对数据包去重。
- 校验和: TCP将保持它⾸部和数据的校验和。这是⼀个端到端的检验和,⽬的是检测数据在传输过程中的任何变化。如果收到报⽂的检验和有差错,TCP将丢弃这个报⽂段和不确认收到此报⽂段。
- 流量控制: TCP连接的每⼀方都有固定⼤小的缓冲空间,TCP的接收端只允许发送端发送接收端缓冲区能接纳的数据。当接收方来不及处理发送⽅的数据,能提示发送方降低发送的速率,防止包丢失。TCP利⽤滑动窗⼝实现流量控制。
- 拥塞控制: 当网络拥塞时,减少数据的发送。
- 确认应答: 通过 ARQ 协议实现。基本原理是每发完⼀个分组就停止发送,等待对方确认。如果没收到确认,会重发数据包,直到确认后再发下⼀个分组。
- 超时重传: 当TCP发出⼀个数据段后,它启动⼀个定时器,等待⽬的端确认收到这个报⽂段。如果不能及时收到⼀个确认,将重发这个报⽂段。