🎬慕斯主页:修仙—别有洞天
♈️今日夜电波:マリンブルーの庭園—ずっと真夜中でいいのに。
0:34━━━━━━️💟──────── 3:34
🔄 ◀️ ⏸ ▶️ ☰
💗关注👍点赞🙌收藏您的每一次鼓励都是对我莫大的支持😍
目录
TCP协议再认识
我们都知道TCP协议叫做:"传输控制协议(Transmission Control Protocol") 。TCP正人如其名, 要对数据的传输进行一个详细的控制。
TCP在操作系统内也就是应用层往下传输层中内部是拥有自己的发送缓冲区和接收缓冲区的。当建立了一个新的链接就会建立对应的发送缓冲区和接收缓冲区。我们自定义在应用层的缓冲区则称为用户缓冲区。实际上我们之前所说的使用write和read像文件一样读写,不是直接从网络中写和读。而是将用户级的缓冲区写入发送缓冲区,从接收缓冲区中读取。本质上都是拷贝的过程!至于什么时候发送什么时候接收,发多少收多少,怎么保障数据安全都是由TCP协议来控制的!大致图示如下:
本质上这同我们之前学的文件系统是一样的,都是按照一定的规则将用户级的缓冲区拷贝到系统级的缓冲区,再由系统级拷入磁盘,只不过这里是拷入网卡。发送和接收数据本质上就是经过网络从另一方的发送缓冲区拷贝到接收缓冲区。
TCP协议段格式
TCP报文也是由报头+有效载荷组成的,报头的长度由规定和上图可知为20字节。TCP是如何将报头和有效载荷分离的呢?这和UDP是一样因为报头都是固定大小的。因此,将报头的20字节分离即可得到有效载荷。那他是如何交付给上层的呢?当然也是通过源端口号和目标端口号来确认的。接下来我们详细分析下面我们在报头内没见过的几部分字段:
选项
TCP协议段中的选项部分是为了适应复杂的网络环境和更好地为应用层服务而设计的。这些选项为TCP连接提供了额外的配置和特性支持。下面是一些TCP协议段中常见的选项及其详解:
- 最大报文段长度(MSS):MSS是TCP最初规定的一种选项,它规定了TCP报文数据部分的最大长度。这个长度是去除了TCP首部后的数据部分的最大长度,可以理解为传输层TCP的“MTU值”。在TCP连接建立时,通信双方会将自己能够支持的MSS写入这一字段,以后就按照这个数值传送数据。如果没有设置这个值,那么MSS会取默认值,通常为536字节。
- 窗口扩大因子:这个选项用于扩大TCP的窗口大小,从而允许更大的数据流量,提高网络吞吐量。
- 时间戳:时间戳选项用于帮助TCP实现更精确的往返时间(RTT)测量和防止序列号回绕问题。它包含了一个发送时间戳和一个接收时间戳。
- 选择确认(SACK):SACK选项允许接收方发送关于丢失报文段的确认信息,而不是仅仅确认最后一个连续接收到的报文段。这使得发送方能够更精确地重传丢失的报文段,提高了传输效率。
- 无操作(NOP):NOP选项是1字节的,用作选项之间的填充,可以多次使用。
- 选项结束(EOF):EOF选项也是1字节的,用于在选项区的结尾处进行填充,表示首部中没有更多的选项了,并且从应用程序传递来的数据开始于下一个32位字开始的地方。它只能用作最后一个选项,并且只允许出现一次。
除了上述常见的选项外,TCP协议段还可能包含其他选项,这些选项通常用于实现一些特殊的网络功能或优化性能。不同的操作系统和网络环境可能会对TCP选项的实现和支持有所不同。如:客户端与服务端建立了链接,但是这个链接长时间不过也不发数据,所以操作系统会保证链接在一定时间自动断开。
需要注意的是,TCP选项是可选的,并且它们的存在和顺序是由发送方根据需要来确定的。接收方在解析TCP报文段时,必须能够正确识别和处理这些选项,以确保数据的正确传输和连接的正常运行。
4位首部长度
TCP协议段中的4位首部长度是用来表示TCP协议报头长度的。这个字段只有4位,所以其取值范围是0101到1111。由于这4位表示的是以4字节为单位的长度,因此TCP协议报头的最大长度是15 * 4 = 60字节。
如果TCP协议不带选项,那么4位首部长度就应该是0101,对应的十进制值是5,代表的标准长度是5 * 4 = 20字节。这20字节是TCP的固定长度,包括源端口、目的端口、序号、确认号、数据偏移、保留、标志、窗口、校验和、紧急指针等字段。
当TCP协议带上选项时,报头长度就会超过20字节。此时,选项的长度就是4位首部长度的值减去标准长度的值。选项是可以选择带或不带的,它是TCP协议提供的一种灵活机制,用于适应不同的网络环境和需求。因此,报头的取值范围为[20,60]。TCP数据部分的大小则取决于可用窗口大小、拥塞控制算法以及其他因素。
需要注意的是,TCP协议的具体实现可能因操作系统和网络环境的不同而有所差异,但基本的报头长度和选项机制是相似的。
如何保证TCP的可靠传输?确认应答机制
TCP在通信的时候,难免会发送丢包、乱序、发送速度太快使得缓冲区满了、重复等等状况,那么如何保证数据的可靠传输呢?这就引出了确认应答机制:
也就是说:我给你发送了一个报文,你需要对这个报文进行确认并且返回确认收到的报文(需要注意的是:他们都是TCP格式的报文,不管是否带有数据至少拥有完整的报头)但是我又怎么保证一定能收到对方一定能把报文发送给我,并且我能收到呢?因此只要我收到了应答,那么对方一定是收到了,我没有收到报文那么我就认为报文丢失了,我会再给你发报文,直到我收到应答。
32位序号和确认序号
通过上面对于应答机制的认识,我们发现如果只是一个发一个返回信息应答那么效率也太低了,因此我们可能会一次性向对方发大量的数据,当然也会收大量的数据。但是这样引出了几个问题:(1)发的顺序不一定是收的顺序。(2)不能确认应答报文和发送报文对应关系。 因此,需要给报文加上编号,也就是在报头中需要包含序号!
TCP协议段中的32位序号和确认序号是TCP协议中非常重要的两个字段,它们共同确保了TCP数据传输的可靠性和有序性。
首先,32位序号表示的是该报文段所发送数据的第一个字节的编号。TCP连接中所传输字节流的每一个字节都会按顺序编号。每发送一次数据,序号就会累加一次。当序号达到2^32时,会发生回绕,序号重新从0开始。这样的设计使得TCP能够处理乱序到达的数据包,并且能够精确地识别丢失或重复的数据包。
而确认序号则是接收方期望收到发送方下一个报文段的第一个字节数据的编号。也就是说,确认序号告诉发送方:我希望你下次发送的数据的第一个字节数据的编号为此确认号。只有当ACK(后续详细介绍)标志为1时,确认序号才有效。发送端收到确认应答后,代表确认序号之前的数据都已经被正常接收。如下图所示:
TCP将每个字节的数据都进行了编号. 即为序列号.
每一个ACK都带有对应的确认序列号, 意思是告诉发送者, 我已经收到了哪些数据; 下一次你从哪里开始发.
需要特别注意的是:如果在确认应答时,中间的“应答报文”丢失了,但是他后面的报文收到了那么后面报文往前的信息都会认为已经收到了。因为确认序号认为他之前的序号都是已经接受成功了的。比如:客户端发送了1~1000、1001~2000、2001~3000.。如果其中的1001~2000并没有收到,那么返回的确认报文中为1001。大致图示如下:
在TCP的数据传输过程中,发送方会不断发送数据,并等待接收方的确认。接收方每收到一个报文段,就会发送一个确认报文,告诉发送方已经成功接收到的数据的序号。这样,发送方就可以根据接收方的确认序号,知道哪些数据已经被成功接收,哪些数据还需要重传。
总的来说,32位序号和确认序号是TCP协议中保证数据传输可靠性和有序性的关键机制。它们共同协作,确保数据能够按照正确的顺序、无丢失地传输到目的地。
为什么32位序号和32位确认序号在不同的字段?
我们都知道TCP是全双工的。那么当客户端发送报文给服务器,服务器在应答时为什么仅仅就只发一个应答报文,而不是带上数据返回呢?这样难道不会提高通信效率吗?而32位序号和32位确认序号的设计就在这里。这种报文也叫做捎带应答!为了保证32位序号和32位确认序号同时存在所以需要在不同的字段。
16位窗口大小
应用层和传输层之间有着如下的系统调用接口:send、write、read、recv。
我们如果使用如上的接口在用TCP发送数据是发送的太快,那么系统的缓冲区很快就被填满了,那么后续没收到的报文就会被丢弃。虽然TCP会重传,但是这也太浪费网络资源和效率了。因此,我们需要控制发送的速度,该快的时候快,该慢的时候慢!这种策略叫做流量策略。发送方发送的数据大小、数据快慢是受到接收方能接收多少来控制的,这取决于接收方的缓冲区剩下的空间。因此,每个报文都会应答自己的接收能力,这就是16为窗口大小。
TCP协议段中的16位窗口大小字段用于表示接收端期望接收的下一个字节的序号,同时也反映了接收端的缓冲区剩余空间大小。这个字段是TCP流量控制的关键部分,由连接的每一端通过声明的窗口大小来提供。窗口大小的起始值是基于确认序号字段指明的值,即接收端正期望接收的字节。
窗口大小字段是一个16位的字段,因此其最大值为65535字节。这个字段的大小限制了TCP在一次传输中可以发送的数据量,从而实现了发送方和接收方之间的流量控制。
在TCP连接建立之初,发送方通常从一个较小的窗口开始发送数据,然后根据接收方的ACK响应逐渐增大窗口大小。这个过程通过TCP的慢启动机制来实现,发送窗口大小最初会成指数增长(每次是之前的2倍),但是一旦发生丢包,发送窗口大小将会减少到一个包的大小,之后再次指数级增长直到之前发生丢包时发送窗口大小的一半。此后,发送窗口大小会由指数增长变为线性增长。
这种动态调整发送窗口大小的方式,可以根据网络状况实时调整数据传输速率,从而提高数据传输效率,同时避免网络拥塞。因此,16位窗口大小字段在TCP协议中扮演着至关重要的角色,是确保TCP数据传输可靠性和效率的重要机制之一。
六个标志位
六个标记位的功能为的是区分TCP报文的类型,对于不同报文将会有不同的处理动作。TCP协议段中的六个标志位各自承载着不同的功能,它们在TCP通信过程中起着至关重要的作用。需要注意的是:每个标志位仅占1bit。下面是对这六个标志位的详细解释:
- URG(紧急)标志位:
- 当URG=1时,表示TCP报文段中有紧急数据,应尽快传送,此时紧急指针字段有效。它告诉系统此报文段中有紧急数据,应尽快传送(相当于按“紧急呼叫”)。
- 紧急指针是一个正的偏移量,和序号字段中的值相加表示紧急数据最后一个字节的序号。TCP的紧急方式是发送端向另一端发送紧急数据的一种方式。
当设置URG为1时,意味着这个报文中含有紧急数据,报文中的字段16为紧急指针将会有效,紧急指针表示的是该报文数据中紧急数据的偏移量。而这个紧急数据的大小为1字节。可以通过设置send中的flags参数为MSG_OOB,recv也设置为MSG_OOB来接收。
- ACK(确认)标志位:
- 仅当ACK=1时确认号字段才有效。当ACK标志位为1时,确认号字段有效,TCP规定,在连接建立后所有传送的报文段都必须把ACK置为1。
- TCP报文段一旦发送,则启动一个定时器,等待对方的确认。如果在规定时间内未收到对方的确认,则重发此报文段。
- PSH(推送)标志位:
- 当PSH=1时,接收端TCP应尽快地交付给应用进程。发送方TCP把PSH置为1,并请求接收方TCP在收到该报文段后就把数据立即传送给接收应用程序,而不是等到缓冲区满后再传送。
- PSH标志位适用于交互式应用,如telnet或rlogin等。在这些应用中,需要尽可能地减少数据的传输延迟。
- RST(复位)标志位:
- 用于复位那些产生错误的连接,也被用来拒绝错误和非法的数据包。当RST=1时,表明TCP连接中出现严重差错(如由于主机崩溃或其他原因),必须释放连接,然后再重新建立运输连接。
- RST标志位还可以用来拒绝一个无效的数据段或拒绝一个连接请求。
- SYN(同步)标志位:
- 用来建立连接。当SYN=1而ACK=0时,表明这是一个连接请求报文段。对方若同意建立连接,则应在应答的报文段中使SYN=1和ACK=1。因此,SYN置为1就表示这是一个连接请求或连接接受报文。
- SYN标志位和ACK标志位搭配使用,共同参与了TCP的三次握手过程,确保连接的可靠建立。
- FIN(结束)标志位:
- 用来释放一个连接。当FIN=1时,表明此报文段的发送端的数据已发送完毕,并要求释放运输连接。
- 在TCP的四次断开过程中,FIN标志位被用来通知对方本端已经完成了数据的发送,准备关闭连接。虽然对应的端口仍处于开放状态,准备接收后续数据,但实际上已经没有数据需要发送了。
这六个标志位协同工作,确保了TCP协议在复杂多变的网络环境中能够实现可靠的数据传输和连接管理。
超时重传机制
主机A发送数据给B之后, 可能因为网络拥堵等原因, 数据无法到达主机B;
如果主机A在一个特定时间间隔内没有收到B发来的确认应答, 就会进行重发;但是, 主机A未收到B发来的确认应答, 也可能是因为ACK丢失了;
因此主机B会收到很多重复数据. 那么TCP协议需要能够识别出那些包是重复的包, 并且把重复的丢弃掉.去重的效果. 这时候我们可以利用前面提到的序列号
那么, 如果超时的时间如何确定?
最理想的情况下, 找到一个最小的时间, 保证 "确认应答一定能在这个时间内返回".但是这个时间的长短, 随着网络环境的不同, 是有差异的.如果超时时间设的太长, 会影响整体的重传效率;如果超时时间设的太短, 有可能会频繁发送重复的包;
TCP为了保证无论在任何环境下都能比较高性能的通信, 因此会动态计算这个最大超时时间.
Linux中(BSD Unix和Windows也是如此), 超时以500ms为一个单位进行控制, 每次判定超时重发的超时时间都是500ms的整数倍.如果重发一次之后, 仍然得不到应答, 等待 2*500ms 后再进行重传.如果仍然得不到应答, 等待 4*500ms 进行重传. 依次类推, 以指数形式递增.累计到一定的重传次数, TCP认为网络或者对端主机出现异常, 强制关闭连接。
感谢你耐心的看到这里ღ( ´・ᴗ・` )比心,如有哪里有错误请踢一脚作者o(╥﹏╥)o!
给个三连再走嘛~