网络原理
传输层
UDP
特点
特点:无连接,不可靠,面向数据报,全双工
格式
怎么进行校验呢?
把UDP数据报中的源端口,目的端口,UDP报文长度的每个字节,都依次进行累加
把累加结果,保存到两个字节的变量中(校验和)
加着加着,可能就溢出了,但是溢出也无所谓,所有字节都加一遍,最终就得到了校验和
传输数据的时候,就会把原始数据和校验和一起传递过去
接收方接收到数据,同时也收到了发送端送过来的校验和(旧的校验和)
接收方按照同样的方式再计算一次,得到新的校验和
如果旧的校验和跟新的校验和相同,就可以视为数据传输过程中是正确的
如果不同,就认为传输过程中出错了
数据相同=>校验和相同
校验和不同=>数据不同
但是
校验和相同,难道数据就一定相同嘛?不一定!!!
正好可能某个字节多了一个1,后面一个字节少了一个1,两者相加,正好抵消
CRC校验确实不那么严谨,但是在工程上也足够用了
也有一些其他的算法进行校验,可以达到更高的精度,但是需要更多的代价,因此没必要
如果一个UDP报文出错了怎么办?
丢弃!(而TCP出错了就可以要求重新发,这也是TCP可靠性的一种体现!)
TCP
1.确认应答(可靠性机制)
TCP的可靠传输是内核实现的,写代码的时候是感知不到的
可靠传输的实现机制是 确认应答(我给对方发消息,对方收到之后给我一个应答说确认收到了),确认应答是保证可靠传输的最核心的机制
再说一下确认应答的后发先至
比如我给女神发消息
本来是
结果是
当连续发多条数据的时候,可能就会出现后发先至的情况(一个数据报是先发的,反而后到了)
怎么产生的呢?
那该怎么解决呢?
,ikk
这里的tcp确认应答跟我们的例子有两个不同
1.针对字节进行编号的,而不是“条数”
2.应答报文也是要和收到的数据的序号相关联的,但是不是“相等”
网络上很多关于这个问题的解释是错误的!
比如tcp保证可靠性的核心机制是"三次握手"
2.超时重传(可靠性机制)
在传输数据的过程中,还可能发生**“丢包”,也就是发送一个数据,然后丢失了
在两个主机之间,网络的结构是非常复杂的,中间要经过很多路由器和交换机,这些路由器和交换机同时也连接着其他的路由器和交换机,这些结果错综复杂,传输的数据量也是不确定,有时候传输的数据可能会多点,有时候可能会少点
如果设备太繁忙,这些数据包就需要等待,如果等太久了,就可能被丢弃了,网络负载越高,线路就越繁忙,就越容易丢包
真的出现丢包怎么办呢?
重传!设置一个时间,在规定的时间里面没有收到回应,就重新传输这个数据,这个就叫做超时重传**
超时重传相当于针对确认应答进行的一个重要补充,因为要保证可靠性
丢包有两种可能性,如下图
如果网络已经出现严重故障,复位操作也无法成功,最终只能放弃连接,只能把自己保存的对端的信息删除掉了
核心就是一句话:确认应答是tcp保证可靠性的最核心机制;超时重传是TCP可靠性机制的有效补充
3.连接管理(可靠性机制)[网络这个模块最常考的部分]
1.建立连接(三次握手)
上述只是简单描述了一下三次握手,实际的三次握手比这个更加复杂,如下图
如果面试中面试官问你TCP三次握手是怎样的过程
三次握手的意义是啥,要完成什么目的?
三次握手也是保证可靠传输的一种重要途径
tcp的三次握手,就是要验证网络通信是否畅通,以及验证每个主机的发送能力和接收能力是否正常
2.断开连接(四次挥手)
连接双方,各自在内存中保存对端的相关信息,如果不需要连接了,就得及时释放上述存储空间
四次挥手的流程和三次握手非常相似
三次握手必然是客户端主动发起来的,但是四次挥手不一定,服务器也可以主动发起,大多数还是客户端发起的
还有一些极端情况,比如A在等待2MSL时间的过程中,B在反复重传FIN多次,这些FIN都丢了(理论上存在这种情况),这时候网络一定存在严重故障了,这个时候不具备可靠传输的前提条件了,因此A就单方面释放资源也无所谓了
再谈
TCP式如何实现可靠传输的?
确认应答
超时重传
连接管理(三次握手,四次挥手)
这些机制都起到了作用,在三次握手中,一旦路探完了,后续就没它事了,网络环境事多变的,可能这会畅通,过会就堵塞了,而确认应答,是保证每次传输的这些数据都是可靠的,因此真正起到决定性作用的还是确认应答!
那么TTL和MSL都是存活时间,有什么区别呢?
4.滑动窗口(提高传输效率)
更准确地说,是让TCP在可靠传输的前提下,效率别太拉跨,因为可靠传输效率已经降低了
使用滑动窗口,不能让TCP变得比UDP快,但是可以缩小差距
那么问题又来了,现在按照这种批量的方式传输,中间丢包了咋整?
对呀TCP来说提高效率必然不应该影响到可靠性
丢包分为两种:
1.数据丢了
2.ACK丢了
下面让我们来看看滑动窗口下的超时重传机制是怎么样的
快速重传是超时重传结合滑动窗口产生的变形操作(本质还是超时重传)
使用TCP的时候不一定就涉及到滑动窗口
如果你通信双方大规模传输数据,肯定是滑动窗口(此时按照快速重传来工作)
如果你通信双方大规模传输数据比较少,这个时候就不用滑动窗口了(仍然按照之前的超时重传来工作)
5.流量控制(作为滑动窗口补充)
滑动窗口的窗口越大,传输效率越高
但是窗口也不能无限大,如果窗口太大了,就可能使接收方处理不过来了,或者是使传输的中间链路处理不过来,这样就会出现丢包,就得重传了,这时候窗口大并没有提高效率,反而降低效率了
流量控制就是给滑动窗口睬踩刹车,避免窗口太大,导致接收方处理不过来
光考虑接收方,还是不够的,还需要考虑中间链路的处理能力(也就是拥塞控制)
6.拥塞控制
总的传输速率是一个木桶效应,取决于最短板
具体怎样衡量中间设备的转发能力呢?
此处并不会对中间设备的转发能力进行量化,而是把中间的设备都看成一个整体,采取“实验”的方式,动态调整,产出一个合适的窗口大小
使用一个较小的窗口传输,如果传输通畅,就调大窗口
使用一个较大的窗口传输,如果丢包,就调小
这是一种工程师思维
这样做也可以非常好的适应网络环境的动态变化
实际发送方的窗口=min(拥塞窗口,流量控制窗口)
拥塞控制喝流量控制共同限制了滑动窗口机制,可以让滑动窗口能够在保证可靠性的前提下,提高传输效率了
也就是说拥塞控制和流量控制也是保证可靠性的机制
7.延迟应答(提高传输效率的机制)
(延迟应答也是围绕滑动窗口来展开的)
是否有办法在条件允许的基础上,尽可能地提高窗口大小呢?
需要在返回ack的时候,拖延一点时间,利用拖延的这个时间,就可以给应用程序腾出来更多的消费数据的时间,这样接受缓冲区的剩余空间就更大了!
此处通过延时应答到底能提高多少速率,还是取决于接收方应用程序实际的处理能力
8.捎带应答
在延迟应答的基础上,引入的第一个进一步提高效率的方式
延迟应答使让ack传输的时机更慢
捎带应答使基于延迟应答,让数据进行合并
9.面向字节流(粘包问题)
属于TCP的特性,不过我把它写在了下面应用层
10.TCP异常情况的处理(经典面试题!!!)
网络本身就会存在一些变数,导致tcp连接不能继续正常工作了
比如
1.进程崩溃
进程崩溃=>
进程没了=>
PCB没了=>
文件描述符表也就被释放了=>
相当于调用socket.close()(socket在系统内核中也是一个文件,也会被放到文件描述符表中)=>
崩溃的这一方就会发出FIN,进一步的触发四次挥手,此时连接就正常释放了
此时tcp的处理和进程的正常退出没啥区别
2.主机关机(正常步骤的关机)
3.主机掉电(拔电源,没有任何反应的空间)
虽然TCP中有心跳包的支持了,但是还不够,往往还需要在应用层的应用程序中重新实现心跳包。因为TCP的心跳包周期太长了,是分钟级别的,而在现在大数据的高并发的特点下,分钟级别是不够的,需要秒级甚至毫秒级的心跳包,这样就可以在更短的时间内,发现某个服务器出现问题
4.网线断开
网线断开相当于主机掉电的升级版
以上就是TCP的十个主要特性,并不是只有这十个特性,还有很多特性在标准文档中
TCP和UDP的对比
应用层
面向字节流
在面向字节流的情况下,会产生一些其他问题
粘包问题
这里的“粘”是“应用层数据报”
通过tcp的 read/white的数据,都是tcp报文的载荷,也就是应用层的数据
发送方一次性是可以发送多个应用层数据报的,但是接收的时候,如何区分,从哪里到哪里是一个完整的应用数据报呢?如果没设计好,接收方就很难区分,甚至会产生bug!!
比如发送是两个包,读可能读了半个或者一个半,这个时候就会产生问题
此处正确的做法,是合理的设计应用层协议
这件事在传输层已经是无解了,因为站在tcp的角度,它只认字节,无法区分是哪个包
因此就需要站在应用层角度来解决这个问题了
可以在应用层协议中,引入分隔符,区分包之间的边界
或者在应用层协议中,引入“包长度”,也能区分包之间的边界
粘包问题不仅仅是tcp才有的,只要是面向字节流的机制(比如文件)都会有同样的问题,解决方案也都是一样,要么使用分隔符,要么使用长度来区分
在自定义应用层协议的时候,就可以使用这种思想来解决问题了
网络层
IP协议
IP协议虽然复杂,但是在这里只是简单讨论,实际开发中用到的并不多
IP地址
IP地址采用点分十进制的一种方式,可以让你知道别人电脑的位置,也可以让别人知道你的电脑的位置
IP地址不够用了咋整?
1.动态分配(DHCP)
你这个设备需要上网的时候就分配给你,不需要的时候就把你的IP地址收回,这种方案,只能缓解,不能根治
2.NAT机制
将IP地址分成了两大类
内网IP:不同局域网内的设备,内网IP可以重复;同一个局域网的设备,内网IP不能重复
范围:
10.xx.xx.xx
172.16x—172.31.xx
192.168.xx
外网IP:外网IP不能重复
在你的电脑控制台输入ipconfig,得到的IP地址就是内网IP,如果你在浏览器上搜IP地址,就是外网
(1).如果同一个局域网内部的两台设备想通信,肯定是没问题的,因为同一个局域网的两台电脑的IP地址肯定是不一样的
(2).如果两个局域网的两台电脑要通信呢,这两台设备很可能IP地址一样,这时候咋整呢?
当前的规则,是禁止这种情况的!!!!!
如果必要的时间,迫切需要两台设备通信呢?比如两个人在地球的两端发微信通信,这就需要有一个带有外网IP的设备进行中转!
(3).局域网内部的设备访问带有外网IP的设备
像平时的手机,电脑,都是在局域网内部使用,他们会有一个内网IP,还有一类设备就是服务器,服务器可以有外网ip
这个过程就涉及到NAT工作机制了
真实的情况是:我的电脑跟学校是一个局域网,一个联通路由器上,有很多个局域网,于是我的电脑的IP地址经过学校局域网,会有一次NAT,学校局域网经过联通路由器会有一个NAT(每次经历路由器转发,都"可能"有一次NAT,为啥说可能呢,具体的还要看路由器怎么配置了,有的配置下就不会触发)
3.IPv6
IPv4是4个字节,
IPv6是16个字节,非常非常大,只要人类没有脱离地球文明,ip地址的个数足够用到地老天荒
可是为什么主流还是NAT呢?
其实IPv6和NAT诞生的时间差不多,为啥NAT能成功呢,而IPv6举步维艰呢?
是因为IPv6和IPv4不兼容,要想升级IPv6,就要更换路由器设备==>花钱
(升级IPv6不会提高网速,更不会提高流畅性)
相比之下,NAT方案只需要路由器开发商开发出新版本的软件(路由器固件),升级软件,即可直接支持(成本非常低)
IP地址的组成
IP地址分为两个部分:网络号+主机号
网络号:标识网段(局域网),保证相互连接的两个网段具有不同的标识
主机号:标识主机,同一网段内,主机之间具有相同的网络号,但是必须有不同的主机号
子网掩码
一个IP地址,哪部分是网络号,哪部分是主机号,通常是通过子网掩码来识别的
特殊的IP地址
路由选择
数据链路层
(简单了解,越往下,距离程序员越远)
以太网
是历史问题,发明IP地址和MAC地址的是两波人,发明之前没讨论,所以都发明出来了,但是发明出来之后谁也不服谁,就都留下了
都留下之后,就让IP地址负责网络层的转发,让MAC地址负责数据链路层的转发
网络层负责是整体的转发过程
数据链路层负责的是是局部(相邻设备)的转发过程
举个例子
DNS(域名解析系统)
平时我们上网要访问服务器,需要知道服务器的IP地址,而IP地址是渔船数字,虽然这个数字使用点分十进制已经清晰不少了,但是仍然不方便人们传播记忆,于是就使用单词来代替IP地址
使用baidu,taobao等单词来代替IP地址
这样的单词就称为域名,实践中为了保证域名的唯一性,域名往往是分级
www.baidu.com com是一级,baidu是二级,www是三级
域名是给人看的,但是机器不认识,于是就有一套系统,把域名自动翻译成IP地址,这个系统就是DNS
那么问题来了,全世界这么多的主机都在上网,此时DNS服务器能承担这么高的并发量嘛?DNS服务器如何承载高并发量呢?
两条原则:开源 节流
从技术角度讲,DNS服务器是否会挂呢?当然会,尤其是你所在地区的镜像服务器,一年挂了两三次很正常
MTU
MTU对IP协议的影响
由于数据链路层MTU的限制,对于较大的IP数据包要进行分包。
将较大的IP包分成多个小包,并给每个小包打上标签;
每个小包IP协议头的 16位标识(id) 都是相同的;
每个小包的IP协议头的3位标志字段中,第2位置为0,表示允许分片,第3位来表示结束标记(当前是否是最后一个小包,是的话置为1,否则置为0);
到达对端时再将这些小包,会按顺序重组,拼装到一起返回给传输层;
一旦这些小包中任意一个小包丢失,接收端的重组就会失败。但是IP层不会负责重新传输数据;
MTU对UDP协议的影响
一旦UDP携带的数据超过1472(1500 - 20(IP首部) - 8(UDP首部)),那么就会在网络层分成多个IP数据报。
这多个IP数据报有任意一个丢失,都会引起接收端网络层重组失败。那么这就意味着,如果UDP数据报在网络层被分片,整个数据被丢失的概率就大大增加了。
MTU对于TCP协议的影响
TCP的一个数据报也不能无限大,还是受制于MTU。TCP的单个数据报的最大消息长度,称为MSS(Max Segment Size);
TCP在建立连接的过程中,通信双方会进行MSS协商。
最理想的情况下,MSS的值正好是在IP不会被分片处理的最大长度(这个长度仍然是受制于数据链路层的MTU)。
双方在发送SYN的时候会在TCP头部写入自己能支持的MSS值。
然后双方得知对方的MSS值之后,选择较小的作为最终MSS。
MSS的值就是在TCP首部的40字节变长选项中(kind=2);
ARP
虽然我们在这里介绍ARP协议,但是需要强调,ARP不是一个单纯的数据链路层的协议,而是一个介于数据链路层和网络层之间的协议
ARP协议的作用
ARP协议建立了主机 IP地址 和 MAC地址 的映射关系。
在网络通讯时,源主机的应用程序知道目的主机的IP地址和端口号,却不知道目的主机的硬件地址;
数据包首先是被网卡接收到再去处理上层协议的,如果接收到的数据包的硬件地址与本机不符,则直接丢弃;
因此在通讯前必须获得目的主机的硬件地址;
ARP协议的工作流程
1.源主机发出ARP请求,询问“IP地址是172.20.1.2的主机的硬件地址是多少”,并将这个请求广播到本地网段(以太网帧首部的硬件地址填FF:FF:FF:FF:FF:FF表示广播);
2.目的主机接收到广播的ARP请求,发现其中的IP地址与本机相符,则发送一个ARP应答数据包给源主机,将自己的硬件地址填写在应答包中;
3.每台主机都维护一个ARP缓存表,可以用arp -a命令查看。缓存表中的表项有过期时间(一般为20分钟),如果20分钟内没有再次使用某个表项,则该表项失效,下次还要发ARP请求来获得目的主机的硬件地址