传输层协议之TCP协议详解

传输层重点协议:UDP和TCP。

作用:负责数据能够从发送端传输到接收端。(在进行网络编程时,我们会使用到socket,然而一旦调用socket就进入到了传输层的范畴内)

前面我们已经讲过UDP协议了,这次我们来讲解什么是TCP协议,TCP协议有哪些特点。

TCP协议

传输控制协议(TCP,Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议。传输控制协议,顾名思义就是要对数据的传输进行一个详细的控制

TCP协议段格式

  • 源/目的端口号:表示数据是从哪个进程来的,要到哪个进程去

端口号:整数。0~65535之间的整数。
知名端口号:把0~1024这些端口号给具体划分了一些具体的作用。(80:http服务器;443:https服务器等)
  • 32位序号/32位确认号:表示对接收到对方曾经发送过的TCP报文的确认

  • 4位TCP报头长度:表示该TCP头部有多少个32位bit(有多少个4字节)。TCP报头的最大长度是15*4=60

  • 6位标志位(TCP报文的核心字段)

  1. URG:紧急指针是否有效

  1. ACK:确认号是否有效

  1. PSH:提示接收端应用程序立刻从TCP缓冲区把数据读走

  1. RST:对方要求重新建立连接;将携带RST标识的称为:复位报文段

  1. SYN:请求建立连接;将携带SYN标识的称为:同步报文段

  1. FIN:通知对方,本端将要关闭;将携带FIN标识的称为:结束报文段

  • 16位窗口大小:保证TCP可靠性机制和效率提升机制的重要字段

  • 6位保留字段:TCP报头中暂时未使用的6个比特位,不确定什么时候会用到

  • 16位校验和:发送端填充,CRC校验。接收端校验不通过,则认为数据有问题。此处的校验和不光包含TCP首部,也包含TCP数据部分

  • 16位紧急指针:标识哪部分数据是紧急数据

TCP如何将报头与有效载荷进行分离:

当我们获取到TCP报文后,首先对报文的前20个字节进行读取操作,同时从其中提取出4位的首部长度,此时就获得了TCP报头的长度大小,在读取完TCP的基本报头和选项字段后,剩下的就是该TCP报文的有效载荷了。

TCP原理

TCP对数据传输提供的管控机制,主要体现在两个方面:安全与效率。

这些机制的原则:保证数据传输安全的前提下,尽可能的提高传输效率

安全机制

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

确认应答机制是保证可靠传输的核心机制

关键:接收方收到消息后,给发送方返回一个应答报文。

可靠指的是:发送方发送出数据后,能知道这个数据是否送到了,也就是说接收方是否收到了这个数据。

这是同一个TCP数据报,这个数据报通过层层封装,变成了一个以太网数据帧,然后进行传输。

数据(1~1000):A给B发送了1000个字节,序号是1~1000;

确认应答(下一个是1001):B给A返回的应答报文(ACK)就会带有一个确认序号叫做1001,表示下一次应该从1001开始发送了。

这样一来一回直到数据发送完毕。

TCP对每个字节的数据都进行了编号,这个编号我们称呼为“序列号”。

每一个ACK都带有对应的确认序列号,意思是告诉发送方,已经接收到了哪些数据,下一次该从哪里开始发送。

表示当前这个应答报文是针对哪个消息进行的确认应答。

关于序号和确认序号:

任何一条数据(包括应答报文)都是有序号的。

确认序号是只要应答报文有的(普通报文确认序号字段里的值是无意义的)。

先发后发的情况:如果传了多个数据报,分装成了多个以太网数据帧,多个数据帧之间才会出现先发后发的情况。

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

相当于是对确认应答机制进行了补充。

确认应答是网络一切正常的时候,通过ACK通知发送方,我已经接收到了。如果出现了丢包的情况,超时重传机制就要发挥作用了。

主机A发送数据给B后,由于某些原因(网络拥堵等)数据无法到达主机B;

如果主机A在一个特定时间间隔内没有收到B发来的确认应答,就会进行重发。

主机A未收到主机B发来的确认应答还有一种情况:ACK丢了。

这种情况下,主机B会收到很多重复的数据。此时就需要TCP能够设别出哪些包是重复的包,并且将重复的包丢弃掉。

TCP内部有一个去重操作

接收方收到数据会先放到操作系统内核的“接收缓冲区”中,接收缓冲区可以视为是一个内存空间吗,也可以视为是一个阻塞队列。

收到新的数据报,TCP会根据序号来检查这个数据在接收缓冲区是否已经存在了,如果存在了,直接丢弃。如果不存在,就放进去。保证应用程序调用socket api拿到的这个数据一定是不重复的。

去重的问题,我们已经解决了。再考虑一下,如何确定这个超时的时间???

  • 最理想状况下,找到一个最小的时间,保证“确认应答一定能在这个时间内返回”

  • 这个时间的长短随着网络环境的不同是有差异的,如果设置的太长会影响整体重传的效率;设置的太短可能会频繁发送重复的包。

  • TCP为了保证无论在任何环境下都能有比较高校性能的通信,会动态计算这个最大超时时间。

  • 在很多操作系统中(linux,windows和BSD unix),超时以500ms为有一个单位进行控制,每次判定重发的超时时间是以500ms的整数倍。如果重发一次仍没有应答,等待2*500ms后再进行重传。以此类推,以指数形式递增。

  • 累计到一定的重传次数,TCP会认为网络或对端主机出现异常,强制关闭连接(自动断开TCP的连接)

超时重传的数据不一定能重传成功。

操作系统具体重传几次才放弃?操作系统超时时间每次增加多少??这些都是可以配置的。

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

也是TCP保证可靠性的机制。描述了连接如何创建,又如何断开。

在正常情况下,TCP要经过三次握手建立连接,四次挥手断开连接。

此处对于三次握手四次挥手只是简单提到,后面会有单独讲解。

流量控制(安全机制)

关键:能够衡量接收方的处理速度。是滑动窗口的延申,目的是为了保证可靠性。

此处直接使用接收方接收缓冲区剩余空间的大小,来衡量当前的处理能力。

接收端处理数据的速度是有限的。如果发送端发送数据过快,那么就会导致接收端的缓冲区被充满,这时如果发送端继续发送数据,就会造成丢包,然后引起丢包重传等一系列连锁反应。

TCP支持根据接收端的处理能力,来决定发送端的发送速度。这个机制就叫做“流量控制”。

  • 接收端将自己可以接入的缓冲区大小放入TCP首部中的“窗口大小”字段,通过ACK端通知发送端。

  • 窗口大小字段越大,说明网络的吞吐量越高。

  • 接收端一旦发现自己的缓冲区快满了,就会将窗口大小设置成一个更小的值,通知给发送端。

  • 发送端接受到这个窗口后,就会减慢自己的发送速度。

  • 如果接收端缓冲区满了,就会把窗口大小设置为0,这时发送端将不再发送数据,但是需要定期发送一个窗口探测数据段,使接收端把窗口大小告诉发送端。

接收方通过ACK报文中的16位窗口大小这个字段来告知发送方。

这个16位窗口大小字段是来衡量当前接收方剩余空间大小,发送方收到这个数据后,就会灵活的调整发送速度(调整窗口大小)

窗口探测报文不传输实际数据,只是为了触发ACK,只是为了知道当前的窗口大小是多少。

16位窗口大小字段的最大不止是65535字节,因为TCP首部40字节选项中还有一个窗口扩大因子M,实际窗口大小是窗口字段的值左移M位。

拥塞机制(安全机制)

也是滑动窗口的延申,也是限制滑动窗口发送的速率。

就是TCP协议像尽可能快的把数据传输给对方,但是又要避免给网络造成太大压力的折中方案。

拥塞控制衡量的是发送方到接收方这整个链路之间的拥堵情况(处理能力)。

如果当前的网络状态是比较拥堵的,在不清楚当前网络状态下,发送大量的数据,可能会引起网络拥堵情况更加严峻。

TCP引入慢启动机制,也就是说:先发送少量的数据探路,摸清楚当前的网络拥堵情况,再决定按照多大的速度传输数据。

最终滑动窗口的大小=min(拥塞窗口,流量控制窗口)。

  • 这里引入一个新的概念:拥塞窗口

  • 发送开始时,定义拥塞窗口大小为1

  • 每次收到一个ACK应答,拥塞窗口加1

  • 每次发送数据包时,将拥塞窗口和接收端主机反馈的窗口大小做比较,取较小值作为实际发送的窗口

为了不增长的太快,不能将拥塞窗口单纯的加倍。这里引入一个慢启动的阈值。当拥塞窗口超过这个阈值时,不再按照指数的方式增长,而是按照线性的方式增长。

当TCP开始启动时,慢启动阈值先是等于窗口的最大值,在每次超时重发时,慢启动阈值会变成原来的一半,同时拥塞窗口置为1.

当出现少量丢包时,仅仅是触发超时重传。当出现大量丢包时,就认为网络拥塞。

线性增长也是增长,增长到一定程度就会出现丢包,一旦丢包此时发送方立即就让窗口变小(回归初识的窗口大小),继续重复刚才的指数增长+线性增长的过程。

效率机制

滑动窗口(效率机制)

本质:批量的发送数据。

确认应答机制中,对于每一个发送的数据段都要给一个ACK确认应答。收到ACK后再发送下一个数据段。这样做的效率较差。针对这种问题,出现了滑动窗口。

一发一收的方式性能较低,我们一次性发送多条数据,就可以提高性能。一次发送一波数据,然后一起等待一波ACK。

并不是把N组数据的ACK都等到了才继续往下发送,而是收到一个ACK,就继续往下发送一组。

若当前是在等待1001,2001,3001,4001四组ACK,不用等4001到了才继续往下发。只要1001到了,就可以往下多发一组(4001~5000),2001到了再继续往下发一组(5001~6000).

  • 在发送1~1000,1001~2000,2001~3000,3001~4000这组数据的过程中,不进行等待。在一份等待时间内等待了多份ACK。

  • 如果一次批量发送数据为N,统一等待一波。此时这里N称为“窗口大小”,窗口大小是指无需等待确认应答而可以继续发送数据的最大值。

  • 收到第一个ACK后,滑动窗口向后移动,继续发送第五段的数据。

  • 操作系统内核为了维护这个滑动窗口,需要开辟发送缓冲区来记录当前还有哪些数据没有应答;只要确认应答过的数据,才能从缓冲区删除。

  • 窗口越大,则网络的吞吐率越高。

当前窗口大小越大,可以认为是传输速度越快。窗口大了,同一份时间内等待的ACK就更多了,总的等待ACK的时间就减少了。

当这个2001的ACK到达之后,就认为1001~2000这个数据已经收到了,然后就可以立即发送下一组数据了。

随着ACK接连到来,随着接连的发送新的数据,此时这个“窗口”(要等待ACK的数据)就在逐渐的向后“滑动”。

那么如果出现了丢包,该如何进行重传?

情况一:数据包已经抵达了,ACK丢了

这种情况下,部分ACK丢了没事,可以通过后续的ACK进行确认。ACK确认序号的特定含义就保证了,后一条ACK能涵盖前一条。

在发送4001之前,收到了2001的ACK,但未收到4001的ACK。2001的意思就是说:在2001之前的数据已经全部收到了。

情况二:数据包直接丢了
  • 当某段报文段丢失之后,发送端会一直收到1001这样的ACK,就像在提醒发送端(我想要1001)一样。

  • 如果发送端主机连续收到三次同样一个"1001"这样的应答,就会将对应的数据1001~2000重新发送

  • 这时候接收端收到了1001之后,再次返回的ACK就是7001(因为2001~7000接收端之前已经接收到了,被放到了接收端操作系统内核的接收缓冲区)

  • 触发重传,这里的重传只是需要把丢了的那一块数据给重传,其他已经到了的不必再重传,整体的重传效率蛮高。这种重传机制被称为”快重传“。也叫”高速重发机制“

延迟应答(效率机制)

相当于流量控制的延申。

如果接收数据的主机立即返回ACK应答,这时候返回的窗口可能会比较小。

假设接收端缓冲区为:1M,一次收到了500K的数据;如果立即应答,返回的窗口就是500K,但实际上可能处理端处理的速度超快~10ms之内就处理掉这500k数据了。在这种情况下,接收端远远没有达到自己处理数据的极限,也就是说,在这种情况下,即使窗口再大一些,接收端也能处理得过来。如果接收端在接收到这500k数据后,稍微等一会儿再进行应答,比如等待200ms再进行应答,此时返回的窗口大小就是1M.

窗口越大,网络吞吐量越大,传输效率就越高。而我们的目标就是在保证网络不拥塞的情况下尽量提高传输效率。

那么,所有的包都可以进行延迟吗???

当然是有限制的:

  • 数量限制:每隔N个包就应答一次。

  • 时间限制:超过最大延迟时间就应答一次。

捎带机制(效率机制)

是延迟应答的延申。

在很多情况下,客户端服务器在应用层也是”一发一收“的,也就是说,客户端给服务器说”hello“,那么服务器也会回复客户端一个”hello“。

这时,我们的ACK就可以搭一个便车,和服务器回应的”hello“一起回给客户端。

对捎带应答来说,ACK已经和数据合体了(成为一个包了)。若ACK丢了,就是数据丢了,此时进行重传。

粘包问题

不是针对TCP的,而是针对于所有面向字节流的机制(读/写文件)

在TCP接收缓冲区中,如果若干应用数据包混在一起了,就分不出来谁是谁了。

在粘包问题中,这个包指的是应用数据包。在TCP协议头中,没有如同UDP一样的”报文长度“字段,但有一个序号这样的字段。站在传输层的角度上,TCP是一个一个报文传输过来的,按照序号排好,放在缓冲区。站在应用层的角度,能看到的只是一串连续的字节数据。那么对应用程序来说,这么一串字节数据,完全分不清楚从哪个部分到哪个部分是一个完整的应用层数据包。

这就是所谓的粘包问题

解决粘包问题

明确两个包的边界

对于定长的数据包,保证每次都按固定大小读取即可。

对于边长的包,可以在包头的位置,约定一个包总长度的字段。也可以在包和包之间使用明确的分隔符。

TCP异常

进程终止:进程终止会释放文件描述符,仍然可以发送FIN。和正常关闭没区别。

机器重启:和进程终止情况相同。

机器掉电/网线断开:接收端认为连接还在,一旦接收端有写入操作,就会发现连接已经不在了,就会进行reset。即使没有写入操作,TCP的内部也有一个定时器。会定期询问对方是否还在,如果对方不在,就会把连接释放掉。

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Sunlightʊə

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值