TCP(Transmission Control Protocol,传输控制协议)是互联网传输层协议之一,也是 TCP/IP 协议簇的核心协议。它的作用是在 IP 网络上提供可靠的、面向连接的通信。
TCP基本特点: 有链接,可靠传输, 面向字节流 ,全双工
TCP协议段格式
- 源端口和目的端口:标识源和目标应用程序的端口号;
- 序列号:用于对TCP流中的字节进行编号,保证数据的顺序传输;
- 确认号:用于确认已经接收的数据的序列号;
- 4位TCP报头长度:表示该TCP头部有多少个32位bit(有多少个4字节);(TCP头部最大长度是15*4=60)
- 6位标志位:
- URG: 紧急指针是否有效, 当URG标志位被设置时,表示在TCP数据中有紧急数据需要尽快传送。
- ACK: 确认号是否有效, 当ACK标志位被设置时,表示确认号字段中的值为有效的确认号,表示接收方已经成功接收到的数据。
- PSH: 提示接收端应用程序立刻从TCP缓冲区把数据读走
- RST: 对方要求重新建立连接; 携带RST标识的称为复位报文段
- SYN: 请求建立连接; 携带SYN标识的称为同步报文段
- FIN: 通知对方本端要关闭了; 携带FIN表示的称为结束报文段
- 窗口大小:接收方的接收窗口大小,用于流量控制
- 校验和:用于验证TCP头部和数据的正确性
- 紧急指针: 标识哪部分数据是紧急数据
- 选项:可选字段,可以包括最大段大小、时间戳等信息。
TCP核心机制
确认应答
确认应答的过程是在TCP建立连接时使用的一种机制,用于确保数据的可靠传输。确认应答通过ACK标志位来实现。
TCP将每个字节的数据都进行了编号,即序列号. 每一个ACK都带有对应的确认序列号, 表示已经成功接收到发送方的数据。发送方收到该确认数据段后,会根据接收方发送的确认号更新自己的发送窗口,并根据需要继续发送数据。
超时重传
主机A发送数据给B后,可能因为网络拥堵等原因,导致数据无法到达B;
如果A在一个特定的时间间隔没有收到B发来的确认应答, 就会进行重发;(A没有收到确认应答也可能是因为B发送的ACK丢失了)
如上图,B会受到很多重复数据,TCP协议就会根据序列号,识别出哪些是重复的,并把重复的去掉,利用序列号,就可以很容易的做到去重的效果
此外,网络传输中还会出现 "后发先至" 的问题,也可以通过序列号来进行解决
"特定的时间间隔"如何确定?
- 最理想的情况,找到一个最小的时间,保证"确认应答一定能在这个时间返回"
- 时间长短随网络环境不同存在差异
- 超时时间设的太长,会影响整体的重传效率
- 超时时间设的太短,可能会频繁发送重复的包
TCP为了保证无论在任何环境下都能比较高性能的通信,因此会动态计算这个最大超时时间
Linux(BSD Unix / Windows)中,超时以500ms为一个单位进行控制, 每次判定超时重发的超时时间都是500ms的整数倍.(如果重发一次之后,仍然得不到应答,等待2*500ms再重传,如果仍然得不到应答,等待4*500ms...以此类推进行递增)累积到一定重传次数后,TCP就会认为网络或者对端主机出现异常,并强制关闭连接
确认应答 和 超时重传 , 相互补充 , 共同构建了TCP "可靠传输机制"
连接管理
建立连接:"三次握手"
- 第一步:客户端向服务器发送连接请求报文段(SYN)。
- 第二步:服务器收到请求后,回复客户端一个连接确认报文段(SYN+ACK)。
- 第三步:客户端收到确认后,再次向服务器发送一个确认报文段(ACK),完成连接建立。
三次挥手的意义
- "投石问路",初步验证通信链路是否畅通
- 确认双方各自的发送能力和接受能力是否都正常
- 让通信双方在进行通信之前,对通信过程中需要用到的一些关键参数进行协商
断开连接:"四次挥手"
- 第一步:客户端向服务器发送连接释放请求报文段(FIN),表示客户端不再发送数据。
- 第二步:服务器接收到连接释放请求后,向客户端发送一个确认报文段(ACK)作为确认。
- 第三步:服务器完成数据传输后,向客户端发送一个连接释放请求报文段(FIN),表示服务器也准备关闭连接。
- 第四步:客户端接收到连接释放请求后,回复服务器一个确认报文段(ACK),确认服务器的关闭请求。
三次握手,三次是因为中间两次交互合并在一起了,而对于四次挥手来说,中间两次,大概率是不能合并的
- 对于三次握手来说: 中间的两次 ACK+SYN,都是在内核中,由操作系统负责进行的
- 对于四次挥手来说: ACK是内核控制的,但是SYN的触发则是通过应用程序,调用close/进程退出,来触发的
(次数,指的就是网络通信的次数,"握手/挥手",传输一个不携带任何业务数据(载荷)的数据报)
TCP状态汇总
- 粗虚线表示服务端的状态变化情况
- 粗实线表示客户端的状态变化情况
- CLOSED是一个假想的起始点,不是真实状态
-
CLOSED: 初始状态,表示TCP连接处于关闭状态。
-
LISTEN: 服务器处于监听状态(绑定好端口,初始化完毕),等待客户端连接请求。
-
SYN_SENT: 客户端发送了连接请求(SYN),等待服务器的确认。
-
SYN_RECEIVED: 服务器接收到客户端的连接请求,并发送确认(SYN+ACK)。
-
ESTABLISHED: 连接已建立,双方可以进行数据传输。
-
FIN_WAIT_1: 客户端发送连接关闭请求(FIN),等待服务器的确认。
-
CLOSE_WAIT: 服务器收到客户端的关闭请求,等待关闭连接。
-
FIN_WAIT_2: 客户端收到服务器的确认,等待服务器发送关闭请求。
-
LAST_ACK: 服务器发送关闭请求,等待客户端的确认。
-
TIME_WAIT: 连接已关闭,等待一段时间(2倍的最长报文段寿命(2MSL))以确保所有报文都已被接收
-
CLOSED_WAIT: 服务器在关闭连接之后,接收到来自客户端的数据。
为什么TIME_WAIT的时间是2MSL?
TIME_WAIT持续存在2MSL,能保证在两个传输方向上的尚未被接收或迟到的报文段都已经消失(否则服务器立刻重启,可能会收到来自上一个进程的迟到的数据,但是这种数据很可能是错误的). 同时也是在理论上保证最后一个报文可靠到达(假设最后一个ACK丢失,那么服务器会重发一个FIN,这时虽然客户端的进程不在了,但是TCP连接还在,仍然可以重发LAST_ACK)
服务器上出现大量CLOSE_WAIT状态是为啥?
服务器没有正确关闭socket,导致四次挥手没有正确完成,排查close是否写了以及是否及时的执行到了
滑动窗口
确认应答策略,对每个发送的数据段,都给了一个ACK确认应答,收到ACK后再发送下一个数据段. 这样做有一个比较大的缺点:影响性能
这样一发一收的方式性能较低,那么一次发送多条数据,就可以提高性能(把多次等待ACK的时间合并成一段时间)
- 窗口大小指的是无需等待确认应答就可以继续发送数据的最大值(上右图窗口大小就是4000个字节)
- 发送前四个段时不需要等待任何ACK,直接发送
- 收到第一个ACK后,滑动窗口向后移动,继续发送第五个段的数据,以此类推
- 操作系统内核为了维护这个滑动窗口,需要开辟发送缓冲区来记录当前还有哪些数据没有应答,只有确认应答过的数据,才能从缓冲区删掉
- 窗口越大,网络的吞吐率越高
如果出现丢包,如何进行重传?
情况一:数据包抵达,ACK丢了
部分ACK丢了,可以通过后续的ACK进行确认(如上图,1001ACK丢了,但是2001ACK收到了,此时认为2001之前的数据都已经收到了)
情况二:数据包直接丢了
当某一段报文段丢失之后,发送端会一直受到1001ACK,就像是在提醒发送端"我想要的是1001". 如果发送端主机连续三次都收到了同样"1001"这样的应答,就会将对应的1001-2000重新发送. 这个时候接收端收到了1001之后,再次返回的ACK就是7001(2001-7000接收端已经收到了,被放到了接收端操作系统内核的接收缓存区中),这种机制被称为"高速重发机制",也叫"快重传"
流量控制
虽然滑动窗口能够高效可靠的发送大量数据,但是通信是发送端和接受端两个"人"的事,发送端发的太快,导致接收端的缓冲区被塞满了,此时继续发送就会导致丢包,此时就需要根据接收方处理数据的能力,制约发送方的发送速度.
当接收方的接收缓冲区有足够的空间时,可以扩大接收窗口的大小,发送方可以发送更多的数据。当接收方的接收缓冲区不足以容纳更多的数据时,可以缩小接收窗口的大小,发送方必须减缓发送速率,以避免数据丢失或者缓冲区溢出。
TCP中,接收方收到数据的时候,就会把接受缓冲区剩余空间大小通过ACK数据报反馈给发送方,这样发送方就可以依据这个数据来设置发送的窗口大小了
- 接收端将自己可以接收的缓冲区大小放入TCP首部中的"窗口大小"字段,通过ACK端统治发送端
- 窗口大小字段越大,说明网络的吞吐率越高
- 接收端一旦发现自己的缓冲区快满了,就会将窗口大小设置成一个更小的值通知给发送端
- 发送端接收到这个窗口之后,就会减慢自己的发送速度
- 如果接收端缓冲区满了,就会将窗口置为0.这时发送方不再发送数据,但是需要定期发送一个窗口探测数据段,是接收端把窗口大小告诉发送端
TCP首部中,有一个16位窗口字段,就是存放了窗口大小信息.16位数字最大表示65535,但并不代表TCP窗口大小最大就是65535字节,TCP首部40字节选项中还包含了一个窗口扩大因子M,实际窗口大小是窗口字段的值左移M位
拥塞控制
慢启动
发送方在开始传输数据时,以指数级增加发送窗口的大小,以快速适应网络的带宽。当发送方检测到网络拥塞时,会触发拥塞避免算法。
慢启动的过程如下:
- 刚开始传输数据,拥塞窗口会非常小,用一个很小的速度来发送数据
- 不丢包,增大窗口大小.进行指数增长
- 增长到一定程度,达到一个阈值(拥塞窗口阈值),此时即使没丢包,也会停止指数增删,变为线性增长
- 线性增长,也会持续使发送速度越来越快,达到某个情况下,出现丢包。
- 出现丢包,减小发送速度,减小窗口大小(两种处理方式)
- 已废弃方案:从头开始,回归慢启动最开始的阶段,重复1-4过程
- 现在的方案:回到新的阈值上,进行线性增长
在慢启动阶段,发送方会指数级地增加发送窗口的大小,从而增加数据的发送速率。慢启动阶段的目的是通过快速增加发送窗口的大小,迅速探测网络的可用带宽。但同时,慢启动也有一定风险,如果发送方过快地增加发送窗口的大小,可能会导致网络拥塞。因此,TCP协议中还包括了拥塞避免和快速重传等机制,以便在网络拥塞时减小发送速率。
延迟应答
在TCP协议中,接收方在接收到数据后会向发送方发送一个确认报文,告知发送方已经成功接收到数据。通常情况下,接收方应该立即发送确认报文,以便发送方可以根据确认报文来判断是否需要重传数据。
然而,延迟应答机制允许接收方推迟发送确认报文。当接收方收到数据后,并不立即发送确认报文,而是等待一段时间,看是否有其他数据到达。如果在这段时间内没有其他数据到达,接收方会发送确认报文。
延迟应答机制的优势在于可以减少网络中的确认报文的数量。当接收方连续收到多个数据包时,可以将这些数据包合并在一个确认报文中发送,从而减少了网络中的开销。这对于网络拥塞控制尤为重要,因为减少确认报文的数量可以减小网络的负载,并减少网络拥塞的可能性。
然而,延迟应答机制也存在一些风险。当接收方延迟发送确认报文时,发送方可能会误认为数据丢失了而进行重传,从而增加了网络的负载。此外,如果发送方也使用了延迟确认机制,那么两端可能会出现长时间的等待,导致数据传输的延迟。因此,延迟应答机制需要在实际应用中根据网络条件和性能要求进行合理调整。
捎带应答
在TCP协议中,默认情况下,发送方每收到一个数据包,都会立即发送一个确认报文来告知接收方数据已经正确接收。
为了减少网络中的确认报文的数量和降低延迟,TCP协议允许在发送数据包时,将之前接收到但尚未确认的数据包的确认报文捎带在当前的数据包中一起发送。这样,接收方在收到数据包时,可以从中提取出确认报文,同时处理数据。
使用捎带应答的好处是可以有效减少网络中的确认报文的数量,从而降低网络的负载。此外,将确认报文和数据捎带在一起发送,可以避免额外的延迟,因为确认报文可以在正常的数据传输过程中被接收方处理。
正常情况下,ack和响应是不同的时机,无法合并,但是,由于"延时应答"机制,ack返回的时间会被往后拖,就可能和发送响应的操作是同时的,此时发送响应就会把ack也带上
面向字节流
- 数据被视为一连串的字节流,而不是离散的消息或数据包。
- 数据是按照一定的顺序传输的,接收方按照接收到的顺序将数据复原。
- 数据传输是可靠的,发送方会自动重传丢失的数据,确保数据的完整性和正确性。
粘包问题
粘包问题指的是在网络通信中,发送方连续发送了多个小数据包,接收方却一次性接收到了多个数据包,导致数据包粘在一起的现象。
造成粘包问题的主要原因有以下几点:
- TCP协议中的滑动窗口:TCP协议使用滑动窗口机制来控制发送和接收数据的速率,发送方可能会在一个滑动窗口内发送多个数据包,而接收方可能一次性接收到多个数据包。
- 操作系统缓冲区:发送方和接收方的操作系统都有自己的缓冲区,数据可能会在缓冲区中进行累积,导致接收方一次性读取到多个数据包。
- 应用程序处理速度不一致:发送方和接收方的应用程序处理数据的速度可能不一致,导致发送方发送的数据包在接收方处形成粘连。
粘包问题可能会导致接收方无法准确地识别和处理每个数据包,造成数据处理错误或解析错误。为避免粘包问题,可以采取以下几种方式:
- 定长包:发送方发送固定长度的数据包,接收方按照固定长度进行数据拆包,无需考虑粘包问题。
- 分隔符包:发送方在每个数据包的末尾添加特定的分隔符,接收方根据分隔符进行数据拆包。
- 基于长度的包:发送方在每个数据包的头部添加表示数据长度的字段,接收方先根据数据长度字段读取数据长度,然后根据长度读取相应长度的数据。
除了以上方法,还可以使用应用层协议来解决粘包问题,例如在数据包中添加消息头和消息尾,通过解析消息头和消息尾来准确识别每个数据包。
总之,解决粘包问题需要在发送方和接收方之间进行协议设计和数据处理的优化,保证数据的精确传输和正确解析。
异常情况
进程终止:进程终止会释放文件描述符,仍然可以发送FIN,和正常关闭无区别
TCP总结
可靠性:
- 校验和
- 序列号(按序到达)
- 确认应答
- 超时重发
- 连接管理
- 流量控制
- 拥塞控制
提高性能:
- 滑动窗口
- 快速重传
- 延迟应答
- 捎带应答
定时器:超时重传定时器,保活定时器,TIME_WAIT定时器等
基于TCP应用层协议:
- HTTP
- HTTPS
- SSH
- Telnet
- FTP
- SMTP
- 自定义