C C++最全后台核心编程(三):网络编程-TCP协议,吐血整理

img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

  • URG:紧急指针是否有效m
  • ACK: 确认号是否有效——>确认报文段
  • PSH: 提示接收端应用程序应该立即从 TCP 接收缓冲区中读走数据
  • RST: 要求对方重新建立连接——>复位报文段
  • SYN: 请求建立一个连接——>同步报文段
  • FIN: 通知对方本端要关闭——>结束报文段

16位窗口大小(Window):滑动窗口流量控制,告诉对方本段的接收缓冲区还有多少。

16位校验和(Checksum):由发送端填充,接收端对其进行CRC算法,建议TCP报文段在传输过程中是否损坏。

16位紧急指针:正的偏移量。它的序号字段的值相加表示最后一个紧急数据的下一个字节的序号。


二、TCP状态流转

建立连接的过程:

在TCP /IP 协议中, TCP 协议提供可靠的连接服务,采用三次握手建立一个连接。

  1. 第一次握手: 建立连接时,客户端发送 SYN 包(SYN = x)到服务器,并进入SYN_SENT 状态,等待服务器确认。
  2. 第二次握手:服务器收到 SYN 包,必须确认客户的 SYN ( ACK= x + 1 ),同时自己也发送一个SYN 包( SYN=y),即 SYN + ACK 包,此时服务器进入 SYN_RECV 状态。
  3. 第三次握手: 客户端收到服务器的SYN + ACK 包,向服务器发送确认包 ACK(ACK=y+1),此包发送完毕,客户端和服务器进入 ESTABLISHED 状态,完成3 次握手。

完成三次握手,客户端与服务器开始传送数据,也就是ESTABLISHED 状态。

结束连接的过程:

  1. 客户端 A 发送一个 FIN(FIN = X + 2),用来关闭客户 A 到服务器B的数据传送。
  2. 服务器 B 收到这个 FIN,它发回一个ACK(x + 3),确认序号为收到的序号加 1。和 SYN 一样,一个 FIN将占用一个序号。
  3. 服务器 B 关闭与客户端 A 的连接,发送一个 FIN 给客户端 A(报文段6)。
  4. 客户端 A 发回 ACK 报文确认,并将确认序号设置为收到序号加 1(报文段7)。

状态详解:

CLOSED: 这个没什么好说的了,表示初始状态。

LISTEN: 这个也是非常容易理解的一个状态,表示服务器端的某个SOCKET处于监听状态,可以接受连接了。

SYN_RCVD: 这个状态表示接受到了SYN报文,在正常情况下,这个状态是服务器端的SOCKET在建立TCP连接时的三次握手会话过程中的一个中间状态,很短暂,基本 上用netstat你是很难看到这种状态的,除非你特意写了一个客户端测试程序,故意将三次TCP握手过程中最后一个ACK报文不予发送。因此这种状态 时,当收到客户端的ACK报文后,它会进入到ESTABLISHED状态。

SYN_SENT: 这个状态与SYN_RCVD遥想呼应,当客户端SOCKET执行CONNECT连接时,它首先发送SYN报文,因此也随即它会进入到了SYN_SENT状态,并等待服务端的发送三次握手中的第2个报文。SYN_SENT状态表示客户端已发送SYN报文。

ESTABLISHED:这个容易理解了,表示连接已经建立了。

FIN_WAIT_1: 这个状态要好好解释一下,其实FIN_WAIT_1和FIN_WAIT_2状态的真正含义都是表示等待对方的FIN报文。而这两种状态的区别 是:FIN_WAIT_1状态实际上是当SOCKET在ESTABLISHED状态时,它想主动关闭连接,向对方发送了FIN报文,此时该SOCKET即 进入到FIN_WAIT_1状态。而当对方回应ACK报文后,则进入到FIN_WAIT_2状态,当然在实际的正常情况下,无论对方何种情况下,都应该马 上回应ACK报文,所以FIN_WAIT_1状态一般是比较难见到的,而FIN_WAIT_2状态还有时常常可以用netstat看到。

FIN_WAIT_2:上面已经详细解释了这种状态,实际上FIN_WAIT_2状态下的SOCKET,表示半连接,也即有一方要求close连接,但另外还告诉对方,我暂时还有点数据需要传送给你,稍后再关闭连接。

TIME_WAIT: 表示收到了对方的FIN报文,并发送出了ACK报文,就等2MSL后即可回到CLOSED可用状态了。如果FIN_WAIT_1状态下,收到了对方同时带FIN标志和ACK标志的报文时,可以直接进入到TIME_WAIT状态,而无须经过FIN_WAIT_2状态。
  
CLOSING: 这种状态比较特殊,实际情况中应该是很少见,属于一种比较罕见的例外状态。正常情况下,当你发送FIN报文后,按理来说是应该先收到(或同时收到)对方的 ACK报文,再收到对方的FIN报文。但是CLOSING状态表示你发送FIN报文后,并没有收到对方的ACK报文,反而却也收到了对方的FIN报文。什 么情况下会出现此种情况呢?其实细想一下,也不难得出结论:那就是如果双方几乎在同时close一个SOCKET的话,那么就出现了双方同时发送FIN报 文的情况,也即会出现CLOSING状态,表示双方都正在关闭SOCKET连接。

CLOSE_WAIT: 这种状态的含义其实是表示在等待关闭。怎么理解呢?当对方close一个SOCKET后发送FIN报文给自己,你系统毫无疑问地会回应一个ACK报文给对 方,此时则进入到CLOSE_WAIT状态。接下来呢,实际上你真正需要考虑的事情是察看你是否还有数据发送给对方,如果没有的话,那么你也就可以 close这个SOCKET,发送FIN报文给对方,也即关闭连接。所以你在CLOSE_WAIT状态下,需要完成的事情是等待你去关闭连接。

LAST_ACK: 这个状态还是比较容易好理解的,它是被动关闭一方在发送FIN报文后,最后等待对方的ACK报文。当收到ACK报文后,也即可以进入到CLOSED可用状态了。

几个问题:

1.为什么建立连接协议是三次握手,而关闭连接却是四次握手呢?

这是因为服务端的LISTEN状态下的SOCKET当收到SYN报文的建连请求后,它可以把ACK和SYN(ACK起应答作用,而SYN起同步作用)放在一个报文里来发送。但关闭连接时,当收到对方的FIN报文通知时,它仅仅表示对方没有数据发送给你了;但未必你所有的数据都全部发送给对方了,所以你可以未必会马上会关闭SOCKET,也即你可能还需要发送一些数据给对方之后,再发送FIN报文给对方来表示你同意现在可以关闭连接了,所以它这里的ACK报文和FIN报文多数情况下都是分开发送的.

2.为什么TIME_WAIT状态还需要等2MSL后才能返回到CLOSED状态?

这是因为虽然双方都同意关闭连接了,而且握手的4个报文也都协调和发送完毕,按理可以直接回到CLOSED状态(就好比从SYN_SEND状态到ESTABLISH状态那样);但是因为我们必须要假想网络是不可靠的,你无法保证你最后发送的ACK报文会一定被对方收到,因此对方处于LAST_ACK状态下的SOCKET可能会因为超时未收到ACK报文,而重发FIN报文,所以这个TIME_WAIT状态的作用就是用来重发可能丢失的ACK报文。

三、超时重传

TCP协议是一种面向连接的可靠的传输层协议,它保证了数据的可靠传输,对于一些出错,超时丢包等问题TCP设计的超时与重传机制。其基本原理:在发送一个数据之后,就开启一个定时器,若是在这个时间内没有收到发送数据的ACK确认报文,则对该报文进行重传,在达到一定次数还没有成功时放弃并发送一个复位信号。
这里比较重要的是重传超时时间,怎样设置这个定时器的时间(RTO),从而保证对网络资源最小的浪费。因为若RTO太小,可能有些报文只是遇到拥堵或网络不好延迟较大而已,这样就会造成不必要的重传。太大的话,使发送端需要等待过长的时间才能发现数据丢失,影响网络传输效率。

超时重传机制如下:
在这里插入图片描述
经典方法:

通过下面的公式计算得到平滑的RTT估计值(SRTT):

SRTT <- α(SRTT) + (1-α)RTTs

最新的SRTT是根据现存的SRTT和新的样本值RTTs计算出来的。 常量α为平滑因子,推荐值是0.8~0.9。这种计算方法叫做指数加权移动平均法或则低通过滤器。
根据前面求的SRTT计算出RTO:

RTO = min(ubound, max(lbound, (SRTT)β))

β是时延离散因子,推荐值1.3~2.0。 ubound是RTO上边界,lbound是下边界。这种计算方法就是经典方法。

这种方法缺点就是没法适应大规模的变动(网络不稳定情况)

基于计时器的重传:

TCP发送端得到了基于时间变化的RTT测量值,就能据此设置RTO,发送报文段时应确保重传计时器设置合理。设置计时器前要记录报文序列号,若及时收到了报文的ACK,就取消计时器。TCP的连接发送端不断的设定和取消重传计时器,如果没有数据丢失就不会出现计时器超时。

TCP将超时重传视为相当重要的事件,当发生这种情况时候,通过降低当前数据发送率来对此进行快速响应。实现有两种方法:一是基于拥塞控制机制减小发送窗口,二是当一个报文段被再次重传时候,增大RTO的退避因子。 退避因子正常情况下是1,随着多次重传会加倍成2,4,8等等,直到上限。

大多数情况下计时器超时并触发重传是不必要的,因为RTO的设置一般大于RTT的2倍,因此基于计时器的重传会导致网络利用率下降。幸运的是,TCP有另外一种方法检测和修复丢包,因为该方法不需要触发计时器超时,所以称为快速重传。

四、滑动窗口

关于这部分自己不晓得怎么叙述才好,因为理解的部分更多,下面就用自己的理解来介绍下TCP的精髓:滑动窗口协议。

所谓滑动窗口协议,自己理解有两点:1. “窗口”对应的是一段可以被发送者发送的字节序列,其连续的范围称之为“窗口”;2. “滑动”则是指这段“允许发送的范围”是可以随着发送的过程而变化的,方式就是按顺序“滑动”。在引入一个例子来说这个协议之前,我觉得很有必要先了解以下前提:

  1. TCP协议的两端分别为发送者A和接收者B,由于是全双工协议,因此A和B应该分别维护着一个独立的发送缓冲区和接收缓冲区,由于对等性(A发B收和B发A收),我们以A发送B接收的情况作为例子;
  2. 发送窗口是发送缓存中的一部分,是可以被TCP协议发送的那部分,其实应用层需要发送的所有数据都被放进了发送者的发送缓冲区;
  3. 发送窗口中相关的有四个概念:已发送并收到确认的数据(不再发送窗口和发送缓冲区之内)、已发送但未收到确认的数据(位于发送窗口之中)、允许发送但尚未发送的数据以及发送窗口外发送缓冲区内暂时不允许发送的数据;
  4. 每次成功发送数据之后,发送窗口就会在发送缓冲区中按顺序移动,将新的数据包含到窗口中准备发送;

下面我们来看一下发送方的滑动窗口示意图:

上图中分成了四个部分,分别是:(其中那个黑模型就是滑动窗口)

  1. 已收到ack确认的数据。
  2. 发还没收到ack的。
  3. 在窗口中还没有发出的(接收方还有空间)。
  4. 窗口以外的数据(接收方没空间)

下面是个滑动后的示意图(收到36的ack,并发出了46-51的字节):

下面我们来看一个接受端控制发送端的图示:

五、拥塞处理

拥塞概念

1、概念:在某段时间,如果对网络中的某一资源的需求超过了该资源所能提供的可用部分,网络的性能就要发生变化,这种情况叫阻塞

2、拥塞控制:防止过多的数据注入到网络当中,这样可以使网络中的路由器或链路不致过载。(通过拥塞窗口处理网络拥塞现象的一种机制)

  • a.前提:网络能够承受现有的网络负荷。
  • b.拥塞控制是一个全局性的过程,涉及到所有的主机、路由器,以及与降低1网络传输性能有关的所有因素
  • c.与流量控制的区别:流量控制往往是指点对点通信量的控制,是个端到端的问题。流量控制所要做的就是控制发送端发送数据的速率,以便使接收端来得及接收。
  • d.代价:需要获得网络内部流量分布的信息。在实施拥塞控制之前,还需要在结点之间交换信息和各种命令,以便选择控制的策略和实施控制。这样就产生了额外的开销。拥塞控制还需要将一些资源分配给各个用户单独使用,使得网络资源能更好的实现共享。

拥塞控制的几种方法

  • 慢开始
  • 拥塞避免
  • 快重传
  • 快恢复

1.慢开始

算法原理:当主机开始发送数据时,如果立即将大量数据字节注入到网络,那么就有可能因为不清楚当前网络的负荷情况而引起网络阻塞。所以,最好的方法是先探测一下,即由小到大逐渐增大发送窗口,也就是说,由小到大逐渐增大拥塞窗口数值。通常在刚刚发送报文段时,先把拥塞窗口cwnd设置为一个最大报文段MSS的数值。而在每收到一个新的报文段的确认后,把拥塞窗口增加至多一个MSS的数值。用这样的方法逐步增大发送方的拥塞窗口cwnd,可以使分组注入到网络的速率更加合理。(慢开始当中的“慢”并不是指cwnd的增长速率慢,而是在TCP开始发送报文段时先设置cwnd = 1,使得发送方在开始时只发送一一个报文段)

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

634342)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 21
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值