作者简介:大家好,我是未央;
博客首页:未央.303
系列专栏:JavaEE初阶
每日一句:人的一生,可以有所作为的时机只有一次,那就是现在!!!!
2.5 连接管理(面试中最高频的问题.网络知识中,最最高频的考题,没有之一!!!)
前言
本节内容我们将介绍有关TCP与IP的有关协议,介绍了其中最重要的几个知识点;
比如三次握手四次挥手,滑动窗口,流量控制等等;
一、TCP/IP协议五层协议栈;
1.1 应用层协议;
1)介绍:
咱们自己编写的应用程序,就是在应用层;
(也是实际开发中最常打交道的)
虽然应用层里面有一些现成的协议. 但是咱们在工作中少不了一个重要的事情, 自定义应用层协议;
自定义应用层协议相当于发明协议;
协议就是约定,约定好客户端和服务器;按照啥样的格式来传输数据;
2)应用层协议是如何约定的?
举例说明:(回显服务器)
约定了:每个请求,都是以\n结尾;每个响应,也都是\n结尾.
scanner.next();这是一个非常简单的约定;
3)自定义应用层协议,需要从两个方面入手:
1.考虑清楚,交互过程要传递的信息有哪些;
举例说明:
点外卖的案例;
比如我们现在需要在美团上面点一个外卖;
1)启动程序,涉及到网络交互.(交互中涉及到哪些信息的传递,和需求又是密切相关!)
请求:需要用户的身份信息,位置信息;
响应:商家的信息(商家名称,商家的评分,商家的位置,商家的预览图)
2) 点击某个商家,涉及到网络交互.
请求:用户信息,点击的商家信息;
响应:该商家的详细情况(有哪些外卖可以点,每个菜都是多少钱,评价如何,销量多少,预览图,分类信息)
2.考虑清楚,这些信息组织格式;
方式一:
直接使用简单分隔符来对不同部分的信息做区分;
注意:使用的;以及\n都是可以灵活的替换成其他符号的;
方式二:
使用固定长度来区分是从哪里到哪里的一个信息;
方式三:
上述的两种风格,还可以混搭.
有些字段使用固定长度,有些字段使用分割符;
上述格式,比较的简单粗暴;
除此之外,还有一些业界更通用的数据约定的格式;但是格式就要更复杂些了;
方式四:
通过XML的格式来约定数据;
方式五:
json.相比于xml更常用的数据组织形式;
方式六:
总结:
咱们应用层协议数据格式,有很多种可以参考的方式!!!
在实际开发中,就要根据实际的情况来决定使用哪种更合适;
应用层不仅仅是可以写代码自定义协议,也有一些现成的协议,可以直接使用的.
其中最著名的就是HTTP协议 (后面的课程再介绍)
二、传输层协议;
2.1 UDP协议;
1)UDP协议端格式:
实际情况的格式:
1.源端口号和目的端口号;
使用的是ip地址;主要用来区分当前是哪个主机;
一个主机上可能有多个应用程序,使用端口号来区分应用程序;
eg:送快递的话;
源端口号就是发件人电话;目的端口号就是收件人电话;
2.UDP长度;
一个UDP数据报最长就是64KB;
为啥不把UDP协议升级更新下?把长度用更大的字节(4字节, 8字节)
原因:
UDP已经内置到各个操作系统内核中了;发布到全世界无数的主机中了.
要想进行升级,就得要求全世界的主机的操作系统都统一升级到这个新版本的UDP才行.
万一有一部分没升级.... UDP就无法工作了.
务必要考虑到升级带来的影响!!很多的升级操作,都要考虑到"兼容性";
3.UDP效验和;
1)作用:
接收方,收到了数据之后,就得验证下,看看当前的数据是否是正确的!!因为网络传输中,传输的数据,不一定是准确无误的!!!
本质上是光信号/电信号;使用不同频率的光信号,表示1-0,使用不同电平的电信号,表示1-0;
干扰就可能造成"比特反转";
2)举实例说明:
比如生活中买电脑台式机(组装的);
就需要选配置;买之前就需要确定每个硬件的配置单;
电脑商家把电脑组装好了,发给你的时候,会带着配置单一起再发给你.
拿着这个配置单,来检查看这里的每个部分都是是否匹配;所以这里的配置单就起到了效验的效果;
3)使用流程:
UDP传输数据,网络上的数据是可能收到干扰;
发送的时候,针对要传输的数据,计算一 个"校验和”(相当于配置单);
发送的时候,把数据连带校验和一起发送过去;
接收的时候,针对收到的数据重新计算校验和,对比一下自己计算的校验和和发来的校验和是否是一样的;
如果是一样的,就说明数据没啥问题;不一样数据就有问题的;
效验和的注意点:
校验和,不仅仅是在UDP这里,很多别的地方也会涉及到;
只要是数据传输可能出现问题,都可以使用校验和的思想;
2.2 TCP协议;
1)特点:
1.有连接;2.可靠传输;3.面向字节流;4.全双工;
2)可靠传输:
可靠传输,是TCP最核心的部分. TCP内部的很多机制,都是在保证可靠传输;
(1)概念:
传输了数据之后,对方收没收到,我心里清楚;
而不是说,发出去之后,对方100%能收到!!毕竟极端情况,网线断了.
(2)可靠性是如何保证的:
通过确认应答的操作;
举实例说明:
比如汤老师约女神去吃饭;
当我收到这个应答的报文的时候,就知道了对方一定是收到了!!
如果我没收到,估计是不是对方没看到,或者短信发丢了(十几年前经常见到的);
情况1:
但是在网络上存在后发先至的问题;
所以说在后发先至的背景下,不能通过顺序;
来判断当前应答报文是在应答哪个数据;
解决上述问题的方法,我们可以通过编号来解决;
总结:
TCP在解决可靠性传输的时候;核心机制是确认应答;
确认应答需要通过序号进行控制;需要通过序号来知道我们当前应答的报文是在应答哪一条;
2.2.3 序号
1) 图示说明:
由于TCP是面向字节流的,编号的时候,也不是说按照"条"的方式遍的,而是按照字节来编;
举例说明:
现在有两台主机A,B,他们之间进行链接;
1.这一口气,发了1000个字节的数据;
TCP报头中的序号是1,整个报文长度是1000;
2.应答报文中的确认序号,就是1001 ;
应答报文,可以视为只有TCP报头,没有载荷;
在这个报头里,确认序号字段,填写了1001 .意思就是<1001的数据,B已经收到了.接下来A要从1001开始往后发送!!!
3.4类似1.2;
如何区分,一个报文是普通的报文,还是应答报文呢?
TCP报头;
在TCP报头中,有六个非常重要的bit位.其中第二位,ACK就表示是否是应答报文;
ACK为0表示不是应答报文;ACK为1表示是应答报文;也把应答报文称为ACK报文;(ACK就是acknowledge)
2.3 UDP和TCP协议传输的区别;
1.UDP协议传输
B这边调用recv方法;每次调用recv就是从接收缓冲区里取走一个数据;在应用层写代码的时候,感知到的事情;
第一次调用,读取出来的一定是1111;
第二次调用,读取出来的一定是2222;
第三次调用,读取出来的一定是3333;
UDP的接收缓冲区,相当于一个链表,里面有三个节点.每次读,都得以节点为单位;
2.TCP传输协议
InputStream. read(buffer)
byte[1] buffer读出来的就是1;
byte[3] buffer读出来的就是111;
byte[5] buffer读出来的就是11112;
byte[7] buffer读出来的就是1111222;
TCP 的接收缓冲区,更像是一个数组.若千个TCP 数据报的载荷会一直追加到这个数组里,彼此之间融为一体;
总结:
面向字节流和面向数据报,主要是在影响代码是咋写(影响着应用层)!!!
而在传输层自身这里;仍然是一个一个报文的方式来传输的.
(传输了报文,不意味着"面向数据报",两个不同的概念)
2.4 超时重传;
1) 超时重传的原因;
在确认应答的情况下,如果收到了ACK,就好办.如果没收到呢??还需要通过其他途径来处理!!
此时我们就会用到超时重传的方法;
不是说没收到ACK,立即就放弃;而是需要重新再发一遍;
网络的环境是非常复杂的.尤其是有些时候,网络会拥堵;拥堵就可能导致丢包
丢包:丢包,是"无差别"丢的.
任何一个数据报,都有可能会丢包!!
发的普通的报文,可能丢;发的ACK也是可能丢的!
2)丢包的分类情况:
(1)业务数据丢了:
发送方等待一定的时间之后,没有收到ACK就会重传数据;
(2) ACK丢了:
业务数据已经到了主机B了!!反馈的ACK没有回过去;
发送方等待一会之后,就触发了重传;这个情况下,B收到了两份1-1000这个数据!!!
所以说此时,如果在应用层调用read,读出来的是1份数据好,还是读出两份一样的数据好?
肯定希望读出一份数据好,节省内存空间;
此时,接收方(B)会根据序号,来进行数据去重;
B知道自己都收到了哪些数据.当发现又收到了一份之前的数据,就会自动丢弃,保证应用层读到的数据是不重复的!!!
总结
对于发送方来说,无法区分是业务数据丢了,还是ACK丢了.
因此发送方能做的只是,达到一定时间之后,就重传!!!!!!
3):超时重传机制下,发一个数据丢包了;重传数据,是否还会再丢包呢?
当然是可能的;
但是站在概率的角度来看,就比如假设一次传输数据,丢包概率是10%(已经是一个很大的数字了)
A->B发一次数据,丢包的概率10% .A->B连续发两次都丢包的概率10%* 10%=> 1%;
丢包操作,还有一个超时时间.
超时时间具体是多少,在操作系统内核是可以配置的;
eg:
第一次传输丢包,超时时间是t1‘;
第二次又丢包,超时时间是t2;
t2 > t1;这里的等待时间间隔,随着时间的推移,要越来越大;
如果连续两次都没发过去,意味着当前单次发送的丢包概率已经相当大了!!
连续重传之后又丢包的次数越多,此时意味着单次发送的丢包概率就更大;很可能是网络上遇到了非常严重的故障,短期内恢复不了.多次发送也没什么用了;
注意:
超时重传也不会无限制的重传下去.尝试几次之后,仍然无法传输过去,此时就会放弃尝试,然后就只能断开连接尝试重连.如果重连也还是连不上,就彻底放弃了;
2.5 连接管理(面试中最高频的问题.网络知识中,最最高频的考题,没有之一!!!)
TCP是有连接的协议;需要建立连接和断开连接;
2.5.1 建立连接(“三次握手”)
"三次握手"主动的那一方是客户端.三次握手,一定是客户端先发起的!!
1) “三次握手”的流程;
图示举例说明:
经历了这四次交互,就完成了建立连接的过程;
两对操作:客户端和服务器,互相给对方发送了一个SYN,再互相给对方发送了一个ACK;
一共是四次交互,完成了这个过程;
为啥还是叫做"三次握手"???因为中间的两次可以合并成一次!!
原因:
每次数据报文传输,都要经过一系列的封装分用!!分成两个包来发,就比一个包,代价大很多!!
eg:两个单,商家合并成一个快递给我发过来;成本低!!!运费只需要付一份就行了!!
注意:
三次握手的时候,B返回的ACK和SYN都是内核收到A的SYN之后,立即返回!!!
2)为什么要“三次握手”??
三次握手,认为是一种保证可靠性的机制!!这个东西相当于“投石问路";
在正式通信之前,先确定好通信链路是否畅通!!!如果通信链路不畅通,后续大概率要丢包!!
eg:地铁/高铁.......一早上第一趟车,都是空车先跑一遍(投石问路)
但是为啥三次握手要握三次呢?四次行不行?(行,但是没必要,因为效率低)两次行不行?铁定不行的!!
三次握手也是在验证通信双方的发送能力和接收能力是否正常!!!
举实例说明:
3)三次握手的重要意义;
能够让通信双方协商一些重要的参数!!
eg:
两个人商量;比如,像序号要从几开始(实际上,一次连接中的序号不一定是从1开始的).包括MSS ;
举例说明:
总结三次握手的意义;
1.投石问路,验证通信双方发送/接收能力是否正常;
2.协商重要参数;
2.5.2 断开连接(“四次挥手”)
四次挥手:断开连接的流程;
三次握手,客户端主动发起第一次.
四次挥手,客户端和服务器都可以主动;
1)四次挥手的流程:
图示举例说明:
和三次握手不同,四次挥手,看起来也是双方各自给对方发送FIN各自给对方发送ACK;
但是这里是四次挥手!!中间两次,不一定能合并!!
不能合并的原因:
B返回ACK是内核的行为.操作系统内核收到FIN之后,就会立即返回ACK.
而接下来B的FIN是用户代码的行为.用户在代码中调用socket.close方法,才会触发FIN !!!
因此,B发送FIN和发送ACK之间会有不可忽视的时间间隔!!正因为有时间间隔了,就不能合并!!
TCP还有一个机制,延时应答和捎带应答.(后面再讲)
2.5.3 三次握手;四次挥手总结;
举实例说明:
如果把建立连接,理解成入职;
B这边,属于没工作的状态,A抛出橄榄枝了,B立即就同意了.
断开连接,就是离职;
A通知B,你被解雇了,你自己提交一个辞职报告吧; B是有一些工作交接的;
所以说:
建立连接,是没有历史包袱的.立即就能完成;
断开连接.很可能A=>B发FIN的时候,B还有数据没读完.B一般不会立即断开,要把未处理的数据都处理完了再说;B啥时候发FIN就是代码层次的了.
2.6 滑动窗口
1)作用:
提高传输效率的机制;
2)本质:
就是把等待ACK的时间重叠起来.
减少等待时间,就相当于提高了效率!!
注意:
可靠性和效率是冲突的!!保证可靠性肯定会影响到效率的!!
TCP在可靠性的前提下,尽可能的提高效率;
3)图示说明其功能的体现:
之前:
每次传输,都需要等待ACK,收到ACK再发下一条数据;
使用滑动窗口之后:
不再是一次发送一条,等待一条;而是一次发送一批,等待一批ACK;
在不等待的前提下,最多可以一次发N条数据;(N指的是窗口大小)
这里的N越大,则同时批量发的数据,就越多,传输效率就越高;
但是N也不是越大越好;传输效率=发送效率&接收效率;
3)扩展:
每一小块都是一个TCP数据报;
白色的区域,当前已经批量的发送了:
??????????????????????????????????
4)在滑动窗口之下,可靠性是否有影响呢?
确认应答,还是正常应答,没啥影响;
5)超时重传,有影响嘛?在滑动窗口下,丢包了,该咋办?
丢包的情况分为两种:
1.数据报丢了;
2.ACK丢了;
(1)情况1:数据报抵达;ACK丢了;
如果1001丢了,2001到了;
此时对于A来说,就知道1-1000这个数据也是到了的!!!后一个会涵盖前一个;
(2)情况2:数据包直接丢了;
主机A发了半天之后,看到了连续好几个1001,就明白了,怕是1001丢了!!!!!
接下来,A就会重传1001这个数据了!!!!!
此处的原则是,哪条丢了,就重传哪条;
已经传输到的数据,不必重复传输;
快速重传:不是说重传的有多快,而是没有冗余的动作;
举实例说明:
注意误区:
说,滑动窗口能提高效率,指的是相比于没有滑动窗口的普通的确认应答;
但是如果和无可靠性的传输相比(UDP),效率还是要差一些的!!
说它是提高效率,不如说是在补救低效率.
2.7 流量控制
1)概念:
滑动窗口,窗口大小越大,发送速率就越快!!
而流量控制就是限制滑动窗口的重要机制!!
流量控制,就是在针对发送速率进行制约;
整体的传输速率=发送速率&接收速率;
如果发送速率>接收速率;这个时候继续提高发送速率,不能够提高整体的效率了!!!
反而会因为接收方丢包,触发更多的重传,反而还降低了速率;
2)
现在要做的是,要让发送速率和接收速率相当(步调一致)
发送数据时候的窗口大小用于衡量发送速率;那么接受速率如何衡量呢?
3) 接收方如何把接收缓冲区剩余空间,告知发送方呢???
可以在ACK这个报文中带上这个信息!!
当16位窗口大小当前是ACK报文的时候会生效;
这个窗口大小,就表示了接收缓冲区的剩余空间大小;
根据这个大小就可以进一步的影响到发送速率了;
举实例说明:
可以建立一个蓄水池的场景;
2.8 拥塞控制
流量控制,站在接收方的角度,来控制发送速率!!!!
但是整体的传输,其实不光有发送方和接收方,还有中间的一系列用来转发的设备!!!
控制A发的快慢,不能光考虑B的接收能力,也要考虑中间设备转发能力!!!
也就像木桶原理:能装多少水,取决于最短的木板;
衡量B的处理能力,是使用了B的接收缓冲区的剩余空间;
要想衡量中间的设备,咋办?
1.中间的设备都有几个??
2.中间的设备各个参数是啥??
3.两次传输,经历的中间设备是否相同??
等等...........................
拥塞控制,采取的办法,做实验!!
通过实验的方式,找出一个合适的窗口大小!!
1.刚开始按照小的窗口来发送;
2.如果不丢包,说明网络中间环境比较畅通;就可以逐渐放大发送窗口的大小;
3.放大到一定程度,速率已经比较快,网络上就容易出现拥堵;进一步出现丢包!!!
当发送方发现丢包之后;就减小发送的窗口;
之后就反复在2-3之间循环!!
这个过程,就达到了一个动态平衡";
发送速率不慢,接近了能承载的极限;同时还可以尽量少丢包;
还能够适应网络环境的动态变化;
2.9流量控制和拥塞控制的联系;
流量控制和拥塞控制都能影响发送方的滑动窗口大小!!!
最终的滑动窗口大小,就取决于流量控制的窗口和拥塞控制的窗口中的较小值;
都是通过控制窗口大小,来制约发送方的发送速率的;
在保证可靠性的前提下,尽量提高一下发送的速度;
(1)如果是拥塞控制的窗口大,流量控制的窗口小;
则中间节点的转发能力强,接收端的代码处理的慢;
(2)如果是拥塞控制的窗口小,流量控制的窗口大‘
则中间节点的转发能力弱,接收端的代码处理的快;
拥塞控制的窗口:发送方自己做实验做出来的;
流量控制的窗口:接收方通过接收缓冲区剩余空间大小
通过ACK报文的报头返回给发送方的;
上述两者最终发送方下一次发送的窗口大小就是通过这两个值的较小值,来确定的
2.10 延时应答;
1)概念:
也是一个用来提高效率的机制.
延时应答,则是让窗口能够大一些!!让流量控制别限制的太狠;
2)工作原理:
举实例说明:
2.11 捎带应答
1)作用:
基于延时应答的策略;为了提高传输效率;
2)工作原理:
正常来说ACK是收到请求之后,内核立即返回的;
响应数据,则是应用程序代码,发送的;
上述两者处于不同的时机,就不能把上个ACK和下个响应报文合并;
但是上面介绍延时应答
延时一会,就可能和返回响应数据,时间上就重合了;
响应在收到请求之后,多长时间之内返回??
不确定!!可能快(几个ms),也可能慢!!!(几百ms);
本来也要发送数据报文;就搭个顺风车,直接就走了呗;
2.12 面向字节流
1)概念:
面向字节流,指的是读写载荷数据的时候,是按照"字节流"的方式来读取的.
TCР数据报,本身仍然是一个一个"数据报"这样的方式来传输的.(应用程序这里,感知不到从哪里到哪里是一个数据报的)
2)图示举例说明:
优点:
可以一次读M个字节,分N次读;
此时,应用程序,在读取数据的时候,就可以很灵活的进行了;
缺点:
面向字节流的最核心的问题:粘占(nian)包问题!!
如果一个TCP连接,里面只传一个应用层数据包,这个时候,不会粘包;(短连接)
如果一个TCP 连接里,传输多个应用层数据报,这个时候就容易区分不清,从哪到哪是一个完整的应用层数据!![粘包问题](长连接)
粘占(nian)包问题实例:
上述数据aaabbbccc; 这些数据都进入接收缓冲区了;
接收方就区分不了,这些数据是来自于几个应用层数据;
也区分不了从哪到哪是一个应用层数据报;
3)粘占(nian)包问题出现的原因及其解决方案;
粘包问题,根本原因,是TCP面向字节流.但是直接影响,却是影响的应用层的代码;
粘包问题的解决方案:
在应用程序代码中,明确包之间的边界;
1.使用分隔符;
2.约定长度;
1.2属于自定义应用层协议的知识点;
2.13 TCP连接出现异常时,如何处理?
1)主机关机(按照固定程序关机)
按照程序关机,会先杀死所有的用户进程(也就包括咱们自己写的tcp程序);
杀死进程=>释放进程PCB=>释放文件描述符表上对应的文件资源(相当于调用close );
这个时候就会触发FIN,开启四次挥手的流程!(这里的异常情况,还是比较好处理)
如果在挥手挥完了,继续关机(没啥特殊的);
如果还没挥完,就已经关机了,对端重传FIN若干次,没有响应,也就放弃了;
2)程序崩溃
同上. 程序是正常关闭,还是异常崩溃,都会释放PCB,都会释放文件描述符表(相当于调用close);
也还是会正常四次挥手(虽然进程没了,但是本身TCP连接也是内核负责,内核仍然会继续完成后续的挥手过程);
3)主机掉电(突然拔电源)
笔记本还好(内置电源);
如果是台式机之类的,直接就没了!!肯定是来不及挥手;
1.接收方掉电.对方尝试发送数据,发现没有ack;尝试重传;重传几次,仍然没有ack ~~发送方尝试重新建立连接~~如果重新建立也不成,认为是当前网络上出现了严重问题~~~也就自然放弃了;
⒉发送方掉电. 接收方就在等待发送方发的数据.由于发送方没了~这个数据显然发不过来了;
接收方,不知道,是对方还没发呢,还是对方出问题了;(接收方区分不了)
接收方如果一段时间没有收到数据,就会定期的给发送方,发送“心跳包"
“心跳包":1.周期性的;2.判定对方是否存活的;
接收方,给发送方发一个特殊的报文(ping)
发送方,对方返回一个特殊的报文(pong)
如果有上述发的两个报文;就认为对方是正常的状态.如果ping没有对应的pong,就认为对方挂了;
4)网线断开
和主机掉电相同;
总结
今天的内容就介绍到这里,我们下期再见!!!!