传输层协议
传输层协议解析: 负责两端之间的数据传输; TCP/ UDP
1. UDP
UDP: 用户数据报协议,无连接,不可靠,面向数据报传输
重点: 协议格式,协议特性,特性对于编程的影响
协议格式:
16位源端口 & 16位对端端口: 述了通信是哪两端进程在进行
16位数据报长度: 描述了包含udp报头在内的数据报长度
因为16位数据所能描述的最大数字: 65535
因此一个UDP报文,包含UDP报头在内,最大必须小于64K
反馈: 应用层使用sendto发送数据的时候,数据的长度必须小于 64k-8
16位校验和字段:校验数据一致性 (分析接收到的数据跟对方发送的数据是否一致)
一个数据一旦传输过程中产生了变化,就不能交付给应用程序处理了
校验算法:二进制反码求和算法
发送方发送数据的时候先将校验和字段置0,然后从报头开始逐字节取反相加,高出16位的部分截断与低16位继续相加,直到数据报结尾。得到了一个校验和然后填充到校验和字段中,进行发送给对方。
接收方收到数据之后,从报头开始进行二进制反码求和,如果最终是0就一致
协议特性
无连接:相较于TCP来说,通信前,并不需要建立连接,只要知道对方的地址信息就可以直接发送数据
不可靠:传输过程中,不保证数据安全,且有序的到达对端
面向数据报传输:传输的数据有最大大小限制(64-8) ,接收端向上交付数的时候必须整条交(dp数据在缓中区中取出的时候:先取8字节报头,取长度-8数据
协议特性对于编程的影响:
1.因为udp不保证数据安全,有序到达对端,因此需要程序员在应用层进行包序管理
2.因为udp不保证数据安全,有序到达对端,因此需要程序员在应用层进行包序管理
不同的特点: UDP支持局域网广播
2.TCP协议
TCP协议:传输控制协议,面向连接,
可靠传输,面向字节流传输
16位源端端口 &16位对端端口: 述了通信两端
32位序号:tcp是面向字节流的,相当于对传输的每个字节都进行了编号,接收数据的一方会根据需要进行数据排序,最终进行数据的有序交付
32位确认序号:接收方接收到了一个数据之后,就会给发送方发送一个确认报文(包含认序号),通过确认序号告诉对方,多少号以前的数据都已经收到了后边会讲到的一些机制(快速重传机制,滑动窗口机制....) 依赖于确认序号
4位报头长度:Cp的报头,不是一个固定长度,长度是会变化的,但是不管怎么变化,前20字节都是固定的,只有选项数据这里存在0~40字节的不定长度
因此在解析的时候,总是先取出20字节固定头部,然后根据头部长度,再决定取出剩余多少的洗项数据 长度-20,剩余的就是应用数据但是4个比特位,所能表示的最大数字: 15,因此4位报头长度,是以4字节为单位
6位保留:暂时未使用
6位标志位: FIN,SYN,RST,PUSH,ACK,URG
16位窗口大小:用于实现滑动窗口机制,进行流量控制
16位校验和:二进制反码求和算法,校验数据一致性
16位紧急指针:指向带外优先数据的结束位置
tcp协议特性
tcp协议特性: 面向连接,可靠传输,提供字节流传输服务
面向连接: 通信前,要先建立连接,确保双方都是在线,具有数据收发能力的。
连接管理: 三次握手建立连接,四次挥手断开连接
三次握手建立连接:通信前,要先建立连接,确保双方具有数据收发能力
四次挥手断开连接: 通信结束了,会有一个断开连接过程,避免出现意外
握手为什么是三次
1.建立连接,是双方都要确保对方具有数据收发的能力,因此都要进行SYN
2. 两次不安全
1.有可能SYN会延迟到达,与重发的SYN形成冲突 (三次有状态要求)
2. 防止恶意攻击,比如客户端发送SYN后直接退出
3.四次没必要(没必要发送两次报文,在一次回复中将对应比特位置1即可)
握手失败后,两端如何处理的?
第一次握手失败: 客户端会重发SYN
第二次握手失败: 服务器等待最后一次ACK超时就会发送RST,然后释放资源
客户端会重传SYN
第三次握手失败: 服务器等待最后一次ACK超时就会发送RST,然后释放资源
FIN 请求的功能:只能表示不再给对方发送数据(不代表不接收数据)
CLOSE WAIT: 等待关闭,对方发送了FIN包,已经不再给自己发送数据上层如果这时候还在继续recv,则会读完缓冲区数据后,不再阻塞,而是返回0。这种情况下就是等待上层针对这种情况的处理
1.挥手为什么是四次
FIN请求只能表示主动关闭方不再发送数据,不代表不再接收数据因此,被动关闭方收到FIN并进行确认后,还有可能会继续发送数据等待上层不再发送数据了,也要关闭套接字了才会发送FIN包因此挥手没有合并为三次
2.一台主机上出现了大量的CLOSE WAIT状态连接,是什么原因?
1.只有收到了FIN请求并进行了确认回复的连接会进CLOSE WAI
2.一直处于CLOSE WAIT而没有进入下一步状态是因为,上层没有进行关闭套接字操作,也就是没有发送FIN,所以没有进入下一步
3.因此原因就是代码中没有针对断开连接的套接字进行关闭处理
3.TIME WAIT状态有什么用,为什么不直接关闭套接字释放资源?
1.TIME WAIT状态是主动关闭方在发送最后一次ACK后进入的状态
2.如果没有TIME WAIT,主动关闭方直接释放套接字资源,有可能出现新启动的套接字使用了与之前相同的地址信息
3.而上一次连接有可能最后一次ACK会丢失,一旦丢失被动关闭方会重传FIN
4.就会导致上一次通信因为最后一次ACK丢失,而遗留的问题 (重传FIN)对新连接造成影响。
因此不能直接释放资源,需要等待两个MSL时间,针对有可能存在的FIN重传进行处理,并保证上次通信的所有数据都消失在网络中。
MSL: 报文最大生命周期 (一个报文在网络中最大能存在的时),默认60s
4.一台主机上出现了大量的time wait状态连接,是什么原因,如何处理?
1.time wait是主动关闭方发送最后一次ACK后进入的状态,等待一段时间是为了处理有可能因为FIN丢失导致的FIN重传的处理因此一台主机出现大量time wait连接,是因为主机上大量的主动关闭了连接I常见于爬虫服务器。
2.time wait等待时间是可配置的,可以将时间设置的更短3.有个套接字选项,叫做地址重用,setsockopt();
5. tcp连接管理中的保活机制
连接断开有个信息: recv会返回0,send会触发异常
tcp通信中,如果客户端和服务端通信频率并不高,中间突然网断了,没有四次挥手的机会,如果两端通信频率很低,可能需要很久才会发现
在通信中,客户端与服务器若长时间无通信 (默认7200s) ,则tcp服务器会自动的向客户端发送保活探测心跳包,要求对方进行响应 (默认每隔75s)若连续多次都没有收到响应 (默认9次) ,则认为连接断开
这都是配置,可配置的。 甚至可以用套接字选项设置
可靠传输: 通过很多特殊机制实现
面向连接---确保双方都具有数据收发的能力
丢包检测机制-确认应答机制: 接收方要针对收到的每一条数据进行确认回复
丢包重传机制-超时重传机制: 等待确认回复超时则重传
序号字段:进行包序管理,有序交付
校验和字段: 校验数据一致性,不一致则丢弃,要求重传
可靠传输
1.保证可靠: 面向连接,确认应答机制,超时重传机制,序号,确认序号,校验和
2.避免丢包: 滑动窗口机制,拥塞机制
3.性能挽回: 快速重传协议,延迟发送机制,延迟应答机制,捎带应答机制
流量控制
1.滑动窗口机制
滑动窗口机制: 通过协议字段中的窗口大小字段实现的
接收方每次接收到数据都会进行确认回复,在确认回复的时候就会计算自己的接收缓冲区中的剩余空间大小,将这个数字放入窗口大小字段中给对方回复。发送方根据确认回复中的窗口大小字段,确定自己最多发送多少数据
作用: 进行流量控制,避免因为发送方发送数据过多导致丢包
关键点: 协议字段中的窗口大小
窗口大小字段: 接收方进行数据发送或者确认回复的时候,告诉对方最多给自己发送多少数据 (大小<接收方的接收缓冲区空闲空间大小)
发送窗口:
窗口后沿: 记录了从哪个序号开始对数据进行编号发送
移动取决于是否收到了后沿数据的确认回复
窗口前沿: 记录了最多发送数据到多少序号
移动取决于对方回复的窗口大小
窗口前沿 - 窗口后沿 <= 接收方回复的窗口大小
确认序号: 告诉发送方,确认序号之前的数据都已经收到了
如果第一条数据丢了,但是收到了第二条数据这时候是不能对第二条数据进行确认回复的。
接收窗口:
窗口后沿: 记录要接收数据的起始序号
移动: 收到起始序号的数据
窗口前沿:记录当前接收数据的结束序号
移动: 根据缓冲区剩余空间大小决定
窗口前沿 - 窗口后沿 <= 缓冲区剩余空间大小
停等协议: 发送方发送一条数据后,收到回复才会发送下一条数据
适用于网络状况较差的场景
回退n步协议: 滑动窗口机制决定了tcp数据传输可以管线化传输,可以连续发送多个报文,而在传输过程中,如果出现了丢包,回退n步协议,指的是从丢包的这个数据开始重新对数据进行传输。
适用于网络状态一般的场景
选择重传协议:传输过程中,丢包了,哪个包丢了,就对哪个包重传
适用于网络较好的场景
2.拥塞机制
拥塞机制: 避免因为网络状况突变,因为网络拥塞而导致大量丢包的情况
关键点: 进行网络状况的探测
拥塞窗口: 控制发送方发送数据量的基准
发送数据大小<= min(滑动窗口大小,拥塞窗口大小)
拥塞窗口,一般初始大小为1,
拥塞控制的思想:慢启动,快增长的过程进行网络探测
拥塞窗口从初始值开始进行指数级增长,达到闯值时进行线性增长
传输过程中,一旦出现了超时重传(丢包):
拥塞窗口的阈值,变为窗口的一半大小,拥塞窗口变为初始值
性能的挽回
快速重传协议
目的:避免每次重传都需要等待超时才进行。
在数据传输过程中,接收方接收数据的时候,并没有接收到起始接收序号的数据,而是接收到了后边的数据 (在第一条数据之前先收到了第二条数据)
接收方不会对第二条数据进行确认回复,正常情况发送方,等待确认回复,超时后进行第一条数据的超时重传。
但是这样效率太低了。因此出现了这种情况后,接收方为了提高效率会给发送方回复一个第一条数据的序号确认
并且在接收后续的数据过程中,都会进行如此确认
而发送方,连续收到三条第一条数据的确认回复,则会对第一条数据进行重传
延迟发送机制
解决频繁的小数据发送效率较低的情况,每次发送数据,数据并不会立即被发送而是会等待一小会,在这期间有可能又会有小数据被放到发送缓冲区,小数据就会积累成为大数据,经过一次IO就可以完成传输。减少了IO次数提高了效率。
延迟应答机制
基于确认应答机制,接收方需要对发送方的每一条数据进行确认回复。而如果直接对数据进行确认回复,大概率数据在缓冲区并没有被取出,因此这时候的回复会导致窗口大小变小,网络的吞吐率降低了 (传输效率降低了) ,因此设计者就设计延迟一会应答,这段延迟的时间中,应用程序就有可能将数据取出,保持窗口不变吞吐率不变,尽可能的总是以最大速率传输数据
捎带应答机制
基于确认应答机制,接收方需要对发送方的每一条数据进行确认回复。但是每一个回复都是一个最小20字节的报文,也会占据带宽因此设计者认为,如果收到了一条数据后,接收方刚好也有数据要发送给对方,就干脆将这个确认回复与要发送的数据结合到一起,发送给对方。这样可以尽量减少空报文的传输
3.字节流传输
字节流传输: 传输的时候,对数据以字节为单位进行编号,进行传输,不限制传输大小
数据发送的时候,总是先放到缓冲区,发送的时候进行编号发送
粘包问题
粘包问题: 数据在缓冲区中堆积,将多条数据当作一条数据进行处理的过程
粘包产生的本质原因: 数据之间缺乏边界管理
tcp粘包原因: tcp在传输层,并不管传输什么数据,只管从缓冲区取合适大小的数据进行操作,没有边界管理。
解决方案: 在应用层,程序员对数据进行边界管理边界管理: 明确一条数据从哪开始,到哪结束。
1.特殊字符间隔:需要对数据中的特殊字符进行编码,避免歧义
2.数据定长:数据固定长度,缺陷就是需要以最大长度定线
3.数据采用TLV格式:在应用层头部中定义数据的长度(先取头部,根据头部中的长度,决定取多少数据) ; ----典型做法:HTTP、UDP
4.TCP的心跳保活机制
TCP的心跳保活机制:
默认情况: tcp的通信,在长时间(7200s)无数据往来,则服务器会每隔一段时间(75s)给客户端发送保活探测数据包,要求客户端进行确认回复,如果连续多次(9次)都没有收到回复,则认为连接断开
不是每个连接断开都会有四次挥手:
有: 正常关机,关闭程序
没有: 机器断电,突然断网....
这套心跳保活机制的默认时间都是可配置的
过设置套接字选项进行设置。
连接断开在程序中反馈:
recv接收数据时会返回0; send发送数据会触发SIGPIPE异常