1.求点赞,求关注
说起TCP协议,很多小伙伴最熟悉的就是三次握手和四次挥手,再了解一点的小伙伴能,能准确说出它工作在tcp/ip模型中的传输层,或者它的mss分段机制。但是TCP协议的机制大有乾坤,有兴起的小伙伴可以跟着博主一起学习,一文学通。
当然了,爱学习的小伙伴已经给博主一个小小的赞了,让博主感受到小伙伴们学习的热情,总结不易,写博文也不易,欢迎各位小伙伴在评论区与博主探讨。
2.为什么需要TCP?
TCP是一个工作在传输层的协议,它的作用就是保证数据交付的可靠性,连接的可靠性。因为工作在它的下一层-网络层的IP协议大哥,只为小数据提供IP地址的寻址服务,是一位不可靠的大哥,不保证数据的交付,也不保证数据的有序交付,更不保证数据的完整交付。
TCP是一个面向连接的,可靠的,基于字节流的通信协议。
-
面向连接:一定是「一对一」才能连接,不能像 UDP 协议可以一个主机同时向多个主机发送消息,也就是一对多是无法做到的;
-
可靠的:无论的网络链路中出现了怎样的链路变化,TCP 都可以保证一个报文一定能够到达接收端;
-
字节流:用户消息通过 TCP 协议传输时,消息可能会被操作系统「分组」成多个的 TCP 报文,如果接收方的程序如果不知道「消息的边界」,是无法读出一个有效的用户消息的。并且 TCP 报文是「有序的」,当「前一个」TCP 报文没有收到的时候,即使它先收到了后面的 TCP 报文,那么也不能扔给应用层去处理,同时对「重复」的 TCP 报文会自动丢弃。
它甚至还可以做拥塞控制,超时重传和流量控制(稍后会讲到)
3. TCP报文格式
在正式学习tcp三次握手之前,我们必须先了解tcp报文格式,因为在握手的时候,客户端和服务端会互相发送报文数据,而从报文格式的变化当中,能更加深刻理解到三次握手。
打开这张令人感到不适的小图片。
源端口号和目标端口号就是客户端和服务端做连接的端口号,不多解释。
序列号和确认答应号是客户端和服务端在互传数据的时候随机生成并随着交流次数累加的数字。序列号保证数据包传输的顺序,用来解决网络包乱序的问题,确认应答号用来解决丢包的问题。
首部长度是随着选项的长度而变化的,首部在没有使用选项这个字段是默认长度是20字节。
控制位:
- ACK:该位为
1
时,「确认应答」的字段变为有效,TCP 规定除了最初建立连接时的SYN
包之外该位必须设置为1
。 - RST:该位为
1
时,表示 TCP 连接中出现异常必须强制断开连接。 - SYN:该位为
1
时,表示希望建立连接,并在其「序列号」的字段进行序列号初始值的设定。 - FIN:该位为
1
时,表示今后不会再有数据发送,希望断开连接。当通信结束希望断开连接时,通信双方的主机之间就可以相互交换FIN
位为 1 的 TCP 段。
4.什么是TCP三次握手?
这次的这个图片更加详细地描述三次握手的整个过程。
- 一开始,客户端和服务端都处于
CLOSE
状态。先是服务端主动监听某个端口,处于LISTEN
状态 - 客户端会随机初始化序号(
client_isn
),将此序号置于 TCP 首部的「序号」字段中,同时把SYN
标志位置为1
,表示SYN
报文。接着把第一个 SYN 报文发送给服务端,表示向服务端发起连接,该报文不包含应用层数据,之后客户端处于SYN-SENT
状态。
- 服务端收到客户端的
SYN
报文后,首先服务端也随机初始化自己的序号(server_isn
),将此序号填入 TCP 首部的「序号」字段中,其次把 TCP 首部的「确认应答号」字段填入client_isn + 1
, 接着把SYN
和ACK
标志位置为1
。最后把该报文发给客户端,该报文也不包含应用层数据,之后服务端处于SYN-RCVD
状态。
-
客户端收到服务端报文后,还要向服务端回应最后一个应答报文,首先该应答报文 TCP 首部
ACK
标志位置为1
,其次「确认应答号」字段填入server_isn + 1
,最后把报文发送给服务端,这次报文可以携带客户到服务端的数据,之后客户端处于ESTABLISHED
状态。
-
服务端收到客户端的应答报文后,也进入
ESTABLISHED
状态。
这中间有一个随机生成序列号并累加的问题,可以参考我的另一篇博客,并且这个序列号起到一个避免网络包乱序,数据包丢包的作用。
从上面的过程可以发现第三次握手是可以携带数据的,前两次握手是不可以携带数据的,一旦完成三次握手,双方都处于 ESTABLISHED
状态,此时连接就已建立完成,客户端和服务端就可以相互发送数据了
我们要清楚的知道,tcp协议就是在保证连接的可靠性,那么什么是连接?
简单来说就是,用于保证可靠性和流量控制维护的某些状态信息,这些信息的组合,包括 Socket、序列号和窗口大小称为连接。
所以我们可以知道,建立一个 TCP 连接是需要客户端与服务端达成上述三个信息的共识。
- Socket:由 IP 地址和端口号组成
- 序列号:用来解决乱序问题等
- 窗口大小:用来做流量控制
那么如何唯一确定一个连接呢?
四元组:
- 源地址
- 源端口
- 目的地址
- 目的端口
5.TCP / UDP?
tcp和udp有什么区别呢?
相比tcp,udp的报文格式简陋得可怜,除了必备的源端口号和目标端口号,就只有包长度和校验和两个字段。
- 目标和源端口:主要是告诉 UDP 协议应该把报文发给哪个进程。
- 包长度:该字段保存了 UDP 首部的长度跟数据的长度之和。
- 校验和:校验和是为了提供可靠的 UDP 首部和数据而设计,防止收到在网络传输中受损的 UDP 包。
关于包长度
细心的你一定发现了,为什么tcp就没有包长度这个字段,那么就要从tcp数据的长度入手了:
其中IP总长度和IP首部长度在IP协议的报文头部当中已经写明,而TCP首部长度也已经在TCP报文中写明,所以不需要包长度字段再来说明数据长度,直接做减法就可以了,那么为什么udp有这个字段呢:
- 第一种说法:因为为了网络设备硬件设计和处理方便,首部长度需要是
4
字节的整数倍。如果去掉 UDP 的「包长度」字段,那 UDP 首部长度就不是4
字节的整数倍了,所以我觉得这可能是为了补全 UDP 首部长度是4
字节的整数倍,才补充了「包长度」字段。 - 第二种说法:如今的 UDP 协议是基于 IP 协议发展的,而当年可能并非如此,依赖的可能是别的不提供自身报文长度或首部长度的网络层协议,因此 UDP 报文首部需要有长度字段以供计算。
TCP 和 UDP 区别:
1. 连接
- TCP 是面向连接的传输层协议,传输数据前先要建立连接。
- UDP 是不需要连接,即刻传输数据。
2. 服务对象
- TCP 是一对一的两点服务,即一条连接只有两个端点。
- UDP 支持一对一、一对多、多对多的交互通信
3. 可靠性
- TCP 是可靠交付数据的,数据可以无差错、不丢失、不重复、按序到达。
- UDP 是尽最大努力交付,不保证可靠交付数据。但是我们可以基于 UDP 传输协议实现一个可靠的传输协议,比如 QUIC 协议,具体可以参见这篇文章:如何基于 UDP 协议实现可靠传输?(opens new window)
4. 拥塞控制、流量控制
- TCP 有拥塞控制和流量控制机制,保证数据传输的安全性。
- UDP 则没有,即使网络非常拥堵了,也不会影响 UDP 的发送速率。
5. 首部开销
- TCP 首部长度较长,会有一定的开销,首部在没有使用「选项」字段时是
20
个字节,如果使用了「选项」字段则会变长的。 - UDP 首部只有 8 个字节,并且是固定不变的,开销较小。
6. 传输方式
- TCP 是流式传输,没有边界,但保证顺序和可靠。
- UDP 是一个包一个包的发送,是有边界的,但可能会丢包和乱序。
7. 分片不同
- TCP 的数据大小如果大于 MSS 大小,则会在传输层进行分片,目标主机收到后,也同样在传输层组装 TCP 数据包,如果中途丢失了一个分片,只需要传输丢失的这个分片。
- UDP 的数据大小如果大于 MTU 大小,则会在 IP 层进行分片,目标主机收到后,在 IP 层组装完数据,接着再传给传输层。
TCP 和 UDP 应用场景:
由于 TCP 是面向连接,能保证数据的可靠性交付,因此经常用于:
FTP
文件传输;- HTTP / HTTPS;
由于 UDP 面向无连接,它可以随时发送数据,再加上 UDP 本身的处理既简单又高效,因此经常用于:
- 包总量较少的通信,如
DNS
、SNMP
等; - 视频、音频等多媒体通信;
- 广播通信;
为什么 UDP 头部没有「首部长度」字段,而 TCP 头部有「首部长度」字段呢?
原因是 TCP 有可变长的「选项」字段,而 UDP 头部长度则是不会变化的,无需多一个字段去记录 UDP 的首部长度。