TCP 三次握手与四次挥手
TCP基本认识
TCP 头格式
序列号:在建立连接时由计算机生成的随机数作为其初始值,通过 SYN 包传给接收端主机,每发送一次数据,就「累加」一次该「数据字节数」的大小。用来解决网络包乱序问题。
确认应答号:指下一次「期望」收到的数据的序列号,发送端收到这个确认应答以后可以认为在这个序号以前的数据都已经被正常接收。用来解决丢包的问题。
控制位:
-
ACK:该位为
1
时,「确认应答」的字段变为有效,TCP 规定除了最初建立连接时的SYN
包之外该位必须设置为1
。 -
RST:该位为
1
时,表示 TCP 连接中出现异常必须强制断开连接。 -
SYN:该位为
1
时,表示希望建立连接,并在其「序列号」的字段进行序列号初始值的设定。 -
FIN:该位为
1
时,表示今后不会再有数据发送,希望断开连接。当通信结束希望断开连接时,通信双方的主机之间就可以相互交换FIN
位为 1 的 TCP 段
TCP协议意义
IP
层是「不可靠」的,它不保证网络包的交付、不保证网络包的按序交付、也不保证网络包中的数据的完整性。
如果需要保障网络数据包的可靠性,那么就需要由上层(传输层)的 TCP
协议来负责。
因为 TCP 是一个工作在传输层的可靠数据传输的服务,它能确保接收端接收的网络包是无损坏、无间隔、非冗余和按序的
TCP是面向连接的、可靠的、基于字节流的传输层通信协议
-
面向连接:一定是「一对一」才能连接,不能像 UDP 协议可以一个主机同时向多个主机发送消息,也就是一对多是无法做到的;
-
可靠的:无论的网络链路中出现了怎样的链路变化,TCP 都可以保证一个报文一定能够到达接收端;
-
字节流:用户消息通过 TCP 协议传输时,消息可能会被操作系统「分组」成多个的 TCP 报文,如果接收方的程序如果不知道「消息的边界」,是无法读出一个有效的用户消息的。并且 TCP 报文是「有序的」,当「前一个」TCP 报文没有收到的时候,即使它先收到了后面的 TCP 报文,那么也不能扔给应用层去处理,同时对「重复」的 TCP 报文会自动丢弃
建立一个 TCP 连接是需要客户端与服务端达成上述三个信息的共识。
-
Socket:由 IP 地址和端口号组成
-
序列号:用来解决乱序问题等
-
窗口大小:用来做流量控制
唯一确定一个TCP需要通过一个四元组,这个四元组包括:
源地址、源端口、目标地址、目标端口
源地址和目的地址的字段(32 位)是在 IP 头部中,作用是通过 IP 协议发送报文给对方主机。
源端口和目的端口的字段(16 位)是在 TCP 头部中,作用是告诉 TCP 协议应该把报文发给哪个进程。
客户端 IP 和端口是可变的,其理论值计算公式如下:
客户端 IP 和端口是可变的,其理论值计算公式如下:
对 IPv4,客户端的 IP 数最多为 2
的 32
次方,客户端的端口数最多为 2
的 16
次方,也就是服务端单机最大 TCP 连接数,约为 2
的 48
次方。
当然,服务端最大并发 TCP 连接数远不能达到理论上限,会受以下因素影响:
-
文件描述符限制
,每个 TCP 连接都是一个文件,如果文件描述符被占满了,会发生 Too many open files。Linux 对可打开的文件描述符的数量分别作了三个方面的限制:
-
系统级:当前系统可打开的最大数量,通过
cat /proc/sys/fs/file-max
查看; -
用户级:指定用户可打开的最大数量,通过
cat /etc/security/limits.conf
查看; -
进程级:单个进程可打开的最大数量,通过
cat /proc/sys/fs/nr_open
查看;
-
-
内存限制,每个 TCP 连接都要占用一定内存,操作系统的内存是有限的,如果内存资源被占满后,会发生 OOM
UDP 和 TCP 区别,分别的应用场景
UDP 不提供复杂的控制机制,利用 IP 提供面向「无连接」的通信服务。
-
目标和源端口:主要是告诉 UDP 协议应该把报文发给哪个进程。
-
包长度:该字段保存了 UDP 首部的长度跟数据的长度之和。
-
校验和:校验和是为了提供可靠的 UDP 首部和数据而设计,防止收到在网络传输中受损的 UDP 包。
TCP 和 UDP 区别:
1. 连接
-
TCP 是面向连接的传输层协议,传输数据前先要建立连接。
-
UDP 是不需要连接,即刻传输数据。
2. 服务对象
-
TCP 是一对一的两点服务,即一条连接只有两个端点。
-
UDP 支持一对一、一对多、多对多的交互通信
3. 可靠性
-
TCP 是可靠交付数据的,数据可以无差错、不丢失、不重复、按序到达。
-
UDP 是尽最大努力交付,不保证可靠交付数据。但是我们可以基于 UDP 传输协议实现一个可靠的传输协议,比如 QUIC 协议
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首部长度
UDP 头部有「包长度」字段,而 TCP 头部则没有「包长度」字段
TCP计算负载数据长度公式为:
TCP数据长度 = IP总长度-IP首部长度-TCP首部长度
其中 IP 总长度 和 IP 首部长度,在 IP 首部格式是已知的。TCP 首部长度,则是在 TCP 首部格式已知的,所以就可以求得 TCP 数据的长度。
而UDP按道理也是基于IP层,按道理也可以通过这个公式计算,查阅资料发现可能有两种说法:
-
第一种说法:因为为了网络设备硬件设计和处理方便,首部长度需要是
4
字节的整数倍。如果去掉 UDP 的「包长度」字段,那 UDP 首部长度就不是4
字节的整数倍了,所以我觉得这可能是为了补全 UDP 首部长度是4
字节的整数倍,才补充了「包长度」字段。 -
第二种说法:如今的 UDP 协议是基于 IP 协议发展的,而当年可能并非如此,依赖的可能是别的不提供自身报文长度或首部长度的网络层协议,因此 UDP 报文首部需要有长度字段以供计算
TCP和UDP可以使用同一个端口
在数据链路层中,通过 MAC 地址来寻找局域网中的主机。在网际层中,通过 IP 地址来寻找网络中互连的主机或路由器。在传输层中,需要通过端口进行寻址,来识别同一计算机中同时通信的不同应用程序。
所以,传输层的「端口号」的作用,是为了区分同一个主机上不同应用程序的数据包。
所以,传输层的「端口号」的作用,是为了区分同一个主机上不同应用程序的数据包。
传输层有两个传输协议分别是 TCP 和 UDP,在内核中是两个完全独立的软件模块。
当主机收到数据包后,可以在 IP 包头的「协议号」字段知道该数据包是 TCP/UDP,所以可以根据这个信息确定送给哪个模块(TCP/UDP)处理,送给 TCP/UDP 模块的报文根据「端口号」确定送给哪个应用程序处理。
因此,TCP/UDP 各自的端口号也相互独立,如 TCP 有一个 80 号端口,UDP 也可以有一个 80 号端口,二者并不冲突。