Linux网络编程: udp,tcp协议原理
- 一.udp和tcp的介绍
- 1.udp介绍
- 1.udp的特点
- 2.udp的适用场景
- 3.udp效率分析
- 2.tcp介绍
- 1.tcp的特点
- 2.tcp的适用场景
- 二.udp协议原理
- 1.udp协议段格式
- 2.udp的缓冲区和全双工通信
- 三.tcp协议段
- 1.tcp协议段格式
- 2.发送接收缓冲区
- 3.确认应答ACK机制,窗口大小和流量控制
- 4.红军蓝军问题以及tcp如何保证可靠性的
- 5.序号与确认序号
- 1.改进tcp的发送与ACK机制
- 2.序号保证接收方的应用层接收到的消息的有序性
- 3.确认序号保证应答方ACK所回复的消息
- 4.序号,tcp缓冲区,字节流的理解
- 5.为滑动窗口做铺垫的场景
- 6.为何序号和确认序号要分开存储 : 捎带应答
- 6.紧急指针与URG标记位
- 7.标记位
- 1.PSH
- 1.PSH在流量控制当中的作用
- 2.PSH在其他领域当中的作用
- 2.SYN,FIN
- 3.RST
- 1.解决第三次握手报文丢失引发的连接建立的认知不一致问题
- 2.其他作用
- 四.超时重传机制
- 1.数据的去重问题
- 2.重传时间
- 3.隐含的一个问题 后面的四次挥手部分"解决"它
- 五.连接管理机制
- 1.OS管理连接
- 2.三次握手
- 1.介绍
- 2.为何要有三次握手
- 1.角度一 : 以最小成本保证通信双方建立好了连接
- 2.角度二 : 三次握手其实是四次握手加一次捎带应答
- 3.角度三 : 三次握手是为了让client跟server建立双向连接时必须由client先建立连接,从而为SYN洪水问题提供一定程度的保护
- 1.SYN洪水问题介绍:
- 2.三次握手与SYN洪水
- 3.系统调用与状态转换
- 3.四次挥手
- 1.介绍
- 2.为何要有四次挥手,三次挥手可以吗?
- 3.状态转换与TIME_WAIT的作用
- 4.数据A如何解决
- 5.CLOSE_WAIT问题
- 6.TIME_WAIT问题
- 五.滑动窗口
- 1.什么是滑动窗口
- 2.滑动窗口如何滑动以及滑窗如何实现流量控制
- 3.滑动窗口与数据重传
- 1.滑窗如何实现数据重传
- 2.快重传与超时重传之间的关系
- 4.埋一个伏笔,IP协议的时候我们回答
- 六.拥塞控制
- 1.为何要有拥塞控制
- 2.拥塞控制算法的介绍
- 3.拥塞窗口与滑动窗口与窗口大小的关系
- 4.小总结
- 5.小例子
- 七.延迟应答
- 八.tcp和udp的对比
- 九.面向字节流导致数据包的粘包问题
- 1.介绍
- 2.面向数据报会导致数据包的粘包问题吗?
- 3.如何解决数据包的粘包问题?
- 十.TCP异常情况与心跳机制
- 十一.全连接队列,accept,backlog
- 十二.打通文件,套接字,系统与网络
- 1.回忆一下C语言实现多态
- 2.看一下内核数据结构
- 十三.TCP总结
注意三个点:
- tcp的各个属性,各个机制都是浑然一体的,无法割裂开来理解,因此这里的标题当中每一个标题的内容当中都可能会不断地解答之前的疑问
- 网络通信面前,主机是平等的,不管你是客户端还是服务器,udp和tcp对你们都是统一对待的,因此所有的场景当中发送数据与接收数据的双方身份完全可以互换
- 之前的进程间通信,线程间通信,我们日常生活当中的通信,我们都是直接传输信息的
在我们网络通信当中,没有单独的数据形式(除了传输层和应用层之间的数据传输),所有的通信都是报头+有效载荷
因此本文所有的图当中的通信信息都默认包含了udp/tcp的协议报头!!!
- tcp是网络协议当中非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常非常重要的协议,希望大家也能认真对待,tcp和ip协议称霸了整个网络协议栈,所以网络协议栈叫做TCP/IP模型嘛
一.udp和tcp的介绍
1.udp介绍
udp:(User Datagram Protocol 用户数据报协议),类似于寄信📧
1.udp的特点
它的特点是:
- 无连接 (只要知道对端的IP地址和端口号即可发送和接收数据,避免了建立和断开连接的开销)
- 不可靠传输 (没有确认机制,重传机制,如果数据包在传输时出现丢包问题不会给应用层返回任何错误信息)
- 面向数据报
优点: 没有数据包的粘包问题,直接对数据序列化反序列化即可传输,使用起来更简单
缺点: 不能够灵活地控制数据读写的次数和数量 - 在数据传输过程中开销通常较低(因为它无连接,不保证传输的可靠性,且头部开销小)
2.udp的适用场景
- 需要进行实时通信,且对数据的完整性和可靠性要求不高,但是对数据的低延迟要求较高的场景(例如直播,音视频通话,在线游戏)
- 简单的响应通信: 例如DNS进行域名解析时,只需要发送一个请求,接收一个响应即可,对数据的完整性和可靠性要求不高
3.udp效率分析
-
udp具有高效性和低延迟性,因为它无需建立连接(处理大量并发请求时更加高效),而且面向数据报(没有数据包的粘包问题)
-
udp没有拥塞控制机制,因此如果接收方处理数据的能力较弱,而发送方发送数据的能力较强,就可能会导致网络拥塞,影响传输效率
因此udp并不能说udp效率就多么多么高
它只是在处理一些简单的通信场景,或者对数据的完整性和可靠性要求不高,但是对数据的低延迟要求较高的场景下更适用
2.tcp介绍
tcp : 传输控制协议(Transmission Control Protocol),见名知意,它要对数据的传输进行详细的控制
1.tcp的特点
- 面向连接(建立连接需要三次握手,断开连接需要四次挥手)
- 可靠传输(拥有确认应答、重传机制、连接管理、流量控制、拥塞控制、序列号[保证用户收到的数据是有序的]等机制)
- 面向字节流
优点: 能够灵活地控制数据读写次数和数量
缺点: 需要处理数据包的粘包问题,使用起来比udp复杂 - 考虑了效率问题(滑动窗口、流量控制、捎带应答、延迟应答)
- 考虑了网络问题(拥塞控制)
因为tcp要保证可靠性,因此tcp就要牺牲部分传输效率作为代价,因为它要做一系列的机制来保证数据传输的可靠性
2.tcp的适用场景
- 对数据的完整性和可靠性要求高(例如文件传输,远程登录,数据库连接等等)
二.udp协议原理
1.udp协议段格式
这个校验和也保证了一下数据的可靠性(与其说可靠性,不如说安全性)
我们之前说过,报头就相当于快递单,是一个结构化字段,因此udp的报头就类似于这么一个结构体
这里可以用位段的方式来进行描述
struct udphdr
{uint16_t src_port:16;uint16_t dst_port:16;uint16_t len:16;uint16_t checksum:16;
}
udp如何解决这两个问题:
- 报头跟有效载荷的分离问题: 报头采用固定大小:8字节
- 如何把有效载荷交给上层: 通过报头当中的16位目的端口号就能将有效载荷交给对应的进程
2.udp的缓冲区和全双工通信
udp没有真正意义上的发送缓冲区,udp发送数据时直接将数据向下交给网络层,由网络层负责后续的网络传输
因此udp的"发送缓冲区"其实并不是udp自己的,而是Linux OS本来就有的sk_buff的缓冲区,
而这个缓冲区的作用就是在网络协议栈的各层之间传递数据包的,各层传递数据包时传递的其实是sk_buff这个结构体,而不是数据包本身
udp就是单纯的将数据之间写到sk_buff的缓冲区当中并将sk_buff向下交给网络层即可,其他的udp不关心
udp是有自己的接收缓冲区的,但是这个接收缓冲区无法保证接收到的数据报的顺序和发送数据报的顺序一致,这取决于网络具体的稳定性等等因素
如果udp的接收缓冲区满了,那么对应的数据包就会直接被丢弃
因为udp没有真正的"发送缓冲区",而有自己的接收缓冲区,所以udp是全双工通信的
至于为何udp要有接收缓冲区,我们可以反着想,如果udp没有接收缓冲区,那就意味着udp接收的数据必须立即被用户读取,
而用户(进程)读取数据之后需要处理数据,如果处理的有点慢,导致没有及时读取udp接收的数据,
等到我们忙完了,去拿数据时,发现数据都被丢弃了,找不到了
这体验会很差吧…
三.tcp协议段
1.tcp协议段格式
tcp如何解决这两个问题:
- 报头跟有效载荷的分离问题: 报头采用固定大小:20字节,先看够20字节吗,如果够,那就看4位首部长度,乘以4之后得到tcp报头的总长度,然后就能够分离报头跟有效载荷了
- 如何把有效载荷交给上层: 通过报头当中的16位目的端口号就能将有效载荷交给对应的进程
这里面的序号,确认序号,窗口大小,紧急指针,还有URS,ACK,PSH,RST,SYN,FIN我们都会介绍的,
不过下面我们先来谈一下tcp的发送接收缓冲区和全双工
2.发送接收缓冲区
tcp是面向字节流的,就凭着一点它就必须要有发送和接收缓冲区,因为支持写入/读取多次和任意字节数
注意:
- 如果小明发送缓冲区和小红接收缓冲区都空了,此时小红读数据,会不会阻塞? -> 会
- 如果小明发送缓冲区和小红接收缓冲区都满了,此时小明写数据,会不会阻塞? -> 会
跟管道一样哦~
我们把小红换成磁盘
我们把小明和小红接到一起
3.确认应答ACK机制,窗口大小和流量控制
确认应答机制:发送方发送消息后,要求接收方返回一个确认消息,以表明它已经成功接收了原始消息
看一下你的大学班级群,有些消息都会加"收到请回复"
在网络通信这里也是如此,不过这个返回确认消息最重要的不是简简单单的一个"收到",而是报头当中的窗口大小当中的内容!!
小明的OS每次向小红发送数据时,小红的OS都需要给小明返回一个带有ACK标记的报头,里面的窗口大小当中的内容就是小红的接收缓冲区中剩余空间的大小
在小红剩余空间不足导致小明无法发送数据时,小明的OS会一直向小红的OS发送询问,要求小红的OS应答发送ACK
小红的OS也会主动向小明的OS发送报头,里面包含自己的窗口大小
当小红的剩余空间足够了,小明的OS就知道了,然后就开始发送数据了
这就叫做流量控制
流量控制的原因: 确保发送方的发送速率不会超出接收方的处理能力
4.红军蓝军问题以及tcp如何保证可靠性的
这个问题说明了100%的可靠通信是做不到的,因为最新一条消息无法保证被对方收到了
反过来说,只要能够保证最新一条消息的确被对方收到了,那么不就能够保证100%的可靠通信了吗!!
对于红军而言,我最新一次"你收到了吗",只要蓝军给我回答了,那么对于我而言,我这条消息的传输就是可靠的
反过来对于蓝军也是如此.
而这里确认逻辑死循环是因为应答方一直担心对方没有收到我的应答而反复确认,所以我们直接不让应答方去确认了!!
如果对方没有收到你的应答,他会一直询问你,要求你给予应答的,而对方如果收到了你的应答,对方就不回应你
因此应答方发出应答之后就不用担心了,如果对方没收到对方会继续问的!!
那么tcp如何保证可靠性的呢?
tcp当中: 发送方发送消息后,都会要求接收方返回一个确认消息ACK,以表明它已经成功接收了原始消息
如果接收方迟迟没有发送确认消息(ACK),那么发送方会进行超时重传(这个超时重传就是刚才的因为没有收到应答而反复询问)
把红军蓝军换成负责发送信息的OS,这就是tcp保证可靠性最重要的方法
每条消息都要求对方应答,
一旦收到应答了,发送方就放心了,因为对方只有在收到我的消息之后才会给我应答
一旦发出应答,应答方也放心了,因为对方如果没有收到应答,它会自己超时重传的
5.序号与确认序号
序号和确认序号有很多用处
这里我们先介绍序号和确认序号的用途之一 :
使得发送消息可以并发进行,从而重叠发送消息的时间以提高效率
1.改进tcp的发送与ACK机制
其实tcp不仅仅在可靠性上下了很大功夫,在效率上面也下了很大功夫
但是因为tcp的可靠性太过于耀眼了,因此tcp的效率方面就有点被遮挡了光芒
那么怎么办呢? tcp是如何改进的呢?
2.序号保证接收方的应用层接收到的消息的有序性
3.确认序号保证应答方ACK所回复的消息
我们从可靠性方面来理解一下:
确认序号不仅仅保证了可靠性来避免重传的浪费,而且还间接地提高了效率!!
4.序号,tcp缓冲区,字节流的理解
字节流当中的"字节"如何理解?
为何确认序号表示的是下一次发送方向发送缓冲区直接写入的下标的起始位置?
为何确认序号表示的是在这之前的数据都已经收到了?
那么字节流当中的"流"怎么理解呢?
5.为滑动窗口做铺垫的场景
下面我们在想一下下面这个场景呢? 这里跟滑动窗口有关,是为后面做铺垫的
6.为何序号和确认序号要分开存储 : 捎带应答
你看看发送方发送序号和接收方接收序号就差一个1,为什么要分开存储,直接合并搞成同一个字段叫做
32位序号/确认序号不好吗?
这个跟捎带应答有关
什么是捎带应答呢?
由于捎带应答机制(为了提高效率,减少浪费)的出现,使得序号和确认序号需要同时存在于报头当中,因此序号和确认序号就必须有各自独立的字段来描述,不能合为一体!!
6.紧急指针与URG标记位
URG:urgent,紧急的
7.标记位
1.PSH
PSH: push,推(就是督促)
1.PSH在流量控制当中的作用
我们前面介绍流量控制的时候提到过
当接收方的接受能力不足/很低时,比如为0了,此时发送方就需要等着,等到接收方接受能力涨上来
在此期间,发送方会每隔一段时间给接收方发送询问,这个询问就是一个没有数据的报头,
只不过报头里面的PSH标记位被置为1了,这个PSH的意思就是催接收方:抓紧接收数据,通过ACK告诉我窗口大小!!
而且在此期间,当接收方的接受能力涨上来了,接收方就会主动给发送方发送报头,报头当中的窗口大小填上好不容易涨上来的接收能力!!
2.PSH在其他领域当中的作用
PSH不仅仅可以用于流量控制,它的作用是催促接收方抓紧处理我的这份数据
因此当发送方想要发送一些数据要求接收方抓紧快速处理的场景当中,PSH也有很大的作用
比如我们的Xshell当中,Xshell作为客户端,它是一个守护进程,只不过远程登录了我们的云服务器,
跟我们的云服务器建立好了连接,
Xshell要求我们的云服务器对我们输入的指令都抓紧响应,这个方式就是使用PSH发送的报文
2.SYN,FIN
3.RST
RST : reset,用于重新建立连接
1.解决第三次握手报文丢失引发的连接建立的认知不一致问题
常用于解决三次握手时因为第三次握手报文丢失导致client和server对于连接建立的认知不一致的问题
因为第三次握手的丢失,导致client认为自己跟server建立了连接,server认为自己还没有跟client建立连接,这就是连接建立的认知不一致问题
RST的功能是用于快速关闭一个异常连接,重新建立连接,不仅仅可以用于解决这里的连接不一致问题
还可以用于保护server的安全,保障tcp连接的可靠性
2.其他作用
- 连接不存在时 : 当server收到一个数据包,但是这个数据包的发送方给我还没有建立连接时,server就会给发送方发送RST要求对方先跟自己建立连接(保障了tcp连接的可靠性)
- 终止已建立的连接 : 当server发现连接出现异常/错误时,可以通过RST报文来终止连接,避免数据丢失/损坏,保证系统的安全性和可靠性
- 拒绝非法数据和请求 :
当server收到一个非法恶意的数据包或者病毒木马时,server可以通过发送RST报文强制关闭连接来保护server的安全
当server收到恶意攻击者发送的大量无效数据时,可以通过发送RST报文强制对方跟自己重新建立连接,使得对方想要攻击server时自身也会受到相应的代价,从而一定程度上保护了server的安全
四.超时重传机制
我们上面说过,当某一方发送消息,但对方迟迟没有ACK时,该方就会进行超时重传
顾名思义,就是过了一段时间之后发现还没给我ACK,那我就重传,然后重传的信息过了一段时间之后还没ACK,那我就在重传…
往复下去…直到重传次数过多时,tcp会认为对方的网络/连接出现了问题,因此会强制关闭连接
1.数据的去重问题
请问:
-
发送方发送数据后,该数据能立即从发送缓冲区移除吗?
不能,因为在没有迟迟收到对方ACK时,发送方需要将数据进行重传 -> 因此发送方必定要将数据保存下来(保存在哪里? 如何保存? 如何管理被保存的数据? 我们在滑动窗口部分会解决它) -
发送方补发的数据要不要有自己新的报头内容呢 ?
不能有,必须跟所补发的数据报文完全相同,因为如果发送的数据和补发的数据同时都被接收方接收到了,接收方如何区分
这两个数据内容一样的信息是发送方用户发了两次一样的信息呢? 还是说有一个是发送方补发的信息呢?
单凭发送的数据内容本身是无法区分的
又因为
每个信息都有一个序号,因此序号就可以作为这些信息的唯一标识,所以接收方就可以根据序号来进行去重处理
这就是序号的另一大作用 : 用于让接收方对数据和补发数据进行去重
2.重传时间
这个时间间隔能不能太短?
不能,因为会导致接收方频繁对数据进行去重,这就是浪费
能不能太长?
不能,因为要保证数据传输的效率
最理想的情况下, 找到一个最小的时间, 保证 “确认应答一定能在这个时间内返回”
但是这个时间的长短, 随着网络环境的不同, 是有差异的,是动态浮动的,因为网络环境是动态浮动的
3.隐含的一个问题 后面的四次挥手部分"解决"它
这个重传机制又衍生一个问题:
如果一个数据(为了方便表述,我们称为数据A)在网络当中阻塞了,但是发送方重传的数据成功被对方接收了,发送方和接收方愉快的进行通信
最后成功断开连接了
然后数据A珊珊来迟,到了接收方这里
此时接收方是会凭借它的序号而成功发现这个数据是之前没有传过来的,然后直接丢弃这个数据呢?
还是认为发送方还没有跟自己建立连接就进行通信,而向对方发送RST要求对方建立连接呢?
如果当数据A姗姗来迟到达接收方这里的时候,双方都已经开始新的一次通信了,新连接都建立好了,那么这个数据A如何被接收方处理呢?
是能发现出这个数据是之前没有传过来的,还是发现不了,使得数据A成功"蒙混过关"呢
这个问题是一个很麻烦的问题,tcp为了解决这个问题做了很多工作,我们在后面四次挥手的时候会解决它的
五.连接管理机制
1.OS管理连接
这里要强调的是:
双方维护连接是有成本的 !! 不仅仅体现在时间方面,空间方面也有成本
2.三次握手
1.介绍
我们之前在介绍RST的时候介绍给三次握手每一次握手的作用,这里就不在赘述了
2.为何要有三次握手
1.角度一 : 以最小成本保证通信双方建立好了连接
2.角度二 : 三次握手其实是四次握手加一次捎带应答
3.角度三 : 三次握手是为了让client跟server建立双向连接时必须由client先建立连接,从而为SYN洪水问题提供一定程度的保护
1.SYN洪水问题介绍:
恶意攻击者向server发送大量伪造的SYN数据包,耗尽其资源,导致服务器无法处理正常的连接请求,从而造成服务不可用
这个攻击的原理是利用了TCP的一种漏洞:
三次握手当中,当server收到client的SYN请求时会向client发送ACK+SYN请求,并建立半开连接,如果client迟迟没有向server回复ACK,
那么server就会一直超时重传SYN+ACK请求(直到重传次数到达一定数量时,才会发送RST来要求client重新建立连接)
因此恶意攻击者就通过大量伪造源IP地址发送SYN数据包给server,(server根本就无法通过恶意攻击者伪造的源IP地址来成功将SYN+ACK发送过去),因此就会一直超时重传,最终导致server处于大量的半开连接状态,从而耗尽server的资源
因为server为每个未完成的连接请求分配资源(如内存、文件描述符等等…)
2.三次握手与SYN洪水
3.系统调用与状态转换
3.四次挥手
1.介绍
2.为何要有四次挥手,三次挥手可以吗?
我们眼中的四次挥手 :
3.状态转换与TIME_WAIT的作用
4.数据A如何解决
TCP无法100%的解决数据A(姗姗来迟的历史数据)的问题,但是TCP通过一系列手段/机制很大程度上降低了数据A的影响,将数据A发生影响的概率降到了非常非常非常非常非常非常非常非常(此处省略几亿个非常…)低
它的手段:
- 主动断开连接的一方在断开了双方连接之后要处于TIME_WAIT状态处理这些历史数据(直接丢弃它们)
- 大多数情况下都是客户端主动断开连接,而客户端的端口号是connect的时候由OS动态随机分配的,所以先后使用的端口号大概率不同
- 网络通信时,每次双方的起始序列号都是随机的(三次握手时会交换通知双方的起始序列号),起始序列号随机一方面是为了降低历史残留数据的影响,另一方面是为了防止恶意攻击者猜测序列号伪造TCP数据包来欺骗双方
- 因为所有数据的序列号都是连续的,所以历史残留数据跟当前接收方所需的序列号相同的概率很低
- 就算相同,OS也能够根据当前数据是否能跟后续数据的序列号衔接起来来防止历史残留数据造成的问题
这个概率降得比我们人类突发某种意外疾病的概率还要低,所以有啥好担心的,数据A造成不了多么大的问题
5.CLOSE_WAIT问题
- 为何要有CLOSE_WAIT状态??
如何解决呢?
server在无需向client发送数据时及时关闭对应的accept返回的新套接字fd即可,也就是及时关闭连接
6.TIME_WAIT问题
- 为何TCP只规定主动断开连接的一方处于TIME_WAIT呢??
五.滑动窗口
平常刷leetcode时大家应该都刷过滑动窗口这种类型的题目,就是用两个指针left和right维护一个窗口
然后left和right只会向右走,不会向左走
大家也应该都刷过同向双指针划分区间属性这种题目,利用两个指针将整个数组划分为三段区间,左边满足A属性,中间满足B属性,右侧尚未遍历到
这里TCP当中的滑窗虽然外貌上很像算法当中的滑窗,但是它们的确是不同的滑窗,不过因为长得很像,所以学起来没啥太大的成本,甚至有种亲切感…
不扯这些东西了,下面开始滑窗的学习
1.什么是滑动窗口
滑动窗口就是用于控制、管理发送方和接收方之间的数据传输的一个机制
它是TCP发送缓冲区的一段连续的区域
滑动窗口在哪呢?
滑动窗口就是发送缓冲区当中的一段连续的区域
不用解释了,满满的熟悉感
2.滑动窗口如何滑动以及滑窗如何实现流量控制
win_start(左区间)就是确认序号,win_end(右区间)就是确认序号+窗口大小
也就是说滑动窗口大小就是对方接收能力的大小(目前可以这么理解)
每次发送方按顺序发送若干个在窗口内的数据给接收方,当接收方收到数据时给发送方ACK和窗口大小
然后发送方拿到ACK,拿出确认序号算一下win_start和win_end的位置,即可更新窗口
那么请问:
-
滑窗大小会变大吗? 会变小吗? 会为0吗?
当然可以,因为滑窗大小就是接收方的窗口大小,也就是接收方接受能力的大小,接收方能力可以变大,可以变小,可以为0滑窗大小为0时怎么办 ?
阻塞等待呗[发送方发送的数据都会存到发送缓冲区,当发送缓冲区满了的时候,此时发送方在调用write/send时就会阻塞]
滑窗大小变大时怎么办 ? 数据发快一点呗 滑窗大小变小时怎么办 ? 发慢一点呗
这是什么?? 这不就是流量控制吗!!! -
win_end会往左移动吗? win_start会往左移动吗?
都不会,win_start不会往左移动很好理解,因为左边是已发送已确认的数据嘛,那些数据已经无需再去发送了
win_end呢?? 因为win_end=win_start+窗口大小,假设你发送x长度的数据,成功发过去了,那么win_start+=x,即使对方用户没有处理这个数据,也就是这个数据就积压在接收缓冲区当中了,因此窗口大小-=x,所以win_end=win_start+x+窗口大小-x=原来的值,所以不会往左移动 -
滑窗大小在一开始还没有发送数据时如何确定?
在三次握手的时候协商好的(因为三次握手时发送不是SYN,SYN+ACK,ACK这些标记位,而是报头!!!) -
滑窗的数据滑出去了,也就是越界了,怎么办 ? 我们可以把发送缓冲区想象成一个数组实现的循环队列,因此不担心这种情况
-
窗口大小只有16位,也就是说滑窗最多容纳64KB的大小 ?? 会不会不够 ,不会的, 因为:
TCP的报头当中可以携带选项,其中有一个选项(窗口扩大因子M),实际的窗口大小 = 窗口大小当中的数值*(2^M)
3.滑动窗口与数据重传
数据重传一定是因为报文丢失或者ACK丢失,而我发送方不关心到底是报文丢了,还是ACK丢了,毕竟发送方也不知道到底是报文丢了还是ACK丢了…
发送方采用一致的数据重传的方式进行重传,这里为了方便说明,我们统一认为是报文丢失导致的数据重传
这里先介绍一下快重传:
快重传也是一种重传机制,用于快速恢复丢失的数据包,当发送方收到3个或3个以上相同确认序号的ACK时就会触发快重传
而无需等待超时计时器超时
1.滑窗如何实现数据重传
最左侧报文丢失
中间报文丢失
发现没有,滑窗在处理时先移动窗口
直到左区间的数据丢了之后,才重传左区间的数据
它是通过什么判断要不要重传的呢 ? 通过接收方应答的ACK当中的确认序号是否重复,将起始下标==确认序号的报文进行重传!!!
因此: 中间报文丢失和最右侧报文丢失都可以转换为最左侧报文丢失来理解!!
那最右侧报文丢失我就不赘述了
2.快重传与超时重传之间的关系
那快重传和超时重传之间有什么关系呢?
快重传不是快吗? 那我用超时重传干啥呢?
快重传和超时重传是相辅相成的关系,二者相互配合
快重传是用来提高重传效率的,特别是用来解决因为前面的报文的丢失导致后续报文一直等待前面报文到达的情况的问题
而超时重传更为保守,一方面通过重传保证可靠,一方面防止重传太快导致接收方一直去重浪费资源
我们可以理解为超时重传是用来兜底的,而快重传是一种神兵利器
两个都要有才能运筹帷幄,既保证效率又减少浪费
4.埋一个伏笔,IP协议的时候我们回答
滑窗里面有很多可以直接发送的数据,为何我们要分成多个数据段进行发送,直接发一个整体不就行了 ?
反正你TCP是基于字节流的,而且报头当中并不包含整个报文的大小
六.拥塞控制
1.为何要有拥塞控制
当网络环境很差时,我们每个发送方都出现了大量丢包,此时我们的发送方就会判断这是网络环境的问题
如果只有我自己重发数据,那对网络不会有很大影响,那我就能直接发吗??
不能!! 因为TCP不允许
如果TCP允许你重发数据,那么它就需要允许所有人重发数据(因为TCP面前主机平等),如果所有人都重发数据,
那么这个本来就几近崩溃的网络环境就更是雪上加霜了,TCP绝对不能允许这种情况发生
2.拥塞控制算法的介绍
为了进行拥塞控制,避免网络环境发生崩溃导致数据包大量丢失,TCP引入了慢启动机制
==========================================================================================
2^n的指数增长不是非常快吗? 毕竟2^32都达到42亿9千万了!! 那你怎么还叫它慢启动呢???1. 拥塞窗口有一个阈值,达到阈值之前,拥塞窗口是指数级增长,但是达到阈值之后,拥塞窗口就变成线性增长了
2. 拥塞窗口初始值小啊,初始值只有1,因此前几次的窗口大小只是 1 2 4 8 16 32 并不大拥塞窗口其实是一个非常大胆且巧妙的设计,
通过前期缓慢增长避免网络拥塞导致数据包大量丢失,中后期迅速增长恢复正常的网络通信,达到阈值之后开始进行线性增长,随时做好网络拥塞的准备它不仅仅是一个衡量网络状况的指标,更像是一个不断试探网络底线的指标,毕竟知己知彼,百战不殆嘛
3.拥塞窗口与滑动窗口与窗口大小的关系
1. 滑动窗口大小=min(窗口大小,拥塞窗口大小)
2. 窗口大小是描述接收方的接收能力的,由接收方ACK的时候告知发送方
3. 拥塞窗口是衡量当前网络状况的,确保了发生网络拥塞时发送方付出的代价足够低(丢包足够少),进而减少了重传的影响且保障了网络状况从而提高TCP传输的效率
4. 滑动窗口的大小是发送方当前能够发送的数据总大小
因此我们要更新一下我们之前对于滑窗右区间的公式: win_end=win_start+min(窗口大小,拥塞窗口大小)
4.小总结
当TCP发生少量丢包时,仅仅会触发重传机制,发生大量丢包时,就认为网络拥塞
这个拥塞窗口存在的意义
对于发送方来说 : 让发送方发生网络拥塞时丢包尽可能少,避免大量丢包造浪费,且使得数据传输更加顺畅,提高传输效率
对于网络来说 : 让网络发生拥塞时更加轻微且易于恢复,不至于发生网络崩溃或者瘫痪
归根到底,拥塞窗口就是TCP在保证不给网络造成太大压力的情况下,提高传输效率的一种折中方案
5.小例子
我在这里想表达的是:
拥塞窗口能够使得网络通信更加稳定,通过让发生网络拥塞时的情况更加轻微/平缓,且使得发送方能够及时调整,
齐心协力先把网络情况搞好,同时因为拥塞窗口前期指数级增长,从而能够快速恢复正常通信
七.延迟应答
大佬就是大佬,TCP都这么NB了,还能从这里搞一个延迟应答,厉害
下面我们尝试站在大佬的视角来思考一下TCP的效率还能怎么优化
所有的数据包都可以延迟应答吗?
不是的,比如PSH的包你需要抓紧ACK
延迟应答的机制 :
数量限制: 每隔N个包就应答一次(这个更为广泛)
时间限制: 超过最大延迟时间就应答一次
具体的数量和超时时间, 依操作系统不同也有差异; 一般N取2, 超时时间取200ms;
八.tcp和udp的对比
九.面向字节流导致数据包的粘包问题
1.介绍
数据包粘包就是指数据包之间没有明确的边界
面向字节流时,数据都是按照一个个字节去划分进行存储的,数据之间没有明确的边界,因此数据包之间就没有明确的边界,因此就导致了数据包的粘包问题
上层看到的都是一个个字节,无法区分从哪个部分到哪个部分才是一个完整的数据包
2.面向数据报会导致数据包的粘包问题吗?
不会导致,
因为面向数据报时,是按照一个个完整的报文进行传输的,每个报文对于用户来说,只要收到就是完整的,要不然就收不到,报文之间有明确的边界
3.如何解决数据包的粘包问题?
让数据包之间具有明确的边界即可
- 定长报文
- 特殊字符作为分隔符
(比如http请求当中请求行之间的信息按照空格分隔的,请求体之间按照换行符分隔的,请求体和请求内容之间是按照空行作为分隔的) - 报头+自描述字段(比如http请求头当中的Content-Length,udp报头当中的udp长度)
十.TCP异常情况与心跳机制
十一.全连接队列,accept,backlog
注意: 这个backlog不能没有,也不能太大,我们举一个现实生活中的场景
十二.打通文件,套接字,系统与网络
1.回忆一下C语言实现多态
2.看一下内核数据结构
可是我还是没有见到tcp和udp啊!!,别急
总的图############################################################################################:
十三.TCP总结
可以看出,整个TCP的设计是非常优雅,每个部分之间紧密相连,考虑了很多提高效率并保证可靠性的方式,很强
但这并不代表udp就多么不好,udp也有自己的优点和使用场景
以上就是Linux网络编程: udp,tcp协议原理的全部内容,希望能对大家有所帮助!!