TCP协议
TCP 协议灵魂 12 问,巩固你的网路底层基础!-腾讯云开发者社区-腾讯云
TCP和UDP的区别
面向连接
- TCP 需要客户端与服务端之间通过三次握手建联,之后才可以发送数据。
- UDP直接向服务端发数据包。
可靠性
- 有状态
- TCP发数据包时,保证数据包按顺序到达。
- 可控制
- 当TCP协议丢包时,可以控制重发和自己的发送速度,保证数据包完整和有序。
- UDP 是无状态并且不可控的。
- 有状态
基于字节流
- TCP将数据包通过字节流发送。
- UDP数据传送直接发送数据报。
用户消息通过 TCP 协议传输时,消息可能会被操作系统「分组」成多个的 TCP 报文,如果接收方的程序如果不知道「消息的边界」,是无法读出一个有效的用户消息的(粘包问题)。并且 TCP 报文是「有序的」,当「前一个」TCP 报文没有收到的时候,即使它先收到了后面的 TCP 报文,那么也不能扔给应用层去处理,同时对「重复」的 TCP 报文会自动丢弃。
三次握手
TCP三次握手的目的是为了确认客户端和服务端双方都具备 发送数据和接受数据 的能力。
SYN-ACK应答机制
TCP 协议中,客户端与服务端建联用到了 SYN-ACK 应答机制。
SYN
SYN 是发起连接标志,表示要建立链接。
ACK
ACK是确认标识,确认连接的正确性。
服务端收到客户端发送的 SYN 标志后,将ACK发给客户端,以表示消息确认建立链接。只有第二次握手和第三次握手才会有 ACK 标志。
seq
用来标识从TCP发端向TCP收端发送的数据字节流。是一个初始序号。
ack
确认序号。当 ACK 标志存在的时候,ack 确认序号为 seq +1;
- 通俗来说,就是 服务端收到消息后,根据 seq + 1 作为 ack 传给客户端。客户端通过计算 ack 发现和上次发的 seq 值一致,代表通信成功。
- 接下来第三次握手的时候,客户端同样会发一个 ack 给服务端。
三次握手流程
- CLOSED:这是TCP连接的初始状态,表示连接是“关闭”或“未打开”的。
- LISTEN:当服务器端的某个端口处于监听状态,等待客户端连接的到来时,处于此状态。
- SYN_SENT:客户端发送SYN请求建立连接后,处于此状态,等待服务器发送SYN+ACK。
- SYN_RCVD:服务器收到来自客户端的连接请求SYN之后,处于此状态,在接收到SYN请求之后会向客户端回复一个SYN+ACK的确认报文。
- ESTABLISHED:当客户端回复服务器一个ACK和服务器收到该ACK(TCP最后一次握手)之后,服务器和客户端都处于该状态,表示TCP连接已经成功建立。
第一次握手
确认了客户端的发送能力。
第二次握手
确认了服务端的接收能力和发送能力。
第三次握手
确认了客户端的接收能力。
为什么握手是三次,不能是两次或者四次吗
四次握手
三次握手就能确认客户端和服务端的接收和发送能力,再进行握手是没有必要的。
两次握手
没有第三次握手会导致服务端不知道客户端是否能正常接收数据。
假如第二次握手失败
对服务端来说,并不知道客户端是否建立连接。
对客户端来说,不能成功建立连接,因为服务端的第二次握手没有成功。
假如客户端第一次握手延时重发
对于服务端来说,收到了两次第一次握手,发出两次第二次握手。
对于客户端来说,两次第一次握手都是一次TCP请求,属于重发。但是服务端返回两个第二次握手,会导致第二次握手出错一次(浪费资源)。
三次握手过程可以携带数据吗
在第三次握手时,可以携带数据。
因为第三次握手对于客户端来说,服务端接收和发送能力都是正常的,所以可以发送数据,相对安全。
但是第一次不可以,在接收发送能力不能确认的情况下,如果携带数据是存在隐患的。比如攻击服务器,多次建联携带大量数据,那么在第一次握手时服务器就会消耗资源处理数据。
四次挥手
https://blog.csdn.net/huaishu/article/details/93739446
可以看到四次挥手的过程
FIN、ACK
ACK
服务端返回给客户端ACK之后,此时不接收客户端发来的数据。但是服务端可以把剩余数据发给客户端。
等发送完毕之后,再通知客户端。
FIN、ACK
客户端经过 MSL 时间后进入 CLOSED 状态。
ACK
服务端收到之后进入 CLOSED 状态,即断开连接。
为什么需要四次挥手
TCP是全双工的连接,必须两端同时关闭连接,才算真正结束。
- 当一方主动 close的时候,它准备关闭写。但是还可以接收另一方发送的数据。
- 发送 FIN 结束报文给另一方,另一方会先回ACK确认收到了结束报文。
- 另一方将数据全部返回之后,发送 FIN 报文,表示可以关闭。
- 最后主动关闭一方收到 FIN 结束报文之后,发送 ACK给另一方。即两端可以都关闭。
TCP报文格式
TCP报文
源端口号和目的端口号是必须的,不然数据不知道发向服务端的哪个应用。
源端端口,一般是随机端口。而目的端是确定的端口,与应用绑定。
包的序号,是为了解决包乱序的问题。
确认序列,是为了确认包发出去后,目的端是否收到包,如果没收到应该重新发送。确认序列是为了解决丢包的问题。
状态位。
TCP是面向连接的,需要维护双方的状态。包里面包含了状态位,能对客户端和服务端的状态进行变更。
TCP在传输数据之前,要进行三次握手建立连接。
- SYN - 发起连接
- ACK - 回复
- FIN - 结束连接
- RST - 重新连接
窗口大小
- TCP 要做流量控制,通信双方在包中声明窗口大小(缓存大小),标识当前自身的处理能力。防止数据过多处理不过来。
TCP 还可以做拥塞控制,在出现网络通道堵塞时,能控制自己发送的速度。
TCP网络包
在建立连接之后,TCP报文由 HTTP报文+TCP头部组成,然后交给传输层下层的网络层去处理。
其中 TCP 报文保证了 TCP的功能。
- 目的端口号保证接收消息的应用。
- 序号保证有序性。
- 确认序列保证不会丢包,如果出现丢包就会重新发包。
- 状态位保证连接状态。
- 窗口大小保证了TCP的流量控制,防止数据过多无法处理。
TCP三次握手
在 HTTP 传输数据之前,需要进行 TCP建连,这个建连其实就是维护一个状态位。
一开始,客户端和服务端都处于
CLOSE
状态。服务端主动监听某个端口,状态为
LISTEN
。客户端主动发送消息,发送
SYN
标识请求连接。之后客户端处于SYN_SENT
状态。服务端收到客户端的
SYN
标识后,向客户端发送想建立连接的SYN
标识,同时发送确认连接的ACK
标识。之后服务端处于
SYN_RCVD
状态。客户端收到服务端发来的
SYN
和ACK
标识后,向服务端也发送一个ACK
标识,使得服务端确认自己的发送能力。此时客户端已经证明了自己的发送和接受能力正常,因为他发消息和收消息都正常。
状态变为
ESTABLISHED
,表示TCP连接成功。服务端收到客户端发来的
ACK
标识后,确保自己接收和发送能力都正常,状态变为ESTABLISHED
。
SYN 标识代表发起连接,ACK标识代表确认连接正确性。
查看TCP连接状态
Plain Text netstat -napt
TCP数据分割
如果 HTTP 报文过长,为了保证数据发送可靠性。TCP会将报文分割发送,称为 Segment(段)。
MSS:一个网络包容纳的TCP数据的最大长度。
传输层的分割,将TCP数据包分割为段。
该分割规则在网络层。
MTU:一个网络包的最大长度,以太网中一般是
1500
字节。
TCP 数据包根据 MSS 进行分割,分割之后,每段都放进单独的网络包,加上TCP头部和IP头部等信息之后进行发送。
如何确定一个唯一的TCP连接
根据TCP四元组可以确认一个唯一的TCP连接。
- 源IP
- 源端口
- 目的IP
- 目的端口
源IP和目的IP的字段(32位)在IP头部,作用是通过 IP 协议找到指定主机。
源端口和目的端口在 TCP 头部,作用是告诉 TCP 协议报文发给主机的哪个进程。
可靠传输与超时重传
在TCP数据包传输过程中,可能出现丢包、错包、乱序等问题。
确认应答
TCP的通信流程中,接收方收到数据包后会返回一个 ACK,用来通知发送方已它已经接收到了数据。
而发送方在发完数据包之后就会等待这个 ACK,如果在规定时间内没有收到 ACK,就会触发重传机制。
当接收方收到重传的数据时,它可以根据以下步骤进行处理:
- 识别重复报文段:接收方会检查重传数据包的序列号,并与已接收到的数据包序列号进行比较。如果序列号相同,说明这是一个重复的数据包。
- 丢弃重复报文段:由于TCP协议是面向连接的、可靠的传输协议,它保证数据按序到达接收方。因此,当接收方识别出重复的数据包时,它会直接丢弃这个数据包,不会将其传递给应用层处理。
- 发送ACK:尽管接收方已经丢弃了重复的数据包,但它仍然需要发送一个ACK给发送方,以确认已接收到的最后一个按序的数据包。这个ACK的确认号将是下一个期望接收的报文段的序列号。
滑动窗口
以滑动窗口方式进行流量控制。
窗口大小表示服务端的接受能力,用来限制发送方的发送速度。
如果接收方有未确认的数据包,数据窗口不会滑动。直到确认报文收到或者触发了重传机制。
序号
TCP发包过程可能存在乱序得问题。
TCP为每个数据包分配了要给独立的序号,用来保证数据包的有序传输。
如果接收方检测到序号不连续的数据包,说明有丢包发生,就会要求发送方进行重传。