TCP(Transmission Control Protocol 传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。
- 应用层向
TCP
层发送用于网间传输的、用8位字节表示的数据流,然后TCP
把数据流分区成适当长度的报文段(通常受该计算机连接的网络的数据链路层的最大传输单元(MTU
)的限制)。 - 之后
TCP
把结果包传给IP
层,由它来通过网络将包传送给接收端实体的TCP
层。 TCP
为了保证不发生丢包,就给每个包一个序号,同时序号也保证了传送到接收端实体的包的按序接收。- 接收端实体对已成功收到的包发回一个相应的确认(
ACK
);如果发送端实体在合理的往返时延(RTT
)内未收到确认,那么对应的数据包就被假设为已丢失将会被进行重传。 TCP
用一个校验和函数来检验数据是否有错误;在发送和接收时都要计算校验和。
TCP
报文结构
- 源端口(Source Port)- 16 位(
bit
) - 目标端口(Destination Port)- 16 位
源端口号和目的端口号,用来标识同一台计算机的不同的应用进程。TCP
报头中的源端口号和目的端口号同 IP
数据报中的源 IP
与目的 IP
唯一确定一条 TCP
连接。
- 序列号(Sequence Number)- 发送数据包中的第一个字节的序列号,32位
在 TCP 传送的流中,每一个字节一个序号。比如一个报文段的序号为 300,此报文段的数据部分共有 100 字节,则下一个报文段的序号为 400。序号确保了 TCP 传输的有序性。
- 确认序列号(Acknowledgment Number)- 32位
指明下一个期待收到的字节序号,表明该序号之前的所有数据已经正确无误的收到。确认号只有当 ACK 标志为 1 时才有效。
- 数据偏移(Data Offset)- 4位,该字段的值是
TCP
首部(包括选项)长度除以4
首部长度也叫数据偏移,是因为首部长度实际上指示了数据区在报文段中的起始偏移值。
- 保留(Reserved):为将来定义新的用途保留,现在一般置 0
- 控制标志位 - 6位
- 窗口(Window)- 滑动窗口大小,16位
用来告诉TCP连接对端自己能够接收的最大数据长度。窗口大小最大为 65535。
- 校验和(Checksum)- 奇偶校验,16位
此校验和是对整个的 TCP 报文段,包括 TCP
头部和 TCP
数据,以 16 位字进行计算所得。由发送端计算和存储,并由接收端进行验证。
- 紧急指针(Urgent Pointers)- 紧急指针,16位
只有当 URG 标志置 1 时紧急指针才有效。紧急指针是一个正的偏移量,和顺序号字段中的值相加表示紧急数据最后一个字节的序号。 TCP 的紧急方式是发送端向另一端发送紧急数据的一种方式。
- 选项和填充(Options、Padding)
最常见的可选字段是最长报文大小,又称为 MSS
(Maximum Segment Size),每个连接方通常都在通信的第一个报文段 (为建立连接而设置 SYN
标志为 1 的那个段)中指明这个选项,它表示本端所能接受的最大报文段的长度。选项长度不一定是 32 位的整数倍,所以要加填充位,即在这个字段中加入额外的零,以保证 TCP
头是 32 的整数倍。
- 数据
控制位 | 说明 |
---|---|
URG | 紧急指针标志,为 1 时表示紧急指针有效,为 0 则忽略紧急指针 |
ACK (Acknowledgement) | 确认序号标志,为 1 时表示确认号有效,为 0 表示报文中不含确认信息,忽略确认号字段 |
PSH | push 标志,为 1 表示是带有 push 标志的数据,指示接收方在接收到该报文段以后,应尽快将这个报文段交给应用程序,而不是在缓冲区排队 |
RST | 重置连接标志,用于重置由于主机崩溃或其他原因而出现错误的连接。或者用于拒绝非法的报文段和拒绝连接请求 |
SYN (Synchronize) | 同步序号,用于建立连接过程,在连接请求中,SYN =1 和 ACK =0 表示该数据段没有使用捎带的确认域,而连接应答捎带一个确认,即 SYN =1 和 ACK =1 |
FIN (Finish) | 用于释放连接,为 1 时表示发送方已经没有数据发送了,即关闭本方数据流 |
TCP
建立连接 (三次握手)
TCP三次握手的过程如下:
- 客户端发送
SYN
(SEQ=x)报文给服务器端,进入SYN_SEND状态。 - 服务器端收到
SYN
报文,回应一个SYN
(SEQ=y)ACK
(ACK=x+1)报文,进入SYN_RECV
状态。 - 客户端收到服务器端的
SYN
报文,回应一个ACK
(ACK=y+1)报文,进入Established
状态。
三次握手完成,TCP
客户端和服务器端成功地建立连接,可以开始传输数据了。
TCP
关闭连接 (四次挥手)
建立一个连接需要三次握手,而终止一个连接要经过四次握手,这是由 TCP
的半关闭(half-close)造成的。
- 客户端调用 close() 函数,并发送一个
FIN
(finish) 标志为 1 的数据包给服务端,来表示本方的数据已经全部发送完毕,此时客户端进入FIN_WAIT_1
状态。TCP
规定,FIN
报文段即使不携带数据,也要消耗一个序号。 - 服务端收到客户端的释放报文后,发出确认报文,其中
ACK
=1,ack
=u+1,并且带上自己的序列号seq
=v。表明自己接受到了客户端关闭连接的请求,但还没准备好关闭连接 (半关闭状态),也就是说客户端已经没有数据要发送了,但服务端仍有可能会发送数据。发送完毕后,服务端进入CLOSE_WAIT
状态。当客户端收到该报文后,客户端就进入FIN-WAIT-2
状态,等待服务器发送连接释放报文。 - 服务器端准备好关闭连接时,会向客户端发送一个连接释放报文,其中
FIN
=1,ack
=u+1。由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为seq
=w。发送完毕后,服务端便进入LAST-ACK
(最后确认) 状态。 - 客户端收到服务器的连接释放报文后,需要发送一个确认包,其中
ACK
=1,ack
=w+1,而自己的序列号是seq
=u+1,并进入了TIME-WAIT
(时间等待)状态,等待过程可能出现的要求重传的ACK
包。 此时 TCP 连接还没有释放,必须经过 2 *MSL
(Maximum Segment Lifetime, 最长报文段寿命) 时间后,当客户端撤销相应的TCB
后,才会进入CLOSED
状态。 而服务器只要收到了客户端发出的确认,立即进入CLOSED
状态。同样,撤销TCB
后,就结束了这次的TCP
连接。
TCP
和 UDP
的对比
UDP | TCP | |
---|---|---|
是否连接 | 无连接 | 面向连接 |
是否可靠 | 不可靠传输,不使用流量控制和拥塞控制 | 可靠传输,使用流量控制和拥塞控制 |
连接对象个数 | 支持一对一,一对多,多对一和多对多交互通信 | 只能是一对一通信 |
传输方式 | 面向报文 | 面向字节流 |
首部开销 | 首部开销小,仅 8 字节 | 首部最小 20 字节,最大 60 字节 |
适用场景 | 适用于实时应用 (IP 电话、视频会议、直播等) | 适用于要求可靠传输的应用,例如文件传输 |