网络原理主要将以四个层面进行学习 分别是 应用层 传输层 网络层 数据链路层 当然还有一个物理层,但是目前来看,学习物理层暂时收益较小~~
1.自定义协议
对于程序员来说,应用层才是发挥的舞台,为啥呢?因为每一个app或者说是软件,它们的协议需求都不尽相同,因此需要特定的一些协议来实现它们,这时候自定义协议就发挥了重要作用~
那么如何自定义协议呢?
1.明确业务需求,比如说你要写一个关于外卖的程序,当你打开列表的时候,就需要出现一些商家介绍等信息,需求分析是非常重要的环节
2.明确要响应的数据以什么形式或者说是格式表达出来,准确一点说是 明确传递的信息以何种方式来组织。常见的有XML,json等
2.传输层内的重要协议
传输层虽说是内核已经实现好了 ,但我们还需要是去了解其精髓的~~
首先明确俩个重要概念:
端口号 IP地址
我们可以带入一下,端口号相当于网购时你填入快递单的姓名,IP地址就是你家地址。
端口号是传输层里面协议中的重要概念,无论是UDP还是TCP都需要用到源端口目的端口,端口号基本上都是2个字节 其值范围是0-65535,这里需要注意的是前1024是默认给一些比较常见的程序来使用, 因此在程序的端口号设置方面要注意避开这些,
1.UDP协议
UDP的特点要明确:无连接,不可靠,面向数据报,全双工
UDP报文长度就是八个字节平均分成每个有2个字节的长度,载荷里面的内容就是应用层数据报
校验和 存在的理由是,在数据传输中会出现一些不可避免的问题,比如说我想给我的好友发送“在学校食堂等我”,但是因为网线/光纤出现问题(环境问题)等等原因,这个字段变成了“在宿舍等我”,就会出现问题,而校验和的存在 就是将载荷里面的内容通过数学模型 变成一段字符串,无论你的发送数据是多长都是是统一长度的字符串,随着UDP报文发送过去,这样就大大避免了以上问题的出现,常见的校验和有 MD5 : 通过复杂的数学模型进行转换 ,而其MD5算法有以下几个特性:
1.定长:长度都是一样的
2.不可逆:通过原始数据获得校验和比较容易,但是反过来推 理论上可能,但是计算量巨大,就相当于所有文字组合推导出MD5之后,再对着查
3.加密
2.TCP协议
TCP的特点:有连接 可靠传输 面向字节流 全双工
有连接 就是 双方只要建立连接才能进行传输数据,面向字节流和全双工都比较好理解 而其可靠传输这一特性是其内部机制。
1.源端口和目的端口和UDP提到的是一个东西
2.一个TCP整个报头的长度不像是UDP8个字节固定的 而是不确定的,因此就存在描述首部长度的位置。要注意的是 这里的单位 不是一个字节 而是4个字节:这里显示5就表示这个udp报头的长度是 4* 5 = 20 。另外还要注意的选项之前的报头固定长度是20 因此报头的长度-20就是选项的长度
3.保留的存在是为了以后进行TCP升级
4.校验和也是和UDP一样
5.选项就是进行对TCP一些属性的描述
剩下的我们无法直接去学习理解,还需要进行TCP内部的工作机制学习之后才能理解~~
TCP协议中的内部工作机制
TCP有很多复杂的机制 主要讨论以下十种比较重要的机制
之前提到的TCP的可靠传输这个特性,家人们还记得吗,它是如何实现的呢?(靠下述的俩个机制)
ps:要知道的是,可靠传输是如果数据没传输成功双方都知道,而不是保证百分百成功传输!
1.确认应答(是TCP可靠传输最核心的机制)
我们用一个场景来带入~~小刚对小红在手机上发送信息:
小刚如果在第一次发消息的时候,小红一直没回答,(先排除小红已读不回的情况哈!)就证明这个消息大概率没了(丢包),小刚看见没有回答就会知道,数据传输出现问题了,反之就会知道数据传输顺利成功了!TCP的可靠传输就是主要依靠确认应答机制!
但是还会出现其他更复杂的问题:
这种情况是“先发后至”问题,因此 滚 回答的是小刚请吃麻辣烫的问题,好啊好啊 回答的是 表白
大家应该在qq上经常遇见这样的问题,这问题也是比较常见的,俩台主机数据进行传输的时候,会有多种路线,而且各自的走到的路线上的路由器 交换机 网速也会不同,就会导致这个问题的出现,那么我们该如何避免呢?
给传输的数据和应答报文都加上序号
6.任何一个数据报文都是有序号的
其实这里的序号排队不是用数据来进行排序的,而是用的字节,假设第一个数据长度是1000个字节,再假设其是从1进行排序的(头一个字节的序号就是1),那么就在第一个报文中的报头中序号只记录下当前第一个字节的序号:1,那么第二个的数据记录就是1000+1 = 1001 依次累加!每个TCP报头填写的序号 只要是数据中头一个字节的序号就行~~因此只需要知道报文长度和头字节的序号就知道全部的字节的序号~~
用这个图更好理解
小结:
1.TCP的可靠传输就是主要通过应答机制来保证的
2.通过应答报文就可以明确数据是否成功传输
3.进一步的引入序号 和 确认序号 就可以让数据进行更详细的区分
2.超时重传
上面是一定程度保证了数据传输的可靠性,但如果已经丢包了捏?
丢包有俩种情况:
1.发的数据丢了
2.ack丢了
其实也好解决 就是 让其等待一段时间,如果过了这一段时间之后还是没有收到应答报文,就再传一个数据报。
这个时候还有一个致命问题,如果这个数据报只是在路上呢?再传相同的数据报,如果是交易请求 就要付俩倍的价格了~~
为了解决重复数据报问题 一方面来说 时间不好控制,那就利用一种可去重的数据结构进行去重呗~~这里有一种非常理想的解决方案:每个TCP的socket对象都有一个“”接收缓冲区“,而当数据报来的时候 先放进这个缓冲区内,把这个缓冲区可以想象成一个阻塞队列,不仅可以去重,还可以进行排序(将发送的数据进行排序),后续 应用程序里使用getInputStream,进一步使用read的时候,直接从缓冲区拿走就行。既保证了去重,还保证了有序使用。
ps:当你重复多次重传的时候,都没有回应,就没必要再重传了,进行断开重连等操作就ok 了~~而且一般情况来说,第一次重传的时间间隔和第二次第三次不一样,越往后基本上是时间越长,因为如果不这样,那么你重传的次数过多,浪费太多的系统资源。
小结:
1.TCP的可靠传输主要是通过 确认应答 和 超时重传 俩大机制来保证实现的
2.确认应答描述的是传输顺利的情况,超时重传是出现问题之后的解决方案。
3.连接管理
那么啥是连接呢?假设A主机和B主机要进行连接,那么A主机内部要有一个空间(数据结构)存储B的信息(ip 端口) ,相同的B也要存储A的信息。这时候俩部分的信息维护好之后,二者的连接就建立了~~把这些空间删除掉就是 断开连接。
建立连接:通信双方要各自记录对方的信息,彼此之间要互相认识
“三次握手”
用这个案例来理解:
三次握手还有一个重要的作用:验证通信双方各自的发送能力和接收能力是否正常。(当然三次握手一定程度上保证了TCP传输的可靠性,当然只是辅助作用)。
具体可以理解成 双方开黑 开麦
1.需要建立连接才能通信,如果连接断开了 就无法进行通信,连接建立过程种 需要双方各自保存对方的信息
2.有没有连接和是否确认应答 是没有任何关系的。确认应答体现的是“可靠传输”,三次握手体现的是“有连接”,二者毫无关联。
那么三次握手的意义:
1.建立二者的关联
2.验证双方通信间传输的接受能力和发送能力是否正常
3.在握手的过程中,需要协商一些参数
具体一点:
断开连接:
这里需要注意的是,被动方主动方 的身份都可以成为。
四次挥手
四次挥手也是像三次握手一样,只是形象的比喻,实际都是数据交互,都是通信双方各自向对方发送断开连接的请求,再互相同意~~
具体到代码上(第一次ack):
B->A FIN
挥手几个重要状态
因此TIME_WAIT就是防止意外发生, 或者说是保证左面的一方向右面的一方发送ACK报文。
具体要等多长时间呢?
2MSL,如果等到左面的一方在2MSL之后没有收到右面的一方的重传的FIN报文,就说明传输ACK成功了 ~~ 断开连接就完成了!
4.滑动窗口
确认应答,超时重传,连接管理都是给TCP可靠传输提供支撑的,但是我们要知道的是,获得了可靠性需要付出传输效率这一代价。
在IO操作过程中,最浪费时间的就是 等待 这一过程,因此滑动窗口本质上就是降低了确认应答 接受ACK的时间 ,或者说是合并一些等待ACK 的时间(批量发送,批量等待)。
那么滑动窗口是个啥呢?它是一种提升传输效率的机制,正常的传输是发送方每发一个数据,发送发就要等待接收方发出的ACK,但是如果引入了滑动窗口的机制,发送方根据规定好的窗口大小(把不需要等待的,就能直接发送的数据的最大量),库库发一堆数据给接收方,然后等待接收方来一个ACK,发送方就发一个数据,注意这里是动态变化的,但是总量是不变的 就好比有一个窗口在发送方,动态变化但总量不变。
这里可以形象比喻成加工线的场景,一个员工比较成主机A,一次工作岗位的最大容量4个半成品工件,做好一个送走(向主机B传输一个数据),来一个半成品来做(接受ACK),他的岗位容量是不变的,但是工作是动态变化的。
滑动窗口出现了丢包问题咋办呢?
丢包有俩种情况一个是ACK丢了 一个是数据丢了;如果是ACK丢了 ,是不需要我们去管的,因为确认序号的含义是这个序号之前传输成功了
那如果是数据丢了 呢?
上面的丢包重传方式,也叫做“快速重传”,(重传只重传丢失的数据)。
如果当前传输数据密集,就是用滑动窗口的机制,丢包重传方式也用的是快速重传
如果当前传输数据不密集,就正常处理就行。
5.流量控制
窗口固然很好,但是窗口的大小咋处理呢?这里就用到了另一个机制:流量控制。
流量控制是一种干预窗口大小的机制,而其是以接收方的处理能力为依据来进行干预的。
这个接收方的处理能力咋衡量啊?看接收方剩余的接收缓冲区大小。
每次A向B发送数据的时候,主机B都要计算一下剩余的缓冲区还有多少,然后填进ACK中发给A,A就知道了窗口大小~~
还有一些要注意的点:
1.这个计算剩余量的动态变化的,也就是说这个窗口大小也是动态变化的~~
2.而且当主机B剩余量不足的时候,主机A会向主机B发送没有业务需求的 窗口探测报文,看主机B缓冲区还有剩余吗
6.堵塞控制
流量控制和堵塞控制共同决定了发送方的窗口大小。只不过堵塞控制描述的是传输过程中的各个节点的传输能力~
但是这各个节点之间咋测呢?天才科学家们利用了实验的方法:
因此窗口的大小选值就是 堵塞控制 和 流量控制的较小值~~
7.延时应答
这个意义就是让窗口大小更大,让主机B等一段时间再发送ACK,这样就可以让主机B把缓冲区内的数据给消费完。此时剩余空间就大了嘛,窗口大小不就大了嘛~~
8.捎带应答
捎带应答也是一种提高效率的机制,啥意思呢?在四次挥手期间,不是在主机A向主机B发送数据之后,主机B立刻由内核直接发出ACK给主机A嘛,过了一段时间也就是代码走到地方,有程序发出FIN,这一段时间是有间隙的,但是由于有了延时应答的机制,所有将主机B向主机A发送的ACK和FIN可以合并在一起,发送给主机A~~
9.面向字节流
我们知道TCP有一特性就是面向字节流,这个好理解但是背后的问题我们也需要明确,那就是粘包问题:在经历多次的数据传输之后,主机B会将数据都存放到接收缓冲区内,但是不知道从何时开始,何时结束,所有程序在“read”的时候,很容易导致 一次读了“一个半数据”,或者是其他各种情况。这时候的处理的方式也很简单,在应用层方面的时候,就约定好协议,俩种方法:1.利用分割符。2.约定每个包的长度。
10.异常情况
异常情况有很多种,我们简要概括成俩大类,四小类