一、关于UDP
使用UDP可能会存在的问题:
因为UDP报文长度是2个字节(范围0-65535就是64K),无法表示一个比较大的数据报
如果要传一个大的数据的解决办法:
方法一:可以在应用层针对大的数据报进行分包(拆成多个部分),然后再通过多个UDP数据报分别发送,这个时候接收方再把收到的几个包重新拼接成完整的数据
方法二:改成TCP,TCP没有长度限制
UDP报头格式:
?校验和:是用来验证网络传输的这个数据是否是正确的
二、【重点】关于TCP
TCP报头格式:
?TCP中的核心机制:有连接、可靠传输、面向字节流、全双工
TCP如何保证可靠传输:
1、确认应答:保证可靠传输的核心机制,关键就是接收方收到消息之后,返回一个应答报文 (ACK acknowledge)表示自己已经收到了
比如说A给B发送了1000个字节,序号是1-1000(意思是TCP报头中的序号是1,报文长度是1000),此时B就给A返回应答报文1001,表明小于1001的数据都已经被B收到了,接下来A再从1001这个序号开始往后进行传递
2、超时重传:相当于对确认应答进行了补充,确认应答是网络一切正常的时候,通过ACK通知发送方我收到了。如果出现了丢包的情况,超时重传机制就要起到效果了
比如说发送消息后消息丢了,或者返回的ACK丢了,使我们认为对方没有接收到消息,此时就会在一段时间之后重新再发一次
为了确保数据不会重复发两次,TCP内部就会有一个去重操作:接收方收到的数据会先放到操作系统内核的“接收缓冲区”中,接收缓冲区可以视为是一个内存空间,并且也可以视为是一个阻塞队列。收到新的数据,TCP就会根据序号来检查这个数据是不是在接收缓冲区中已经存在了,如果不存在就放进去,如果存在直接丢弃,保证应用程序调用socket api拿到的这个数据一定是不重复的
3、【重点!】连接管理:
1)如何建立连接:三次握手->客户端和服务器之间,通过三次交互,完成了建立连接的过程
三次握手能保证可靠性的原因:三次握手相当于“投石问路”,检查一下当前的网络情况是否满足可靠传输的基本条件,如果不满足就放弃传输;双方能协商一些必要的信息
(类似于两个人打电话,一个人问另一个人能不能听到,另一个人说能,然后又反问另一个人是否也能听到,另一个人也回复能,当两个人都能听到的时候,证明此时满足可靠通信的条件,可以进行传输,若不满足条件,就放弃传输)
三次握手的状态:
LISTEN?:表示服务器启动成功,端口绑定成功,随时可以有客户端来建立连接(就像手机信号好,随时可以有人给我打电话)
ESTABLISHED:表示客户端已经连接成功,随时可以进行通信了(有人给我打电话,我接听了,接下来可以通话了)
?2)如何断开连接:四次挥手
四次挥手的状态:
CLOSE_WAIT:四次挥手挥了了两次之后出现的状态,这个状态就是在等待代码中调用socket.close()方法来进行后续的挥手过程~正常情况下,一个服务器上不应该存在大量的CLOSE_WAIT。如果存在,说明大概率是代码存在bug,close没有被执行到
TIME_WAIT:谁主动发起FIN,谁就进入TIME_WAIT.起到的效果就是给最后一次ACK提供重传机会,表面上看起来A发送完ACK之后就没有A的事了,按理说A此时就应该销毁连接释放资源了,但是并没有直接释放,而是会进入TIME_WAIT状态等待一段时间,一段时间之后再进行释放,目的是,怕最后一个ACK丢包,如果最后一个ACK丢包了就意味着B会重传FIN
TIME_WAIT应该持续多久:2*MSL
MSL表示网络上任意两点之间,传输需要的最大时间,这个时间也是系统上可以配置的参数,一个典型的设置就是60s
4、滑动窗口(在保证可靠传输的前提下提高传输效率)
之所以传输效率低是因为由于确认应答机制的存在,导致每次执行发送操作,都需要等待上个ACK的到达,此时大量的时间都花在等ACK上了
而滑动窗口本质就是在批量的发送数据:一次发一波数据,然后在一起等一波ACK,此时就可以缩小等待时间,进而提高效率
当前这个窗口越大,可以认为传输速度就越快,窗口大了,同一份时间内等待的ACK就更多,总的等待ACK的时间就减少了
但是滑动窗口也避免不了丢包的问题~
在滑动窗口的背景下丢包的处理方法:
情况一:ACK丢了(不用管,此时不影响)
?
情况二:数据丢了(重传数据)?
就像看电视剧一样,每天电视播两集,但是有一天有事情落下一集没有看,此时直接就先跳过这一集,直接跟着后边看,等哪天再把这一集没看的补上就行了,没必要再重头看一遍
5、流量控制:是滑动窗口的延申,目的是为了保证可靠性
流量控制的关键,就是能衡量接收方的处理速度,通过接收方缓冲区的剩余空间的大小,来衡量当前接收方的处理能力
6、拥塞控制:是滑动窗口的延申,也是限制滑动窗口发送的速率
拥塞控制衡量的是发送方到接收方这整个链路之间拥堵情况的处理能力
7、延时应答:相当于流量控制的延申
流量控制相当于是踩了刹车,使发送方发的不要太快,延时应答,就是在这个基础上能够尽量的再让窗口更大一些
八、捎带应答:延时应答的延申
?九、面向字节流-》粘包问题
注意:不仅仅是TCP存在粘包,其他面向字节流的机制也存在粘包问题,例如:读文件
TCP粘包粘的是应用层的数据报,在TCP接收缓冲区中,若干个应用层数据包混在一起了,这种就是粘包问题
解决方案: 在应用层协议里面加入包之间的边界
TCP的异常处理:
1、进程终止:直接结束进程的处理流程和四次挥手是一样的
因为TCP连接是通过socket来建立的,socket本质上是进程打开的一个文件,文件其实就存在于进程的PCB里面的文件描述符表里,每次打开一个文件(包括socket)都在文件描述符表里增加一项,每次删除一个文件,都在文件描述符表里删除一项
如果直接杀死进程,PCB就没了,PCB里面的文件描述符表自然也就没了,此处的文件相当于自动关闭了,这个过程和手动调用socket.close()一样,都会触发4次挥手~
2、机器关机:此处的机器关机是指按照操作系统约定的正常流程关机
正常流程的关机,会让操作系统杀死所有进程然后在关机(和1没区别)
3、机器掉电/网线断开:直接拔电源,此时操作系统不会有任何的反应时间,也不会有任何的处理措施
?
TCP和UDP的对比:
1:啥时候使用TCP? =>对可靠性有一定要求,(日常开发中的大多数情况,都基于TCP)
2:如果传输的单个数据报比较长(超过 64k) -> 首选 TCP
3:啥时候使用UDP? =>对可靠性要求不高,对于效率的要求更高(机房内部的主机之间通信,分布式系统中,广播就是首选UDP)
面试题:基于UDP如何实现可靠传输?
在应用层基于UDP复刻TCP的机制:
实现确认应答机制
. 每个数据收到之后,都要反馈一个ACK(应用程序自己定义一个 ack包)
实现序号/确认序号,以及实现去重
实现超时重传
.
实现连接管理
要想提高效率,实现滑动窗口
为了限制滑动窗口,实现流量控制/拥塞控制
实现延时应答,捎带应答