【网络原理】Tcp相关的一些机制

Tcp的相关特性:1.有链接  2.可靠传输  3.面向字节流  4.全双工

其中可靠传输是重中之重,是tcp最核心的特性,所谓的可靠传输不是说100%能够将数据传输到对方,而是退而求其次,1.发送方将数据发出去之后,能够知道接收方是否收到数据。2.一旦发现对方没有收到,就可以通过一系列的手段来进行“补救”。

1.确认应答

发送方,把数据给接收方之后,接收方收到数据就会给发送方返回一个应答报文。

发送方,如果收到了这个应答报文,就知道自己的数据是否发送成功了。

举个例子,假如我给女神发消息说我请你吃麻辣烫好吗?

这时候,女神就会给我说好啊,好啊,这个好啊好啊就相当于一个应答报文。 但是如果我连续给女神发送两个信息,会发生什么样的情况

这时候我就会理解成女生愿意做我女朋友,请女神吃麻辣烫,给回复一个滚字。这是一种最理想的状态,这种情况称为消息的后发先至。为了针对这种情况,tcp种引入了确认应答这种机制。

首先所谓的确认应答是在接受方收到了数据之后,他会发送一个序号,这个序号就是一个整数,大小关系就是发送消息的顺序。

这样就不会造成消息误解了。上面的图还不够严谨,更却准的来说,序号不是按照一条两条方式来进行编号的,而是按照字节来编号的,因为tcp是面向字节流的

 

假设tcp开始传输的数据是从序号1开始传输的,一般tcp在传输数据时候,初始序号不会是1

 如果一个tcp的载荷部分有1000个字节,初始序号为1,那么这个初始序号会在报头中记录,而1000这个序号字段并不会在报头中记录,这个序号是tcp这一次传输数据的第一个字节序号,其他的序号都需要推导出来。

应答报文会在确认序号中填写1001,并发送给对方,这个确认序号的含义表示是我已经收到了1-1000这1000个字节的数据,接下来我要接收的是1001开始的数据。

接收方会给发送方发送一个ack数据报文,里面携带的确认序号,告诉发送方我已经收到了那些数据。假如确认序号是5001,那么就代表的5001之前的数据我已经收到了。

如何判断一个数据包是普通数据包还是ack数据包呢?

如果ack这一位是1,就代表这个数据包是一个ack数据包,确认应答序号就会生效。

反之ack这一位是0,就代表这个数据包是一个普通数据包,确认应答序号就不会生效。

 2.超时重传

确认应答,描述的是一个比较理想的情况,如果网络传输的过程中,出现了丢包怎么办?

出现丢包,那么发送方势必收不到ack,使用超时重传机制,针对确认应答,进行补充

为什么会出现丢包呢?

首先把网络比作公路,错综复杂的公路,在公路上有许多的收费站,平日里,如果车流量不大的时候,收费站车都能很快的通过,此时也就很少出现堵车的情况,但是遇到节假日的时候,收费站就会很容易出现堵车。网络中的收费站就是路由器/交换机,如果数据包太多了,就会在这些路由器/交换机上进行堵车,路由器和交换机针对堵车的这种情况,处理是比较粗糙的,不会将数据包给保存好,而是将一些数据包给直接丢弃掉,此时这个数据包就在网络上进行丢失了。

在丢弃数据有两种情况:

1.传输的数据包丢失

2.返回的ack丢了

 

对于发送方来说,这两种是无法进行区分的,无论出现哪一种情况,都会发生超时重传。 那么超时重传的时候也发生了数据丢失呢,首先这种问题大概率不会出现的。假设发生丢失数据的概率是10%,那么发生两次数据丢失的概率为1%。重新发送一次数据提升了成功发送数据的概率。

那么发送方何时重新发送数据呢? 等待时间

 在等待时间内,如果接收方发送的ack到达接收方了,那么就不会触发超时重传。

如果在等待时间内没有收到ack,发送方就会触发超时重传。

1.初始的等待时间,是可配置的。不同的系统上的等待时间是不一样的,也可以通过内核参数来修改等待时间。

2.等待时间是动态变化的,当进行第二次传输数据的时候,等待时间会变长,时间变长也不是无限的进行变长,边长到一定的程度就会断开链接。

3.链接管理

建立链接和断开链接,三次握手是建立链接,四次挥手是断开链接。

这里的握手,只是打个招呼,打招呼的内容没有实际意义,也比较简短,只是为了唤起对方的注意,好进行下面的操作。在握手这个动作中并不是tcp独有的,甚至不是网络通信中独有的,计算机中很多操作都会涉及到握手这个操作。

1.三次握手

tcp建立链接需要三次握手

谁主动建立链接谁就是客户端,那么被动的一方就是服务器。

syn是一个同步报文段,是一个特殊的tcp数据报,不携带任何数据。

在建立链接的过程通信双方都要发送syn,也都要反馈ack,一共是进行了四次握手,但是中间两次可以合并成一次。

三次握手是否可以变成两次握手,不可以因为,在进行两次握手的时候,至少有一方没有接收对方发送过来的ack,此时无法确定双方的接收能力和发送数据能力是否正常。

为什么第 2 次要带上 SYN?

关键原因:TCP 是全双工通信,双方都必须建立各自的发送序列号。

  • 第 1 次握手:客户端告诉服务器 → “我的起始序列号是 x”。

  • 如果第 2 次握手只带 ACK 而没有 SYN
    那么客户端知道了服务器收到了自己的序列号,但客户端却不知道服务器的序列号是多少。
    这样客户端没法确认 服务器端的发送方向 是否建立。

换句话说:

  • ACK 表示:确认对方的序列号 ✅

  • SYN 表示:告诉对方自己的序列号 ✅

因此第 2 次握手必须同时带上 ACK 和 SYN,才能保证:

  • 服务器确认了客户端的序列号。

  • 同时服务器也告诉客户端:我也要通信,这是我的序列号。

只有这样,第 3 次握手客户端才能确认服务器的序列号,从而双方通信才算完全对等地建立。

三次握手的作用:

1.检测网路通信的道路是否通畅。

这好比在我生活中,地铁系统在每天早上正式发车前,先都会有一辆空车先跑一趟,检查在休息的时候,道路是否出现了异常的情况。

2.检测通信双方的接收能力和发送能力是否正常

在这里举个例子:比如我经常和我的朋友进行开黑。

在开黑之前都会检查耳机和麦克风是否正常,于是就出现了下面的情况

3.让通信双方,在握手过程中,针对一些重要的参数,进行协商。

 在插上充电头的一瞬间,充电头里的芯片就会和手机这边芯片进行握手,也就是协商了一下双方能支持的功率,以及最终应该使用多少功率。

 
 2.四次挥手

 建立连接一般都是客户端主动发送的,断开链接客户端和服务器都可以主动发送。

在上图中FIN是结束报文段,也是一种不懈怠任何数据的报文段。标志位的其中之一。

和三次握手不同,此处的四次挥手,能否把中间的两次交互和二为一呢?

像三次握手的时候中间SYN和ACK都是内核触发的,可以一并返回,

这里不能进行合并,是因为ACK和第二个FIN触发的时机不一样的,ACK是B收到FIN之后立马进行发送的,而FIN是应用程序的代码触发的,当应用程序调用了close这个方法,意味着你的代码执行完毕,这时候B就会发送FIN,这中间经历多长时间取决你的代码执行逻辑。上述是正常的四次挥手断开流程,但是还有异常的挥手情况,这也是存在的。这就意味着A就没有收到B发送的FIN的结束报文段,进一步推出应用程序没有执行到close方法,程序就异常退出了。

 4.滑动窗口

tcp的可靠传输,是会影响传输的效率的(多出了一些ack的等待时间,单位时间内能传输的数据就少了),所以滑动窗口就让可靠传输对性能影响更少一些。

 

 但是在滑动窗口出现丢包的问题怎么呢?如果出现丢包的情况,这里重传跟上面的重传又有不一样的。

1.ack丢失

 ack丢失这种情况是不用进行重传的,因为ack表示的含义是:当前的序号之前的数据,我已经收到了,下一个你应该从确认序号这里开始发送的。如果这里的1001丢失了,但是我收到了2001这个确认序号,同时节间的表示我也收到了1-1000这之间的数据。

2.数据包丢失

 在上述的传输数据的过程中,如果其中一个数据丢失了,就会告诉发送方那个数据丢失了,会一直告诉这个数据丢失,直到这个数据我收到了,然后才开始进行索要下一个数据包。

如果通信双方,传输数据的量比较小,也不频繁,就仍然使用普通的超时重传和确认应答

如果通信双方,传输数据的量比较大,频繁,就是用滑动窗口来进行传输数据。

滑动窗口在一定程度上,解决了传输效率的问题,但是滑动窗口越大越好吗,如果的传输的速度太快了,接收方就会处理不过来。所以滑动窗口也不是越大越好。

5.流量控制

这个流量控制是站在接收方的角度上,来反向制约发送方的传输速度。

 衡量一个接收方处理数据的能力就看这个缓冲区还有多大的空间,剩余的空间大,说明接收方处理数据的能力比较快,而且比较强,反之比较弱。

在tcp报头中有一个16位的窗口大小,其实就是接收缓冲区剩余空间大小。

这里是否是最大只能表示64K呢?其实不是的,tcp报头中,选项中有一项是叫做窗口扩展因子,可以让窗口来表示一个更大的值

 6.拥塞控制

流量控制是考虑接收方的处理能力,不仅仅是接收方,还有你整个通信的路径。

拥塞控制就是考虑衡量通信过程中间节点的情况。这中间转发的过程中,任何一个节点,处理能力达到上限,都可能对发送方产生影响,都可能会影响到可靠传输。

由于中间的节点情况很复杂,所以我们采用实验的方式,先按照小的窗口进行发送数据,如果数据发送成功,在慢慢的增加窗口的大小,随着窗口的不断增大,达到一定的程度,可能中间节点就会出现问题了,此时这个节点就可能出现丢包,发送方发现数据包丢了,就把窗口的大小调小,此时如果还继续丢包,就再进行调小,不丢包了再进行慢慢的调大。达到窗口的一个动态平衡。

 7.延时应答

A把数据传给B,B就会立即返回ack给A,这是属于正常的情况。

但是延时应答,有时候B会等一会将ack返回给A。

延时应答本质上为了提升传输效率,发送方的窗口大小,就是传输效率的关键,流量控制这里,就是根据接收缓冲区的剩余空间,来决定发送效率的。延时返回ack,给接收方更多的时间,来读取接收缓冲区的数据,此时接收方读了这个数据,缓冲区剩余的空间更大了,返回的窗口大小也就更大了。

8.捎带应答

在延时应答的基础上,进一步的提高效率,网络通信中都是这种一问一答模型。

 9.面向字节流

这里有一个重要的问题,粘包问题(不是tcp独有的,而是面向字节流机制都会有的问题)

此处包应用层数据包,如果同时有多个应用层数据包被传输过去,此时就容易出现粘包问题。

 但是udp就没有粘包问题,因为udp是面向数据包进行传输数据的。

udp的接收缓冲区,相当于是一个DatagramPacker对象,应用程序在读取的时候,能明确知道哪里到哪里是一个完整的数据。

 在tcp中如何解决粘包问题?

核心思路就是:通过定义好的应用层协议,明确应用层数据包之间的边界。

这里所说的应用层协议,并不是跟我们想的那个协议一样,这里的协议是指程序猿在写代码的时候,规定好应该用什么来解决粘包问题。

1.引入分隔符

2.引入长度

 10.异常情况的处理

如果在使用tcp的过程中,出现意外,会如何处理?

1.进程崩溃:进程没了,异常终止了。文件描述符,也就释放了,相当于调用了socket.close()

        此时就会触发FIN,对方收到之后,自然就会返回FIN和ACK,正常的四次挥手断开链接的流程)tcp的链接,可以独立于进程的存在,(进程没了,tcp链接不一定没)

2.主机关机(正常流程)

        在进行关机的时候,就是会触发强制终止进程的操作

        此时会触发FIN,对方收到,自然返回FIN和ACK.

        不仅仅是进程没了,整个系统也可能关闭了,如果在系统关闭之前,对端返回的ACK和FIN到了,此时系统还是可以返回ACK,进行正常的四次挥手的,如果系统已经关闭了,ACK和FIN迟到了,无法进行后续ACK的响应,站在对端的角度,对端以为自己的FIN丢包了,重传FIN,重传几次都没有响应,自然也就放弃链接了。

        

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值