传输层:UDP/TCP协议
网络协议图
一.UDP
特点:
无连接,不可靠,面向数据报,全双工(前面网络编程中介绍过)
格式:
服务器的端口号一般都是程序员指定的(这样你才能访问到),客户端的端口号是系统自动分配的(如果提前指定好, 可能会与其他程序冲突)
UDP的长度问题
也许你也会有一个问题:在当今的世界, UDP的报文最大长度为64kb,是否够用?
显然是不够用的,这也是UDP的最大痛点,也是被边缘化的主要原因
为什么设计UDP的大佬不做出改变,将UDP报头的表示长度的属性不设计更大一点4字节?6字节?
不是技术问题,是zz问题↓
要传输一个超过64kb的数据该怎么办?
有两个方案
校验和
上述的比特翻转本来就是小概率事件, 敲好两个反转能抵消的概率小之又小, 工程上可以忽略
UDP发现数据校验不对时,只能丢弃不会重发, 也是不可靠传输的体现,想要重发要么使用TCP,要么在应用层代码中自己实现
二.TCP
特点:
有连接, 可靠传输,面向字节流,全双工
格式
像上面的32位序号和确认序号16位窗口大小和紧急指针,还有那六个标志位后面会介绍到
三.TCP的十大核心机制
核心机制一:确认应答(可靠性机制)
TCP的可靠传输是内核实现的,写代码的时候是感知不到的
可靠传输的实现机制是 确认应答(我给对方发消息,对方收到之后给我一个应答说确认收到了),确认应答是保证可靠传输的最核心的机制
再说一下确认应答的后发先至
比如我给女神发消息
本来是
结果是可能是
当连续发多条数据的时候,可能就会出现后发先至的情况(一个数据报是先发的,反而后到了)
怎么产生的呢?
如何解决?
针对数据编号,就要用到报头中的32位序号了
应答报文可能携带载荷也可能不携带
引入序号之后接收方就可以根据序号顺序排序来依次读取数据了
核心机制二:超时重传(可靠性机制)
在传输数据的过程中,还可能发生“丢包”,也就是发送一个数据在传输的过程中丢了,没有到达对方
在两个主机之间,网络的结构是非常复杂的,中间要经过很多路由器和交换机,这些路由器和交换机同时也连接着其他的路由器和交换机,这些结果错综复杂,传输的数据量也是不确定,有时候传输的数据可能会多点,有时候可能会少点
如果设备太繁忙,这些数据包就需要等待,如果等太久了,就可能被丢弃了,网络负载越高,线路就越繁忙,就越容易丢包某段路线出现强烈信号干扰也会丢包
真的出现丢包怎么办呢?
重传!设置一个时间,在规定的时间里面没有收到回应,就重新传输这个数据,这个就叫做超时重传
两种丢包的情况
以下两种情况接收无法分辨, 都会触发重传
第一种情况(要传输的数据包丢了)
这种情况发送的数据丢了再重新传一次就好了 主要还是第二种情况
第二种情况(返回的ACK应答数据包丢了)
接收缓冲区在操作系统内核中会分配一个专门缓冲区存储数据等待TCP协议栈处理,类似于生产者消费者模型
确认应答是tcp保证可靠性的最核心机制;超时重传是TCP可靠性机制的有效补充,这两个机制保证了tcp的可靠性传输,并不是三次握手
核心机制三:连接管理 [网络这个模块最常考的部分]
1.建立连接(三次握手)
tcp是有连接的 客户端与服务器是通过三次握手来建立连接的
这个时候就有疑问了:明明三次握手上面确实是四次握手?
这里的中间两次握手可以合并为一次↓
为什么能合并?
其实syn和ack打包是在操作系统内核中完成的 时间上可以说是同步的,tcp也允许在报头中设置多个标志位(ACK和SYN都为1) 同时合并也能减少开销提升效率
三次握手传输的是什么?
传输的数据的序号从几开始,往往两次连接的初始序号差别很大(这里就为了防止前朝的剑斩本朝的官问题后面会介绍到) 还会告诉对端的IP和端口号并且互相保存(有连接的体现)这是网络层IP协议要做的(每次网络传输都会涉及最开头那张图的封装分用)
三次握手TCP层的状态
上述只是简单描述了一下三次握手,实际的三次握手比这个更加复杂,如下图框出的地方(再下面是传输数据和四次挥手的过程)
各状态的介绍
上述状态常见的就是listen和establish
为啥tcp要三次握手,有啥用,解决了啥问题?
1.投石问路,先初步探一探网络通信链路是否通畅(网络通常是可靠传输的前提条件)
2.验证通信双方的发送能力和接收能力是否正常
讨论:两次握手是否可行?
不行,两次握手少了一步给服务器发ack,这会让服务器不知道服务端的接收能力是否正常和服务器的发送功能是否正常
四次握手是否可行?
可以,但是没必要,浪费资源,效率较低
3.可以协商一些关键信息
也如前面所说防止出现前朝剑斩本朝官
2.断开连接(四次挥手)
过程
问题:四次挥手的中间两次能否合并变成三次挥手?
有时候能有时候不能
不能:ack和fin的交互时机不一样ack是在操作系统内核中就完成了,fin需要应用层应应用程序调用close方法,时机不同所以就不能合并,而三次握手之所以能是因为ack和syn都是在内核中完成的交互时机可以说瞬发,就可以合并
能:tcp有延迟应答机制,可以延迟发送ack,这样就可以和fin同步了
虽然有时候能有时候不能,但是大多数情况下还是不能
四次挥手TCP层的状态
如图圈出来的
重点就关注close_wait和time_wait状态
close_wait状态介绍
time_wait状态介绍
time_wait要等多久才合适呢?
2*MSL(网络上任何两个节点传输所要消耗的最大时间) 通常会配置成60s ,2*MSL也就是两分钟
MSL每个系统配置的都不一样,也能修改
异常情况

再谈TCP式如何实现可靠传输的?
确认应答
超时重传
连接管理(三次握手,四次挥手)(握手挥手的过程也是依靠确认应答和超时重传实现可靠传输的)
这些机制都起到了作用,在三次握手中,一旦路探完了,后续就没它事了,网络环境事多变的,可能这会畅通,过会就堵塞了,而确认应答,是保证每次传输的这些数据都是可靠的,因此真正起到决定性作用的还是确认应答!
核心机制四:滑动窗口(提高提高传输效率)
更准确地说,是让TCP在可靠传输的前提下,效率别太拉跨,因为可靠传输效率已经降低了(可靠和效率不可兼得)
使用滑动窗口,不能让TCP变得比UDP快,但是可以缩小差距
下一组是怎么发的?
1.等待所有ack都收到再发下一组
2.收到一个发一个
很明显是第二种,第一种并不能节省多少时间,甚至会等待更长时间
如果2001比1001的ack先收到会怎么样?
如果这样的情况窗口直接往后走两个就行了, ack确认序号的含义是该序号之前的数据都已经收到了,比如数据1-50收到了 71-100收到了51-70没收到,返回的ack确认序号也是51不会是101,等到后续收到51-70才会发送确认序号为101的应答报文
丢包问题
情况一:数据包已经抵达,ack却丢了
这种情况不要紧,因为可以通过后续的ACK进⾏确认; 也就是上面所说的确认序号的作用
情况二:数据包直接就丢了
重传采用的是快速重传机制(滑动窗口下的,超时重传的变种操作)
快速重传就是只要谁丢了就重传谁,其他的数据(都已经在接收缓冲区里呆着)不用重传,整个过程速度很快
接收方的缓冲区情况↓
超时重传和快速重传并不冲突而是相辅相成
核心机制五:流量控制(作为滑动窗口补充)
滑动窗口的窗口越大,传输效率越高
但是窗口也不能无限大,如果窗口太大了,就可能使接收方处理不过来了(和你代码有关系),或者是使传输的中间链路处理不过来,这样就会出现丢包,就得重传了,这时候窗口大并没有提高效率,反而降低效率了
流量控制就是给滑动窗口睬踩刹车,避免窗口太大,导致接收方处理不过来
*滑动窗口的窗口大小是实时变化的
具体流程
光考虑接收方,还是不够的,还需要考虑中间链路的处理能力(也就是拥塞控制)
核心机制六:拥塞控制
总的传输速率是一个木桶效应,取决于最短板
具体怎样衡量中间设备的转发能力呢?
此处并不会对中间设备的转发能力进行量化,因为中间设备那么多也不好逐个进行量化,更何况网络环境还是动态变化的,而是把中间的设备都看成一个整体,采取“做实验”的方式,动态调整,产出一个合适的窗口大小
这样做也可以非常好的适应网络环境的动态变化
方案↓
实际发送方的窗口 取决于拥塞窗口,流量控制窗口的最小值
拥塞控制喝流量控制共同限制了滑动窗口机制,可以让滑动窗口能够在保证可靠性的前提下,提高传输效率了
也就是说拥塞控制和流量控制也是保证可靠性的机制
核心机制七:延迟应答(提高传输效率的机制).
(延迟应答也是围绕滑动窗口来展开的)
是否有办法在条件允许的基础上,尽可能地提高窗口大小呢?
需要在返回ack的时候,拖延一点时间,利用拖延的这个时间,就可以给应用程序腾出来更多的消费数据的时间,这样接受缓冲区的剩余空间就更大了!
此处通过延时应答到底能提高多少速率,还是取决于接收方应用程序实际的处理能力(也不是百分百提升效率还是看应用程序消费的快不快,也有可能延时的时候又收到了其他数据)
核心机制八:捎带应答
在延迟应答的基础上,引入的第一个进一步提高效率的方式
延迟应答使让ack传输的时机更慢
捎带应答使基于延迟应答,让数据进行合并
核心机制九:面向字节流(粘包问题)
这里主要讨论粘包问题至于这个粘读zhan和nian的都有
有以下情况
解决办法
已经有成熟的方案例如json和protobuf已经解决粘包问题,但是自定义应用层协议的时候就要考虑到这个问题
核心机制十:TCP异常情况的处理(经典面试题)
网络本身就会存在一些变数,导致tcp连接不能继续正常工作了
比如
1.进程崩溃
进程崩溃=>进程没了=>PCB没了=>文件描述符表也就被释放了=>相当于调用socket.close()(socket在系统内核中也是一个文件,也会被放到文件描述符表中)=>崩溃的这一方就会发出FIN,进一步的触发四次挥手,此时连接就正常释放了,此时tcp的处理和进程的正常退出没啥区别
2.主动关机
3.主机掉电了
心跳包
4.网线断开了
以上就是TCP的十个主要特性,并不是只有这十个特性,还有很多特性在标准文档中
补充:tcp报头其他属性
TCP和UDP对比
如何实现UDP的可靠传输,就往TCP上面靠