TCP协议是一种面向连接、面向字节流、提供可靠传输服务的一对一通信传输层协议。
· TCP特点
面向连接:数据收发前需要建立连接,数据收发要通过这个逻辑的虚拟信道。
全双工通信:通信两端都可收可发,而且双向的收发可以同时发生。
一对一通信:一个client socket只能与一个客户端进程的socket进行数据收发。
面向字节流:TCP只把数据看成一连串有序而无结构的字节流。
可靠传输服务:数据不丢失、不重复、无差错、不乱序。
TCP功能在UDP功能(数据交付和差错检验)的基础上加上了连接管理、超时重传、流量控制和拥塞控制。
· TCP报文段格式
TCP首部的前20个字节是固定的(TCP首部最小长度为20字节,最大长度60),后面4n字节是按需增加的选项。
序号(seq):TCP数据的每个字节是按序编号的,TCP首部的“序号”字段就是本报文携带数据的第一个字节的编号,范围在0~2^32-1, 超过则下一个序号会回到0重新增长。
PS:初始序号(ISN)在建立连接时设置,ISN是一个随时间动态增长的非0序号,这也是为了防止被攻击者伪造初始序号和TCP报文。
序号是TCP实现可靠传输的基础,其作用有:防止接收方接收重复分组;确认应答机制基于序号,给字节标记序号便于超时重传触发时发送方知道自己应该重发那哪分组。
确认号(ack):是一端期望收到对端下一个报文段数据的第一个字节的序号,也是本端上一次发送的报文段的最后一个字节序号+1。
数据偏移:表示TCP首部的长度,占4个比特,每个比特的单位是4字节。因此TCP首部最大长度为60字节。
6个标志位
紧急位 URG:URG = 1时报头的紧急指针字段生效,表示报文段有紧急数据要尽快传送。
socket有发送缓冲区,运输层会择机将发送缓冲区的数据发送出去(3个时机),但如果URG = 1的报文段则无需等待这3个时机,可以直接发送。
确认位 ACK:ACK = 1时,报头的确认号(ack)字段才有效,表示本报文是一个确认报文(tcp的应答确认机制)。TCP规定在连接建立后所有传送的报文段都必须把ACK置为1。
推送位 PSH:PSH=1的报文段,接收方会尽快上交给应用进程(不要在接收缓冲区中缓存),该标志位是针对接收方的。
重置连接位 RST:RST =1 的报文段标明TCP连接出现差错,必须释放连接,然后重新建立连接。
同部位 SYN:SYN = 1表示这是一个连接请求报文。
终止位 FIN:FIN = 1表示这是一个请求释放连接的报文
窗口字段:接收方告诉发送方,下一次容许发送方能够发送的最大数据长度(取决于接收方的接收缓冲区大小)。
检验和:同UDP校验和。
紧急指针:指出本报文段中紧急数据有多少字节,紧急数据放在报文段数据的最前面,所以紧急指针等于紧急数据在本报文的最后一个字节的位置。窗口为0时也可以发送紧急数据。
选项字段(最大40字节):该字段长度可变。有如下可选项:
所有可选选项都包含该选项的类型长度还有实际内容(例如下面的时间戳选项,kind=8表示这是一个时间戳选项,length表示时间戳选项长度为10字节)。
所有可选选项都在建立连接时的SYN报文指定开启。
窗口扩大选项 使用窗口扩大项后,可以是窗口大小从原本最大 2^16 - 1 扩大到最大 2^30 - 1个字节。
这是考虑到链路可能有长又肥(即带宽很大,且链路很长(即时延很长)),如果一次发的数据太少就无法充分利用带宽,吞吐率也低。
发送端的发送窗口(TCP头部的窗口大小)由接收方的接收缓存大小 (流量窗口)以及 链路带宽和拥塞情况(拥塞窗口)共同决定的。
选择确认选项:接收方告诉发送方自己收 到的连续字节块。用于数据段失序到达时,发送端重复发送数据段。
时间戳选项:占10字节,包含最主要的是时间戳值字段(4字节)和时间戳回送回答字段(4字节)。
有两个作用:
A. 计算报文在两端传输层的往返时延(接近于RTT)
A发送报文时会将发送时间戳放入 timestamp(时间戳值字段), B接收到报文后将timestamp复制到timestamp echo(时间戳回显重试字段),并在返回ack报文时将当前时间戳放入timestamp。
回复报文到达A后,A可以用当前时间戳 - timestamp echo得到往返时间,而且该往返时间可认为就是RTT。
B. 防止序号回绕带来的问题
需要注意,填充的时间戳不是真实的时间戳,而是一个自增的整型,而且发送方填入的timestamp和接收方填入的timestamp可以是独立的,例如发送方填入timestamp = 5012, 接收方填入timestamp = 197720862,也就是说两端的时间戳可以不用同步。
· MSS 最大报文段大小
MSS 最大报文段数据大小,用于告诉对端,我所在的局域网链路能容纳的最大报文段的数据长度。MSS和窗口无关,和网络带宽有关。在建立TCP连接时,通信双方都要在SYN报文指明自己允许的MSS大小,MSS是双向的。
MSS可以控制TCP的传输效率,MSS太大可能导致报文段在网络层分片,太小可能导致传输效率降低(假设MSS设为1个字节,那么一个报文段的数据包含只有1个字节但头部有20个字节,你说效率低不低)。应该尽量设置MSS接近网络层一个分片的大小,使得该报文段刚好不用分片,这取决于从源主机到目的主机链路的最小MTU(MTU是网络层的包的最大长度)。
MSS + TCP头部 = TCP报文段长度。
MSS + TCP头部 + IP头部 <= MTU
(下面了解即可)
MSS默认是536字节(这也是合理的最小MSS),因为任何主机都应该至少处理576字节的IPv4数据报(含IP头部),如果按最小的IPv4和TCP头部计算,最小IPv4数据报下的最大MSS = 576 - 20 - 20 = 536。
在以太网中IPv4协议下,MSS应该设置的比较合适的值是略小于1460,因为以太网MTU=1500, 而TCP和IP头部分别为20字节,1460 + 20 +20 = 1500,刚好达到网络层不用对IP包分片的最大包大小,也刚好到达以太网链路的最大报文数据的传输大小。
在以太网中IPv6协议下,MSS应该设置的比较合适的值是略小于1440,因为IPv6的头部为40字节。