【Java EE初阶 --- 网络原理】传输层---UDP/TCP协议
乐观学习,乐观生活,才能不断前进啊!!!
我的主页:optimistic_chen
我的专栏:c语言 ,Java
欢迎大家访问~
创作不易,大佬们点赞鼓励下吧~
文章目录
- UDP
- 校验和
- TCP
- TCP核心应答机制(可靠性)
- 确认应答
- 超时重传
- 连接管理
- 三次握手
- 四次挥手
- 批量传输
- 流量控制
- 拥塞控制
- 延时应答
- 捎带应答
- 粘包问题
- 异常情况处理
- 完结
UDP
特点:无连接、不可靠性传输、面向数据报、全双工
UDP数据报总长度最大是64KB,而报头只有8个字节。
前面博客提到,HTTP的报头是文本格式,UDP/TCP/IP报头都是二进制的
如果要传输更大的数据 ,可以在应用层拆包,最后解析时再组包;或者使用TCP协议。
校验和
与证书中的校验和不同,HTTPS的数字签名是为了防止黑客篡改,UDP校验和是验证数据是否发生修改。
具体过程类似:发送之前先把整个数据报代入计算一个校验和,把数据和校验和一起发送给服务器,服务器接收后计算一下校验和,与受到的校验和相比较,不同直接丢弃。
TCP
特点:有连接、可靠性传输、面向字节流、全双工
TCP数据报总长度无限制。
4位首部长度:代表了报头数据范围是0~15,(TCP不是使用字节为单位,而是4字节为单位),所以报头长度是4*15=60
保留位是TCP设计者考虑到UDP不能扩展的弊端设计的,用于扩展
TCP最核心的6个标志位:
URG:紧急指针是否有效
ACK:确认号是否有效
PSH:提示接收端应用程序立刻从TCP缓冲区把数据读走
RST:对方要求重新建立连接;我们把携带RST标识的称为复位报文段
SYN:请求建立连接,我们把携带SYN标识的称为同步报文段
FIN:通知对方,本端要关闭,我们把携带SYN标识的称为结束报文段
TCP核心应答机制(可靠性)
确认应答
T可靠性: A发给B数据,要尽可能让B收到
保证可靠性的前提是,A要知道自己发送的数据是否被B接收,需要B返回一个“应答报文”,A就确认B收到了。
但是A如果一连发送好几条信息,B返回的应答报文到底是哪一条信息的应答报文呢?
这种情况,就会导致交流牛唇不对马嘴。
TCP的处理方案就是给传输的数据编号,也就是TCP报头中的32位序号;应答报文中生效的是32位确认序号。
我们知道TCP是面向字节流的,TCP数据包部分编号时,按照“字节”编号,每个字节都分配一个编号,连续递增。
那么我们如何确定给此处数据写什么序号呢?
序号字段填写数据包部分的第一个字节的序号,后面依次递增;确认序号把收到的数据包的最后一个字节序号+1 填写到确认序号中。
B确认应答返回后,A确认1~1000位的数据收到了,接下来你从1001位开始发送数据。
这个时候即使出现“后发先至”,B可以根据序号对数据进行排序,再针对排序返回应答报文。(确保应用程序通过socket读到的数据顺序是准确的)
超时重传
网络传输时可能出现丢包情况,TCP的超时重传针对丢包做出处理。
判断出丢包的两种情形:A发给B的数据丢了;B返回给A的数据丢了。
TTCP中引入超时时间判断是否丢包(不能一直等待),假设A发送数据给B,丢包的超时时间阈值是T,如果B收到了数据,那就延长这个时间阈值,设定超时次数到一定数目,超过这个数量放弃这次传输,重新传输。
A不能判断超时究竟是哪种情况,只要没有接收到B的应答报文,超过超时时间就重传。如果B接收到数据,只是应答报文没有传到A,A触发超时重传,这个时候B可能会收到两份一样的数据,TCP内部根据序号排查,在缓存区中如果存在就直接丢弃,不存在才放入排序中。
连接管理
TCP与UDP不同,通信双方TCP报头中保存了对方信息。
三次握手
TCP通过“三次握手”方式来完成,客户端主动发起。
这就是相当著名的三次握手问题,初步判断网络通信链路是否通畅;验证双方发送和接收能力是否正常;协商关键信息,比如初始序号。
处于具体什么状态:
四次挥手
客户端和服务器端都可以主动发起FIN(看谁先调用close),一般还是客户端
谁是主动发起FIN的一方,就会进入TIME_WAIT
谁是被动发起FIN的一方,就会进入CLOSE_WAIT
TIME_WAIT:防止ACK丢包,等待FIN重传
CLOSED_WAIT:A发给B FIN 后,B直接返回ACK,但是直到B再发FIN的这段时间,具体逻辑程序员自己决定。
LAST_ACK:B完成了收尾工作,给A发送FIN
批量传输
为了实现TCP的可靠性,不得不付出一些代价,那就是效率问题。
我们不再发送一个数据等待一个数据的发送方式,而是发送到一定量后再等待,用等待一组ACK的时间等待多组
按照一定量发送,只要收到一个ACK就发送下一条
当然,滑动窗口也会丢包,分两种情况:
数据包成功到达,但是ACK丢了。
这个时候其实不用处理,虽然没有收到1001的回复,但是1001~2000发送接收都正常,2001的ACK能覆盖掉前面的ACK,这个序号的含义就是:该序号之前的数据都收到了。
数据包丢了
这个就涉及到一个快速重传,在传输数据量多,形成滑动窗口,某区间数据包丢包时,使用快速重传:谁丢了重传谁
流量控制
滑动窗口的窗口越大,效率就越高,但是不能无限大,要考虑接收方的处理能力
流量控制就是给发送方一个限制, 让接收方根据自身处理数据的速度,反馈给发送方(ACK)。限制发送方发送的速度。
这个ACK就是TCP报头中的 16位窗口大小(接收方接收缓存区的剩余空间大小),发送方按照这个数据设置窗口大小,控制发送端发送速度。
既然是16位窗口大小,那滑动窗口的大小是否最大数值就是64Kb呢?
其实不然,TCP报头中选项中有一个窗口拓展因子,所以实际上窗口大小是:窗口大小<<窗口拓展因子 (导致窗口大小成指数增长)
还有一个细节,假如接收端的接收缓冲区满了,ACK就会告知发送端满了,保持等待,但是发送端不会一直等,过了重发超时时间,发送端会发送一个窗口探测包,问一下接收端能发送了吗,如果接收缓存区有位置了,就会通知发送端继续发送。
拥塞控制
刚刚流量控制是依据接收端处理速度进行控制发送端速度的,那么拥塞控制就是依据传输链路的转发能力进行限制
传输链路中和涉及到很多设备,到底哪个设备转发存在限制,我们不得而知,那么只能按照限制能力最低的发送数据;如果不丢包,加大速度,出现丢包,减小速度,在这个过程中,窗口一直在动态变换。(类似和面,水多了加面,面多了加水)
既然拥塞控制和流量控制都能限制发送端的窗口大小,那这两个值谁小谁说了算。
延时应答
默认情况下,接收端都是在收到数据的瞬间就返回ACK,但是可以通过延时返回ACK的方式提高效率。
等待过程中,应用程序会消耗接收缓存区中的数据。
肯定不是所有包都延时应答,一般情况下:
数量限制:每隔N个包就应答一次(数据密集)
时间限制:超过最大延时时间就应答一次(数据稀疏)
捎带应答
在业务场景中,客户端发出请求,服务端会响应,返回响应的时候把上次的ACK捎带回去。再次提高效率。
粘包问题
因为TCP是字节流传输,数据包之间没有很明显的界限,很难区分从哪里到哪里是一个完整的应用数据包。
这个问题TCP无法解决,需要站在应用层角度解决:
1. 约定包和包之间的分隔符(包的起始标记和结束标记)
2. 约定包的长度
异常情况处理
- 某个进程奔溃,本质上就是退出,释放进程,回收文件描述符表的每个资源,继而调用socket的close,触发四次挥手,断开连接
- 主机关机,四次挥手如果发送端主机突然关机,没有接收到接收端的FIN,意味着接收端不会有ACK,即使重传,也不会有,几次重传之后,接收端只能主动放弃连接。
- 主机掉电,台式机突然断电可能导致硬盘上写入的数据会出错
完结
可以点一个免费的赞并收藏起来~
可以点点关注,避免找不到我~ ,我的主页:optimistic_chen
我们下期不见不散 ~ ~ ~