1.TCP 的概念
传输控制协议(Transmission Control Protocol,TCP)是一种面向连接的、可靠的、基于字节流的传输层通信协议。在 TCP 协议中,通过三次握手建立连接。通信结束后,还需要断开连接。如果在发送数据包时,没有正确被发送到目的地时,将会重新发送数据包。
⾯向连接:⼀定是「⼀对⼀」才能连接,不能像 UDP 协议可以⼀个主机同时向多个主机发送消息,也就是⼀对多是⽆法做到的;
可靠的:⽆论的⽹络链路中出现了怎样的链路变化,TCP 都可以保证⼀个报⽂⼀定能够到达接收端;
基于字节流:消息是「没有边界」的,所以⽆论我们消息有多⼤都可以进⾏传输。并且消息是「有序的」,当「前⼀个」消息没有收到的时候,即使它先收到了后⾯的字节,那么也不能扔给应⽤层去处理,同时对「回复」的报⽂会⾃动丢弃。
1. 如何理解面向连接里面的“连接”?
面向连接就是通信双方在通信时,要事先建立一条通信线路,然后进行通信。这条通信线路并不是一条实际的路,而是我们抽象出来的一条路,简单来说就是:⽤于保证可靠性和流量控制而维护的某些状态信息称为连接也可以理解成“通信线路”;这些状态信息包括Socket、序列号和窗⼝⼤⼩等。
- 套接字:由 IP 地址、端⼝号以及传输层协议(TCP或UDP)组成
- 序列号:⽤来解决乱序问题等
- 窗⼝⼤⼩:⽤来做流量控制
两个套接字可以唯一确定一个“连接”,即四元组:源IP、源端口、目的IP、目的端口。
2. TCP的功能
① 面向流的处理
TCP 以流的方式处理数据。换句话说,TCP 可以一个字节一个字节地接收数据,就像水流一样处理,而不是一次接收一个预订格式的数据块。TCP 把接收到的数据组成长度不等的段,再传递到网络层。
② 重新排序
如果数据以错误的顺序到达目的地,TCP 模块能够对数据重新排序,来恢复原始数据。
③ 流量控制
TCP 能够确保数据传输不会超过目的计算机接收数据的能力。
④ 优先级与安全
为 TCP 连接设置可选的优先级和安全级别。
⑤ 适当的关闭
以确保所有的数据被发送或接收以后,再进行关闭连接。
3. TCP 工作模式
TCP 协议的数据包进行传输采用的是服务器端和客户端模式。发送 TCP 数据请求方为客户端,接收端则为服务器端。客户端要与服务器端进行通信,服务器端必须开启监听的端口,因为TCP报文到达接收端的传输层的时候,需要找到监听端口的程序,然后交给该程序去处理,并且TCP协议规定TCP报文中必须带有目的端口,然后才能进行通信。
① 建立连接
首先基于TCP协议的应用,必须通过三次握手建立连接,即通过三次握手在通信双方的本地维护一份套接字、序列号、窗⼝⼤⼩等信息。
② 发送数据
建立好连接(维护好套接字、序列号、窗⼝⼤⼩等信息)后就可以发送信息了;发送端每次发送信息,接收端都会回复一个信息已收到的确认报文。如果接收端没有返回确认报文,发送端会继续发送。
③ 断开连接
信息发送完成后,就需要通过四次挥手断开连接(消除套接字、序列号、窗⼝⼤⼩等信息)。
4. TCP的报文格式
TCP是协议,是协议就有协议格式。
1)源端口和目的端口
TCP源端口(Source Port):源计算机上的应用程序的端口号,占 16 位。
TCP目的端口(Destination Port):目标计算机的应用程序端口号,占 16 位。
- 2)序列号
CP序列号(Sequence Number):占 32 位。它表示本报文段所发送数据的第一个字节的编号。在 TCP 连接中,所传送的字节流的每一个字节都会按顺序编号。当SYN标记不为1时,这是当前数据分段第一个字母的序列号;如果SYN的值是1时,这个字段的值就是初始序列值(ISN),用于对序列号进行同步。这时,第一个字节的序列号比这个字段的值大1,也就是ISN加1。
3)确认号
TCP 确认号(Acknowledgment Number,ACK Number):占 32 位。它表示接收方期望收到发送方下一个报文段的第一个字节数据的编号。其值是接收计算机即将接收到的下一个序列号,也就是下一个接收到的字节的序列号加1。
4)数据偏移
TCP 首部长度(Header Length):数据偏移是指数据段中的“数据”部分起始处距离 TCP 数据段起始处的字节偏移量,占 4 位。其实这里的“数据偏移”也是在确定 TCP 数据段头部分的长度,告诉接收端的应用程序,数据从何处开始。
5)保留
保留(Reserved):占 4 位。为 TCP 将来的发展预留空间,目前必须全部为 0。
6)控制/标志位
- CWR(Congestion Window Reduce)
拥塞窗口减少标志,用来表明它接收到了设置 ECE 标志的 TCP 包。并且,发送方收到消息之后,通过减小发送窗口的大小来降低发送速率。
- ECE(ECN Echo):
用来在 TCP 三次握手时表明一个 TCP 端是具备 ECN 功能的。置为1会通知通信对方,从对方到这边的网络有拥塞。
- URG(Urgent)紧急标志
表示本报文段中发送的数据是否包含紧急数据。URG=1 时表示有紧急数据。当 URG=1 时,后面的紧急指针字段才有效。
- ACK(Acknowledge Flag) 应答标志
表示前面的确认号字段是否有效。ACK=1 时表示有效。只有当 ACK=1 时,前面的确认号字段才有效。TCP 规定,连接建立后,ACK 必须为 1。
- PSH(Push)立即上传应用层标志
告诉对方收到该报文段后是否立即把数据推送给上层。如果值为 1,表示应当立即把数据提交给上层,而不是缓存起来。值为0,则不需要立即发送,可以先缓存起来。
- RST (Reset Flag) 强制重置连接标志
表示是否重置连接。如果 RST=1,说明 TCP 连接出现了严重错误(如主机崩溃),必须释放连接,然后再重新建立连接。
- SYN (Synchronize Flag) 希望建立连接标志
在建立连接时使用,用来同步序号。当 SYN=1,ACK=0 时,表示这是一个请求建立连接的报文段;当 SYN=1,ACK=1 时,表示对方同意建立连接。SYN=1 时,说明这是一个请求建立连接或同意建立连接的报文。只有在前两次握手中 SYN 才为 1。
- FIN (Fin flag) 希望断开连接标志
标记数据是否发送完毕。如果 FIN=1,表示数据已经发送完成,希望断开连接。
7)窗口大小
窗口大小(Window Size):占 16 位。它表示从 Ack Number 开始还可以接收多少字节的数据量,也表示当前接收端的接收窗口还有多少剩余空间。该字段可以用于 TCP 的流量控制。
8)校验和
校验位(TCP Checksum):占 16 位。它用于确认传输的数据是否有损坏。发送端基于数据内容校验生成一个数值,接收端根据接收的数据校验生成一个值。两个值必须相同,才能证明数据是有效的。如果两个值不同,则丢掉这个数据包。校验和是根据伪头 + TCP 头 + TCP 数据三部分进行计算的。
9)紧急指针
紧急指针(Urgent Pointer):仅当前面的 URG 控制位为 1 时才有意义。它指出本数据段中为紧急数据的字节数,占 16 位。当所有紧急数据处理完后,TCP 就会告诉应用程序恢复到正常操作。即使当前窗口大小为 0,也是可以发送紧急数据的,因为紧急数据无须缓存。
10)可选项
选项(Option):长度不定,但长度必须是 32bits 的整数倍。
格式如下:
- 选项的第一个字段kind表示选项的类型,用数字表示。有的TCP选项没有后面两个字段,仅包含1字节的kind字段
- 第二个字段length(如果有的话)指定该选项的总长度,该长度包含了kind字段和length字段占据的2字节
- 第三个字段info(如果有的话)是选项的具体信息
类型 | 对应类型占用长度 | 说明 |
0 | 选项表结束(EOP)选项,首部已经没有更多的消息,应用数据在下一个32位字开始处 | |
1 | 空操作(NOP)选项,没有特殊含义,一般用于将TCP选项的总长度填充为4字节的整数倍 | |
2 | 4 | 最大报文段长度(MSS)选项,TCP连接初始化时,通信双方使用该选项来协商最大报文段长度。TCP模块通常将MSS设置为(MTU-40)字节(减掉的这40字节包括20字节的TCP头部和20字节的IP头部)。这样携带TCP报文段的IP数据报的长度就不会超过MTU(假设TCP头部和IP头部都不包含选项字段,并且这也是一般情况),从而避免本机发生IP分片。对以太网而言,MSS值是1460(1500-40)字节。 |
3 | 3 | 窗口扩大因子选项,TCP连接初始化时,通信双方使用该选项来协商接收窗口的扩大因子。在TCP的头部中,接收窗口大小是用16位表示的,故最大为65535字节,但实际上TCP模块允许的接收窗口大小远不止这个数(为了提高TCP通信的吞吐量)。窗口扩大因子解决了这个问题。 假设TCP头部中的接收通告窗口大小是N,窗口扩大因子(移位数)是M,那么TCP报文段的实际接收通告窗口大小是N*2M,或者说N左移M位。注意,M的取值范围是0~14。我们可以通过修改 /proc/sys/net/ipv4/tcp_window_scaling 内核变量来启用或关闭窗口扩大因子选项。 和MSS选项一样,窗口扩大因子选项只能出现在同步报文段中,否则将被忽略。但同步报文段本身不执行窗口扩大操作,即同步报文段头部的接收窗口大小就是该TCP报文段的实际接收窗口大小。当连接建立好之后,每个数据传输方向的窗口扩大因子就固定不变了。 |
4 | 2 | 选择性确认(Selective Acknowledgment,SACK)选项,TCP通信时,如果某个TCP报文段丢失,则TCP会重传最后被确认的TCP报文段后续的所有报文段,这样原先已经正确传输的TCP报文段也可能重复发送,从而降低了TCP性能。SACK技术正是为改善这种情况而产生的,它使TCP只重新发送丢失的TCP报文段,而不用发送所有未被确认的TCP报文段。选择性确认选项用在连接初始化时,表示是否支持SACK技术。我们可以通过修改 /proc/sys/net/ipv4/tcp_sack 内核变量来启用或关闭选择性确认选项。 |
5 | N*8 + 2 N为发送的段数 | SACK实际工作的选项,该选项的参数告诉发送方本端已经收到并缓存的不连续的数据块,从而让发送端可以据此检查并重发丢失的数据块。每个块边沿(edge of block)参数包含一个4字节的序号。其中块左边沿表示不连续块的第一个数据的序号,而块右边沿则表示不连续块的最后一个数据的序号的下一个序号。这样一对参数(块左边沿和块右边沿)之间的数据是没有收到的。因为一个块信息占用8字节,所以TCP头部选项中实际上最多可以包含4个这样的不连续数据块(考虑选项类型和长度占用的2字节)。 |
8 | 10 | 时间戳选项,该选项提供了较为准确的计算通信双方之间的回路时间(Round Trip Time,RTT)的方法,从而为TCP流量控制提供重要信息。我们可以通过修改 /proc/sys/net/ipv4/tcp_timestamps 内核变量来启用或关闭时间戳选项。 |