传输层两大重要协议之TCP 协议

本文详细介绍了TCP协议的基础知识,包括TCP报文段格式、确认应答机制、超时重传、连接管理(三次握手和四次挥手)、滑动窗口、流量控制和拥塞控制等关键特性。此外,还讨论了延迟应答和捎带应答在提升效率方面的作用,并解释了发送和接收缓冲区的工作原理以及如何解决粘包问题。
摘要由CSDN通过智能技术生成

1. 什么是TCP 协议

TCP,Transmission Control Protocol,传输控制协议是一种连接的、可靠的、基于字节流的传输层通信协议。在网络中负责数据能够从发送端传输到接收端。它与另一个传输层协议不同的就是它既有接收缓冲区也有发送缓冲区。

2. TCP 报文段格式

在这里插入图片描述

  1. 源端口号:表示源主机中发送数据的程序;
  2. 目的端口号:表示目的主机中接收数据的程序;
    ps:源端口号和目的端口号都属于五元组。
  3. 序号:32位;
  4. 确认号:也是32位;
  5. 4位首部长度:TCP报头长度,表示该TCP 有多少个32位bit ,TCP 头部最大长度是 15 * 4 = 60
  6. 6位标志位:

URG:紧急指针是否有效
ACK:在三次握手中确认号是否有效
RSH:提示接收端应用程序立刻从 TCP 缓冲区把数据读走 RST:要求重新建立连接,把携带 RST 标识的称为复位报文段
SYN :请求建立连接,把携带 SYN 标识的称为同步报文段
FIN:通知对方,要断开使用,把携带 FIN 标识的称为结束报文段

  1. 16位检验和:发送端填充,CRC 检验。接收端检验不通过,则数据有问题。此处检验不光包含 TCP 首部,还包含 TCP 数据部分;
  2. 16位紧急指针:标识紧急数据;

3. TCP 八大特性

3.1 确认应答机制(安全机制)

确认应答机制是一种安全机制。这种机制和序号,确认号,ACK 标志位有关。因为 TCP 报文将每个字节的数据都进行了编号,即序号。每一个 确认报文段ACK 都有对应的确认号,当主机A发送一段数据到主机B时,数据的序号是1~1000,为了确保主机B接收到了数据,主机B会回应主机A序号1001也就是 ACK 加一。意思是告诉主机A已经接收到了 1001 之前的数据,下次从1001 开始发送。这样当发送多段数据时,如果有一段数据丢失,主机B就会回应最小接收的数据段末值来告诉主机A哪段数据没有接收到。比如主机A发送序号为1 - 1000,1001 - 2000,2001 - 3000的数据,结果主机B没有接收到1001 - 2000这段数据,他就会向主机A发送 序号1001 告诉主机,从而使主机再次发送1001以后的数据。

3.2 超时重传机制(安全机制)

3.2.1 发生的情况:
主机A发送数据给主机B,可能因为网络拥堵等原因,数据无法到达主机B;
如果主机A在一个特定时间间隔内没有收到主机B发来的确认应答,就会进行重发。

3.2.2 超时的时间:
超时时间设计太长,会影响整体的重传效率;设计太短,可能会频繁发送重复的数据。所以重传的频率不是一个固定的值,在Linux系统下重传的时间是500ms,如果第一次重传还是没有接收到数据,第二次重传等待的时间是在上一次的时间基础上乘2。当发送一定次数后如果主机B还没有确认应答,主机A就会停止重传,不会无限制的重传下去。

3.3 连接管理机制(安全机制)

3.3.1 建立连接(三次握手)

在这里插入图片描述
客户端发送同步报文段SYN,请求建立连接,SYN = 1;
服务器端接收到连接请求,向客户端发送SYN确认报文 ACK;
客户端收到确认报文再次向服务器端发送确认报文ACK,建立连接成功可以开始传送数据。

3.3.2 断开连接(四次挥手)

在这里插入图片描述
客户端发送请求断开连接携带结束报文段FIN;
服务器端收到FIN,服务器返回确认报文段ACK给客户端,客户端收到服务器的确认返回报文段,开始等待服务器端结束报文段FIN;
服务器准备好断开连接,向客户端发送FIN,此时服务器等待断开;
客户端收到服务器发送的FIN,发出最后一个确认报文段ACK,进入断开连接状态。

TCP状态转换图:
在这里插入图片描述
从上面这幅图(红色线是客户端,蓝色线是服务器端)可以看出客户端从TIME_WAIT状态进入CLOSED状态需要等待一段时间,这段时间通常是2MSL。MSL 是 TCP 报文的最大生存时间,之所以需要2MSL,是为了保证在两个传输方向上的尚未被接受或迟到的报文段都已经消失,同时也是在理论上保证最后一个报文可靠到达。

3.4 滑动窗口机制(效率机制)

前面的确认应答策略,是对每一个发送的数据段都要给出一个ACK确认应答。收到ACK后再发送下一个数据段,这样一发一收有一个缺点,就是效率低,为了提高效率我们可以一次发送多条数据段。
在这里插入图片描述
滑动窗口的实现:
滑动窗口中的窗口大小指的是无需等待确认应答而可以继续发送数据的最大值。上图可以看出窗口的大小就是4097个字节(4个段)。
1.发送前四个段不需要等待ACK,直接发送。
2.收到前四个段后发出ACK,滑动窗口向后移动,继续发送第五个段的数据。
为了维护这个窗口操作系统需要开辟发送缓冲区来记录当前没有应答的数据,确认应答的数据会从缓冲区删掉。滑动窗口越大,则网络的吞吐率就越高。

3.5 流量控制机制(安全机制)

根据接收端的处理能力来控制发送端的发送速度,防止发送端发送的太快,导致接收端的缓冲区被打满,之后发送数据就会造成丢包等一系列问题。这个控制发送端的发送速度,防止缓冲区打满的机制就叫做流量控制。
在这里插入图片描述
如何进行流量控制:
1.接收端将自己可以接收的缓冲区大小放入TCP首部中的窗口中,通过ACK通知发送端;
2.当接收端发现自己的缓冲区快满了,就会将窗口大小减小成一个更小的值ACK通知给发送端;
3.发送端就收到这个窗口就会减慢自己的发送速度;
4.如果接收端缓冲区满了,就会将窗口减少为0,这时发送方不再发送数据但是会定期发送一个探测数据段,接收端会把窗口大小告诉发送端,当接收端缓冲区又有空间时继续发送。

3.6 拥塞控制机制(安全机制)

除了缓冲区打满会导致丢包等问题,网络状态拥堵发送大量数据也会导致一系列问题。所以为了解决网络问题,TCP 引入了慢启动机制,先发少量数据摸清当前的网络状态,再决定按照多大的速度传输数据。

慢启动过程

3.6.1 拥塞窗口

慢启动机制中引入了拥塞窗口,开始发送数据时,定义拥塞窗口大小为1,发送端每次接收一个ACK应答时,拥塞窗口加一倍,这样每次加一倍试探网络速度。每次发送数据包的时候,将拥塞窗口和接收端主机反馈的窗口大小做比较,取较小的值作为实际发送的窗口。
在这里插入图片描述

3.6.2 慢启动阈值

但是上面拥塞窗口的这种增长速度,是指数级别的,“慢启动”只是初始增长慢,但是增长速度非常快。为了慢启动时不增长的那么快,因此引入了慢启动的阈值,当拥塞窗口超过这个阈值时,不再按照指数方式增长而是按照线性方式增长。
在这里插入图片描述
当TCP 开始启动时,慢启动阈值等于窗口最大值;
当碰到网络拥堵的时候,慢启动阈值会变成原来的一半,同时拥塞窗口置回1。

ps:超时重传和网络拥堵的区别:少量丢包是超时重传,大量的丢包是网络拥塞。

3.7 延迟应答(效率机制)

由于 TCP 使用滑动窗口机制,所以如果每次接收数据后接收端立刻返回确认应答报文段ACK,这时返回的窗口可能就会比较小。比如接收端缓冲区为1M,一次收到500k的数据,如果立刻应答,返回的窗口就是500k;如果不立刻应答等处理端很快将这500k的数据消费了,那么缓冲区就又是1M的大小这时再应答,返回的窗口就是1M了。
在这里插入图片描述

3.7.1 延迟应答的作用

使滑动窗口越大,而窗口越大,网络吞吐量就越大,传输效率就越高。

3.7.2 延迟应答的类型

不是所有的包都可以延迟应答,延迟应答有两种限制。
数量限制:每隔N个包就应答一次;
时间限制:超过最大延迟时间(一般是200ms)就应答一次。

3.8 捎带应答(效率机制)

虽然有延迟应答,但是很多情况下客户端和服务器在应用层还是还是”一发一收”,此时就会导致数据传输效率低下,捎带应答就是接收端在给发送端发送数据的时候,捎带着向发送端发去确认应答,应答的内容是接收端已经收到发送端发送的数据。

比如:
使用捎带应答之前:
客户端:分手吗? 服务器:我收到你发的消息了(即:接收端的ACK应答) 服务器:分吧
使用捎带应答:
客户端:分手吗? 服务器:分吧(接收端给发送端发送的数据),我收到你发的消息了(即:接收端的ACK应答)

在这里插入图片描述

4. 缓冲区

4.1 发送缓冲区

  1. 发送数据时会先调用 write ,数据被写入发送缓冲区;
  2. 如果发送的数据过长,会被拆分成多个 TCP 的数据包发出;如果数据太短,就会先在缓冲区里等待,等到缓冲区里的数据差不多了,发送出去。

4.2 接收缓冲区

  1. 接收数据时会先从网卡驱动程序到达接收缓冲区;
  2. 应用程序调用 read 从接收缓冲区拿数据;

对于 TCP 的连接,既有发送缓冲区也有接收缓冲区,这个连接既可以读数据也可以写数据,这种就叫做全双工

5. 粘包问题

5.1 什么是粘包问题

粘包问题中的“包“是指应用层的数据包,在TCP的协议头部中有序号字段,这样在传输层角度,TCP 就是一个个报文传输过来的,按照序号排放在缓冲区中。但是在应用层的角度看到的却是一串连续的字节数据,应用程序不能分清是从哪个部分开始到哪个部分,所以就有了粘包问题。

5.2 解决粘包问题

明确两个数据包之间的边界。

  1. 对于定长的数据包,每次都按固定大小读取;
  2. 对于变长的数据包,可以在包头的位置约定一个包总长度的字段,从而就得到了包的结束位置;
  3. 对于变长的数据包,还可以在包与包之间使用明确的分隔符,但要保证分隔符和正文不冲突。
  • 7
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值