网络原理之TCP

TCP 对数据传输提供的管控机制,主要体现在两个方面:安全和效率。
这些机制和多线程的设计原则类似:保证数据传输安全的前提下,尽可能的提高传输效率。

确认应答(安全机制)

发送数据给对方后,要知道对方有没有收到,其关键就是接收方收到消息之后,给发送方返回一个(应答报文ACK(acknowledge))

  1. 案例引入(消息先发后置)

由于网络环境原因,当发送多条消息时,容易出现消息先发后至情况
(我们就会错误理解女朋友的意思,以为她喜欢打游戏)

在这里插入图片描述
TCP 报头结构
在这里插入图片描述
TCP 序号

TCP 将每个字节的数据进行了编号,(TCP 发送数据并不是按 “几条消息” 这样的格式,而是针对字节)
在这里插入图片描述
序号:发送方发送序号 1,数据(1~1000).
确认序号:接收方发送确认序号 1001 (之前的数据已收到,请继续发送数据)。
在这里插入图片描述
TCP 先发后至解决方法

TCP 中有接收缓冲区(一块内核中的内存空间)
可以按照序号对所有发来的消息进行排序再输出
(应用程序读到的数据是有序的,和发送方一样)

超时重传(安全机制)

如果一切顺利,就可以直接确认应答,但 丢包 也是网络上非常典型的情况。。。

  1. 发送方发送的数据丢包了
    在这里插入图片描述
    丢包后,接收方未收到,自然就没返回ack,发送方没拿到应答报文,等待一段时间过后,发送方就认为刚刚发生了丢包,就会重新发送数据

  2. 接收方回复的 ack 丢包了

在这里插入图片描述
TCP内部实际上是有去重操作的。

接收方收到的数据会先放到操作系统内核的"接收缓冲区"中,接收缓冲区可以视为是一个内存空间,并且也可以视为是一个阻塞队列;收到新的数据,TCP就会根据序号,来检查这个数据是不是在接收缓冲区中已经存在了.如果不存在,就放进去;如果存在,直接丢弃。保证应用程序调用socket api拿到的这个数据一定是不重复的。应用程序感知不到超时重传的过程的。

  1. 重传后再次丢包
    多包丢失时, TCP 会继续超时重传,但每丢包一次,等待时间都会延长(重传的频率变低)
    如果多次重传都无效,TCP 此时会尝试重置连接,如果重连也失效, TCP 则会关闭连接

TCP 是如何实现可靠性的:确认应答 + 超时重传

连接管理(安全机制)

在这里插入图片描述

TCP 建立连接:三次握手
通信双方进行网络交互,客户端 和 服务器之间通过三次交互建立了连接关系
(syn 同步报文段)

一次:客户端 syn(询问)
二次:服务器 ack(确认)+syn(询问)
三次:客户端 ack (确认) 在这里插入图片描述

TCP 断开连接:四次挥手

通信双方,各自给对方发送一次 FIN(结束报文) ,再各自给对方返回 ack
在这里插入图片描述
三次握手和四次挥手间的区别与联系

a.三次握手:

一定是客户端主动发起的(主动发起的一方才叫客户端);
中间两次能合并。
三次握手中,B发送的ACK和SYN同一时机,就能够合并,此处的B给A发送的ACK和SYN都是操作系统内核负责进行的。

b.四次挥手:

可以是客户端主动发起,也可能是服务器主动发起。
中间两次有时候合并不了(有时候是能合并)。
不能合并的原因,在于B发送ACK和B发送FIN的时机是不同的;四次挥手中,B给A发的ACK是内核负责的,B给A发的FIN是用户代码负责(B的代码中调用了socket.close()方法,才会触发FIN)。如果这两操作之间的时间差比较大,就不能合并了;如果时间差比较小,这是可能会合并的(延时应答和捎带应答)。

滑动窗口(效率机制)

刚才我们讨论了确认应答策略,对每一个发送的数据段,都要给一个ACK确认应答。收到ACK后再发送下一个数据段。这样做有一个比较大的缺点,就是性能较差。尤其是数据往返的时间较长的时候。
既然这样一发一收的方式性能较低,那么我们一次发送多条数据,就可以大大的提高性能(其实是将多个段的等待时间重叠在一起了)。
在这里插入图片描述

  1. 窗口大小指的是无需等待确认应答而可以继续发送数据的最大值。上图的窗口大小就是4000 个字节(四个段)。
  2. 发送前四个段的时候,不需要等待任何ACK,直接发送;
  3. 收到第一个ACK后,滑动窗口向后移动,继续发送第五个段的数据;依次类推;
  4. 操作系统内核为了维护这个滑动窗口,需要开辟发送缓冲区来记录当前还有哪些数据没有应答;只有确认应答过的数据,才能从缓冲区删掉;
  5. 窗口越大,则网络的吞吐率就越高;
    在这里插入图片描述
    那么如果出现了丢包,如何进行重传?
    一:数据包抵达,ACK被丢了。
    在这里插入图片描述
    确认序号的含义: 表示该序号之前的数据都已经收到 后一个 ack 可以包含前一个ack 含义(如果最后一个 ack 丢了那就超时重传)
    所以无需担心

二:数据包就直接丢了。
在这里插入图片描述

  1. 由于刚才 1001 - 2000丢了,所以接收方发送到 ack 仍然继续索要 1001
  2. 多次索要后 发送方就会重传 1001 - 2000 数据,当接收方收到后,就会应答 7001 确认序号
  3. 此后发送方继续发送

流量控制(安全机制)

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

ACK 报文在这里插入图片描述

  1. 接收端将自己可以接收的缓冲区大小放入 TCP 首部中的 “窗口大小” 字段,通过ACK端通知发送端;
  2. 窗口大小字段越大,说明网络的吞吐量越高;
  3. 接收端一旦发现自己的缓冲区快满了,就会将窗口大小设置成一个更小的值通知给发送端;发送端接受到这个窗口之后,就会减慢自己的发送速度;
  4. 如果接收端缓冲区满了,就会将窗口置为0;这时发送方不再发送数据,但是需要定期发送一个窗口探测数据段,使接收端把窗口大小告诉发送端。
    在这里插入图片描述

拥塞控制(安全机制)

在这里插入图片描述
在网络传输中间路径中,可能当前的网络状态就已经比较拥堵。在不清楚当前网络状态下,贸然发送大量的数据,是很有可能引起雪上加霜的。

TCP引入慢启动机制
先小速率发送,不丢包就扩大速率
发生丢包后,马上调小速率
重复上述过程,最终达到一种动态平衡状态
在这里插入图片描述
为了不增长的那么快,因此不能使拥塞窗口单纯的加倍。
此处引入一个叫做 慢启动的阈值(ssthresh)
当拥塞窗口超过这个阈值的时候,不再按照指数方式增长,而是按照线性方式增长
当TCP开始启动的时候,慢启动阈值等于窗口最大值;
在每次超时重发的时候,慢启动阈值会变成原来的一半,同时拥塞窗口置回1;
少量的丢包,我们仅仅是触发超时重传;大量的丢包,我们就认为网络拥塞;

延迟应答(效率机制)

在这里插入图片描述
如果接收数据的主机立刻返回ACK应答,这时候返回的 窗口 可能比较。(窗口越大,网络吞吐量就越大,传输效率就越高
如果接收端稍微迟一些应答,应用程序消费数据变多,窗口大小大概率变大(传输效率提高)

  1. 数量限制:每隔N个包就应答一次;
  2. 时间限制:超过最大延迟时间就应答一次;

捎带应答(效率机制)

在延迟应答的基础上,我们发现,很多情况下,客户端服务器在应用层也是 “一发一收” 的。意味着客户端给服务器说了 “How are you”,服务器也会给客户端回一个 “Fine, thank you”;
那么这个时候ACK就可以搭顺风车,和服务器回应的 “Fine,thank you” 一起回给客户端在这里插入图片描述
ACK 的时机是由 内核 完成的,回复响应的时机是由 程序代码 完成的
(ack 延迟回复,当程序回复的适合捎带上ack)

面向字节流 (粘包问题)

TCP粘包问题指的是当 A 给 B 发送多个应用层数据报之后 ,在 B 的接收缓冲区中若干个应用层数据报就会粘在一起,读取困难。
在这里插入图片描述

解决方案:1. 定义分隔符 / 2. 约定一个数据报长度

异常情况

  1. 进程终止:进程终止会释放文件描述符,仍然可以发送FIN。和正常关闭没有什么区别。
  2. 机器重启:和进程终止的情况相同。
  3. 机器掉电/网线断开:接收端认为连接还在,一旦接收端有写入操作,接收端发现连接已经不在了,就会进行reset。即使没有写入操作,TCP自己也内置了一个保活定时器(心跳包),会定期询问对方是否还在。如果对方不在,也会把连接释放。

另外,应用层的某些协议,也有一些这样的检测机制。例如HTTP长连接中,也会定期检测对方的状态。例如QQ,在QQ断线之后,也会定期尝试重新连接。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值