一、定义
传输控制协议(TCP,Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议。它是在传输层。
二、结构
TCP报头.png源端口和目的端口(各2byte)
即数据发送端口和数据接收端口
序号 Sequence Number (4byte)
TCP用序列号对数据包进行标记,以便在到达目的地后重新重装,假设当前的序列号为 s,发送数据长度为 l,则下次发送数据时的序列号为 s + l。在建立连接时通常由计算机生成一个随机数作为序列号的初始值。
确认号 Acknowledgemt Number (4byte)
表示期望收到对方下一个报文段的序号值。 TCP 的可靠性,是建立在「每一个数据报文都需要确认收到」的基础之上的。
数据偏移 Offset (0.5byte 4位)
它指出了 TCP报文段的数据起始处距离TCP报文的起始处有多远,即TCP报头长度。
保留 Reserved(0.75byte 6位)
保留为今后使用,但目前应置为 0。但为了支持ECN(一种端到端的拥塞通知机制),TCP使用了后三位的3个标志位:Nonce Sum (NS)
,ECN-Echo (ECE)
和Congestion Window Reduced (CWR)
,在wireshark抓包里也能看到。
标志位 TCP Flags(0.75byte,6位,)
标志位,一共有 6 个,分别占 1 位,共 6 位 。 每一位的值只有 0 和 1,分别表达不同意思。
-
URG:
紧急指针有效。 -
ACK:
确认序号有效。当 ACK = 1 的时候,确认号(Acknowledgemt Number)有效,否则确认号被忽略。 -
PSH:
优先推送。当 PSH = 1 的时候,表示该报文段高优先级,接收方 TCP 应该尽快推送给接收应用程序,而不用等到整个 TCP 缓存都填满了后再交付。 -
RST:
重置连接。当 RST = 1 的时候,表示 TCP 连接中出现严重错误,需要释放并重新建立连接。 -
SYN:
发起了一个新连接。当 SYN = 1 的时候,表明这是一个请求连接报文段。SYN=1时不能携带数据。 -
FIN:
释放一个连接。当 FIN = 1 时,表示此报文段的发送方的数据已经发送完毕,并要求释放 TCP 连接。
窗口大小(2byte)
该字段明确指出了现在允许对方发送的数据量,它告诉对方本端的 TCP 接收缓冲区还能容纳多少字节的数据,这样对方就可以控制发送数据的速度。
校验和(2byte)
由发送端填充,接收端对 TCP 报文段执行 CRC 算法,以检验 TCP 报文段在传输过程中是否损坏,如果损坏这丢弃。检验范围包括首部和数据两部分,这也是 TCP 可靠传输的一个重要保障。
紧急指针(2byte)
仅在 URG = 1 时才有意义,它指出本报文段中的紧急数据的字节数。 当 URG = 1 时,发送方 TCP 就把紧急数据插入到本报文段数据的最前面,而在紧急数据后面的数据仍是普通数据。
三、三次握手和四次挥手
3.1 三次握手
三次握手.pngTCP面向连接,建立连接之后才能够发送数据,三次握手就是为了建立连接。
如果只有2次握手的话,服务端就不知道自己是否发送能发数据到客户端。
3.2 四次挥手
四次挥手.png在服务器端发送一个FIN时,客户端会处于time_wait状态。当处于time_wait状态时,我们无法创建新的连接,因为端口被占用。
关于 TIME_WAIT 过渡到 CLOSED 状态说明: 从 TIME_WAIT 进入 CLOSED 需要经过 2MSL,其中 MSL 就叫做 最长报文段寿命(Maxinum Segment Lifetime),根据 RFC 793 建议该值这是为 2 分钟,也就是说需要经过 4 分钟,才进入 CLOSED 状态。
TIME_WAIT的作用
- 可靠的终止TCP连接。若处于time_wait的客户端发送给服务器确认报文段丢失的话,服务器将在此重新发送FIN报文段,那么客户端必须处于一个可接收的状态就是time_wait状态而不是close状态。
- 在第四次挥手后,经过2msl的时间足以让本次连接产生的所有报文段都从网络中消失,这样下一次新的连接中就肯定不会出现旧连接的报文段了。
TCP四次挥手可以变成三次吗?
可以。四次挥手->三次挥手就是服务端将FIN和ack合并成一条进行发送。为什么会进行合并呢?是因为在关闭的时候,服务端没有数据发送给客户端,然后优化后就会将FIN和ack合并在一起发送给客户端。
TCP为啥可靠?
- 面向连接,确认通信端存在才会发数据
- 每次发送数据,对方会回个ACK回复,如果短时间内没收到回复,那就进行重发。如果一段时间内都没收到回复,那就主动断开连接。
为何会出现粘包拆包?
-
应用程序写入的数据大于套接字缓冲区大小,这将会发生拆包。
-
应用程序写入的数据小于套接字缓冲区大小,网卡将应用多次写入数据发送到网络,这将会发生粘包。
-
进行MSS(最大报文长度)大小TCP分段,当报文长度-TCP头部长度>MSSd的时候将会发生拆包。
-
接收方法不及时读取套接字缓冲区数据,也会发生粘包
服务端出现大量time_wait
http的请求头Connection如果是close的话,服务端会主动断开连接,就会产生大量time_wait状态的端口。
解决:
-
http
客户端用Connection=keep-alive
的请求头。 - 服务器端允许
time_wait
状态的 socket 被重用;缩减time_wait
时间,设置为 1 MSL(即,2 mins)。
参考资料
百度百科——TCP
TCP/IP协议详解——知乎
TCP三次握手四次挥手及time_wait状态解析
为什么TCP会出现粘包/拆包?
终于搞懂了服务器为啥产生大量的TIME_WAIT!
网友评论