引言:
北京时间:2024/3/19/11:16,若是说记忆有克星的话,那么一定是时间。若是说耐心有克星的话,那么一定是人的心态。连续几天睡眠问题,加上环境影响,上篇博客还有部分知识只能放在该篇博客介绍了。由于需要理解的东西一直在变多,博客字数一直呈上升趋势,博客更新周期一直延长。日更这辈子是不可能日更了,毕竟以前的博客大部分都是六千字左右,而现在打底都是两万字。知识点虽然不多,但是字数却越来越多,只能说明我们的理解更加全面以及深入。当然这种博客并不适合小白食用,这种博客只适于有一定理解的人食用,而其中以我自己最为享用。毕竟古有名言色即是空,空即是色,呸呸呸,是快即是慢,慢即是快。结合我对记忆两个字的理解,我举双手双脚赞成这句话,当然是否合理有待未来评定。今天周二,上个周末对于我来说非常有趣,与我预期的一样在图书馆待了两天约莫十八个小时。当然有趣肯定不是有趣在这十八个小时,而是在于某个事件。思虑了一番这也不是什么见不得人的事情,主要还是这件事情对于我来说挺有纪念意义,算是我人生当中的宝贵财富!不知如何记叙会比较委婉一点。在一个月黑风高的晚上,算了还是不好说,还是不说算了。对了,这里我再强调时间是把记忆刀,刚刚在重新设置云服务器安全组的时候,又是因为忘记重启云服务器,让我尝试到了许久没有体会到的痛点。而虽然上述事件确实难以启齿,但是我可以描述一点我的小理解,好比我的歌单里有非常多我喜欢的歌,但是很多都以积灰许久。所以闹钟还是得原声才是永恒,岂能白白糟践了你曾经的美好。所以一个事物也不是非得要更近一步,保持距离也是心灵上的一种慰藉。
网络协议栈拓展知识学习
当我们学习完上篇博客中有关数据链路层的知识,此时整个网络协议栈我们就学完了,当然物理层我们不需要考虑。从应用层学习套接字学习序列化反序列化学习应用层协议,到传输层学习各种传输机制学习各种保证可靠性的策略,到网络层学习网段划分和路径选择,再到数据链路层学习局域网通信。这种从上层开始到下层结束的学习方式,虽然过程中痛点频发,但当我们踏踏实实将每一层应该掌握的知识明确之后,很多当时困扰我们许久的问题就不再是问题。并且在解决该问题的同时,可以让我们更好的整合回顾许多知识在细节方面的处理,从而实现对某些知识的深入理解。一路走来,磕磕碰碰,从对网络通信一无所知到不过如此,这也许就是我们最大的收获吧!是时候暂时要跟网络协议栈说再见了,只不过在说再见之前,我们再对其进行一个整体认识的同时拓展相关知识的学习。如对在应用层被广泛使用的DNS,与网络层或者说网络管理员有关的ICMP协议,以及与局域网通信有关的代理服务器等知识。只有当我们将这些知识结合所学搞定之后,我们才正式和网络协议栈告一段落,真正进入到数据发送和读取也就是有关高级IO知识的学习。
什么是域名系统(DNS)和梳理应用层
想要学习这块知识,最好的切入点就是当时在学习应用层HTTP协议时对URL的理解。刚从学习HTTP协议的那篇博客中回来,遥想当初我怎么会这么厉害。对于URL的认识写的那么有条理那么有逻辑,一切都是铺垫一切都是因果,让我不仅瞬间对URL的知识有了定位,还明确了有关URL的各种周边知识。当初我们学习HTTP协议,在讲解为什么所有的Web服务器都需要使用HTTP协议时,我们对浏览器有了一定的认识,但可能是当时才疏学浅,在我刚刚回顾的时候我发现对部分知识的理解是有误的,所以这里我们重新对浏览器相关知识进行深入学习。我们直接以微软浏览器的使用场景出发,首先场景分为两种,一种是联网状态一种是非联网状态。若我们在没有联网的时候运行浏览器客户端,我们发现我们依然能看到浏览器上的信息,而并不是想象中的提示你目前没有网络连接。所以对于浏览器客户端第一层的理解就是,其内部或者说本地肯定缓存了大量的HTML代码和各种图片数据等,当然具体这些数据的来源一般是在安装软件时加载的。而这层理解也非常契合我们对浏览器可以渲染各种Web服务器的网页一样,本质就是浏览器客户端拥有识别像HTML/JavaScript/CSS这种前端语言的能力,换一个角度来看,我们也就可以把浏览器客户端理解成是一个HTML/JavaScript/CSS编译器。而当我们在联网时运行客户端程序,此时就不得不谈一谈浏览器服务端和Web服务器之间的区别了。而想要谈它两的区别,同理直接从现象出发。在浏览器客户端上我们可以看到两个输入框,一个在浏览器客户端的最顶上也被称为地址栏或者URL栏,一个在较为中间处也被称为搜索栏。顾名思义,两者名字不同用途自然也不同。而想要明白为什么会有两个不同用途的输入框,此时就又不得不谈谈浏览器的本质以及搜索引擎的本质了。我们要明确对于浏览器而言,它最重要的功能是向目的IP地址和端口或者说目的进程发送请求。当然这个功能对于学完应用层的我们而言,本质不就是使用套接字API与特定的IP地址和端口进行绑定,然后用send将HTTP请求发送出去,当然因为浏览器一般使用TCP所以还需要connect建立连接,并且此时对于发送出去的概念,对于学完网络协议栈的我们来说,本质不也就是将数据交付给下层。因此对于浏览器的理解我们就可以将其看成是一个高级万能客户端。而随着时代的进步,我们能发现浏览器具有的功能越来与丰富,其中就以搜索引擎最为亮眼。基本所有的浏览器都以配备搜索引擎为标准,如微软浏览器上的必应搜索引擎或者是被人们推崇的谷歌搜索引擎再者国内最流行的百度搜索引擎。当然对于搜索引擎的基本工作原理,当时在拓展有关HTTP重定向知识时在谈重定向与爬虫之间存在的联系,对其有了一定的认识这里我们不再重复。所以此时对于地址栏和搜索栏我们就能明确,原来地址栏才是浏览器客户端提供给我们访问特定IP地址和端口号使用的,其格式为URL格式功能同理上述所说,只不过此时在send之前可能就还需要对URL格式中特定的数据做解析以及HTTP报文的构建。当然因为浏览器有进行特殊处理,所以如果你在地址栏中输入非IP地址和端口号数据或者说非URL格式数据,那么浏览器因为无法识别就会将对应数据默认转给与该浏览器绑定的搜索引擎服务器。因此也就是说只有在地址栏输入合法的URL,此时浏览器访问的目的IP地址才会是你输入的IP地址当然也就是域名。反之无论你是在地址栏中输入还是在搜索栏中输入,目的IP地址都一定是对应搜索引擎服务器IP地址。因此我们也就明白,浏览器客户端上的两个用户输入框都不是简单的服务器表单,也就是说浏览器客户端和普通的客户端不同,它并不需要将数据转给浏览器服务端,而是都可以直接向目的IP地址发送请求并渲染响应。所以对于浏览器服务端而言,在浏览器客户端看来它并没有其到很大的作用。对于其理解我们就可以将其理解成是一个普通的服务器,用于提供各种URL也就是资源路径或者说超链接信息给浏览器客户端使用,当然更重要的是还有大量的广告链接,也就是广告对应服务器的域名或者说IP地址。所以当我们单纯只是想访问浏览器客户端上的数据时,目的IP地址就不再是搜索引擎IP地址也不是你提供的IP地址,而是浏览器服务器提供的IP地址。因此也就是说对于一个Web服务器而言,其最重要的功能不是数据处理,而是提供大量的URL供用户选择,然后根据用户对特定URL的选择快速将对应资源响应给用户或者说浏览器。而当我们清晰准确的明白了上述知识,小小DNS不是手到擒来。本质同理我们在学习应用层协议需要有默认端口号时所说。当然对于那种配套机制的客户端和服务端对于协议默认端口这块不怎么好讲,因为都懂客户端自己设计,服务端也自己设计,那不就是什么都是天王老子我说了算。所以我们同理还是要以浏览器这种需要有协议的会比较好讲。也就是浏览器为了提高用户的使用效率或者说降低用户的使用难度,它就默认用户可以不输入端口只输入IP地址就能访问到全网唯一的一个进程。当然这个默认情况并不是说不要端口号是吧,那肯定是默认就访问特定端口号也就是HTTP或者HTTPS对应的80号端口以及443号端口。那么浏览器有这个设计,所有的Web服务器还不得乖乖听话,将自己服务器的端口号设置为80或者443。同样这个道理,当然一切都是为了增加用户体验感。用户说端口我都记不住或者懒得及,你IP地址这么长我怎么记,还是不上网算了。所以为了解决这个问题,DNS就说我会出手,当然解决方案都是在不断改进优化过程中完善的,所以具体一开始是如何解决IP地址不好记的问题我们不考虑。因此就提出了域名的方案,也就是说每个服务器想要上网,当然这个说法肯定不准确,但是就是这个意思。那么它就需要申请一个域名,当然结合我们对HTTPS那块CA证书的理解,这两块问题最终可能就被结合成了一个问题同时解决。当你申请到了域名或者说将你的域名和IP地址信息添加到了DNS中,那么此时你就可以实现被全网直接使用域名访问。所以到底是如何访问的呢?同理首先用户在浏览器的URL栏内输入对应的域名,当然对于掌握了上述知识的我们而言,此时这个用户的输入过程我们知道肯定不是表单而是浏览器客户端上自带的HTML/JavaScript/CSS语言实现的一个输入框,而在我们学C++的角度看就是一个数据输入接口如cin,当浏览器使用了一个类似cin的接口将我们的数据从标准输入也就是键盘从获取之后,它就会对该数据也就是域名做解析,从上述的分析来看对域名做解析本质也就是在查找该域名的映射关系,因为DNS本质就是一个域名和IP地址的映射系统。明确无论是操作系统还是浏览器其自身内部都会维护DNS缓存,也就是域名与IP地址的映射表,并且在操作系统内部还会配置与DNS服务器有关的数据如IP地址。所以当浏览器在自己本地的DNS缓存中没有查到对应域名的IP地址,也就是域名解析失败,那么此时浏览器就会向操作系统发起DNS查询请求,当然这个过程浏览器肯定也是使用特定系统调用接口完成。当操作系统收到该请求同理操作系统先查询本地DNS缓存,没有的话同理依据操作系统内有关DNS服务器的信息就向DNS发送域名查询请求,当然这个域名查询请求肯定是应用层封装好的。而当DNS服务器收到对应的域名查询请求,DNS服务器首先就会提取对应域名并查看该域名类型。因此我们明确域名是有类型的,而之所以域名需要有类型,本质和子网划分是一个原理,为了提高查询效率嘛!例如此时域名为www.example.com,其中com表示一级域名,example表示二级域名,www表示子域名(不重要)。当然对于域名等级的区分具体需要通过场景来看,这也就是为什么有的人会谈到顶级域名的概念,最好的区分方法就是把域名的结尾部分看成一级域名或者顶级域名,然后向前分级。具体可以参考下图所示。当DNS服务器查询到了对应域名的IP地址,当然全世界存在域名的数量不可想象,而之所以能查这么快的原因除了因为分类型之外,本质就是域名和IP地址之间是哈希或者K/V,因此DNS有可能就是用Redis实现。当响应IP地址回到操作系统,操作系统再将该IP地址返回给浏览器,注意此时我用的是返回,好比就是一个接口调用完成之后,返回了一个数据。当浏览器拿到这个目的IP地址,那么很简单套接字说我终于轮到我登场了,上述说过浏览器一般是TCP协议,所以同理初始化sockaddr_in结构体,然后使用connect与目的服务器建立连接。当然一直在传输层和网络层是操作系统内核,所以传输层和网络层想要拿到端口号和IP地址应用层就必须通过对应系统调用接口参数的形式将数据传给或者说拷贝给操作系统使用,反之理解也一致。
什么是ICMP协议
当我们对上述应用层有关DNS以及部分梳理过程有一定认识之后,此时我们就来看看网络层除IP协议之外的ICMP协议吧!当然具体ICMP协议是在网络层还是传输层我们不关心,我们只要明确它在网络层和传输层之间就行,也就是说ICMP协议也是操作系统内核代码,因此我们明确操作系统内部一定提供了有关ICMP协议的系统调用接口供给给应用层使用。追本溯源已成习惯,这部分知识本简单了解进行,但为了将来或者是现在能够对其有一个系统的认识,我们还是需要花费一些精力来学习它的。首先同理就从为什么要有ICMP协议出发。因为角度不同理由肯定不同,而获取理由最好的方式莫过于反向思考。如果没有ICMP协议会怎么样呢?按照我们一路以来对网络协议栈的理解,发现就算不认识ICMP协议也没有问题啊,网络通信原理我们照样能够首尾呼应、环环相扣。用户数据在网络传输过程中好像不需要ICMP协议也能达到目的主机。如果真这样想的话,那么ICMP协议就要生气了,好你个忘恩负义的家伙,当不需要我的时候你们就将我抛弃,迟早有一天你们会回来找我的。因此可以看出,虽然网络通信过程和ICMP协议没有什么关系,但是之所以能正常进行网络通信好像跟ICMP协议有很大的关系。所以我们就明白,ICMP协议是一个用于检测网络设备是否正常或者说网络通信是否正常。那么问题又来了,不对啊,我直接使用TCP/IP协议进行数据传输不也可以检测出网络通信是否正常吗?能收到响应就是正常收不到就是不正常呗!所以ICMP协议更重要的是它是一个发送控制协议,也就是它能够将通信过程中具体的信息返回给发送主机,当然这个信息可以是出错原因也可以是当前网络状态如延迟、经过节点等。因此ICMP多用于检测某目的IP是否可达,当然也就是在应用层使用ICMP协议提供的系统调用接口封装特定的ICMP报文,然后利用IP协议以及数据链路层将其发送到目的主机。若可达则可以返回对应的网络状态信息,若不可达此时依据ICMP协议就会返回一个ICMP应答报文,其中包含的就是不可达原因,此时发送者通过应用层就可以了解到报文无法到达目的IP的具体原因。如下图所示,此时因为主机B电源关闭导致路由器2无法将报文转发给下一跳IP地址,此时路由器2就会生成一个特定的ICMP错误应答报文返回给主机A。
因此我们明白,ICMP协议在发送数据时并不保证数据能被成功送达,它只能保证尽量送达。也就是遇到正常的路由器和主机那么就进行正常的转发,一但遇到不正常的路由器或者主机此时就返回ICMP应答报文,告诉发送主机错误原因。因此在ICMP协议这样的设计理念之下,我们就明确ICMP协议或者说对应的系统调用接口在应用层就被广泛用于检测网络设备之间通信是否正常。并且根据这个设计理念此时我们也就明白为什么ICMP协议处于传输层和网络层之间,同时可以直接提供系统调用接口给应用层使用,也就是在发送数据报文时不需要经过传输层。本质也就是ICMP设计理念不需要传输层协议的控制。并且因为IP协议不像ICMP协议一样拥有应答的能力,所以如果只是单纯的使用TCP/IP进行数据传输,并不能很好的检测到问题所在。所以根据ICMP协议,此时在应用层就出现了两个供给我排查网络故障的工具:ping和traceroute命令。其中对于ping而言,其主要用于测试两个网络设备之间是否可达,以及测量两个网络设备之间的延迟和经过节点的个数。具体原理也就是通过ICMP协议的系统调用接口向目标主机发送一个ICMP请求,然后根据实际情况获取相应的ICMP应答。而对于traceroute命令,它则侧重于记录数据所经过路由器的IP地址和对应的响应时间,从而了解数据在网络中的实际传输路径以及每个路由器对数据的处理情况。最后明白,对于ICMP协议而言它的本质是一种网络管理协议,是提供给特定的人如网络管理员用于排查网络中各种出故障的网络设备以及反应网络状态信息的一种数据控制协议。
理解代理服务器
搞定上述应用层DNS和网络层ICMP,我们最后再来看看局域网代理服务器,这部分知识是有关网络协议栈最后的知识。想要理解什么是代理服务器,最简单的方法就是贴近生活。想必各位都听说过什么是校园网吧!明确在一个学校局域网内部,一般会存在一个大型机房用于放置该学校的服务器。这种服务器一般会在学校内部提供一些网站服务,如学校的官网、考试系统以及学生信息认证等。当然这种服务器提供网站服务只是它的能力之一,这种服务器更重要的是用于局域网的管理。由于服务器可以提供大量的存储空间,因此若是将一个服务器安置在交换机和路由器之间,也就是当局域网内的主机想要访问外网时,那么当交换机接收到局域网内主机发送的MAC报文,交换机此时就不再是直接根据对应MAC地址和端口的映射将报文转给路由器而是优先转给服务器。而当服务器收到一个想要访问外网的请求数据,此时该服务器就会该请求数据做检查和过滤,只有当符合服务器的转发标准此时服务器才会将对应数据转发给路由器。当然对于为什么交换机会将数据优先转给服务器,本质就是因为我们连接了校园网。也就是当我们连接了校园网,那么就等于是与学校的服务器建立了连接。当然具体如何连接我们不关心,肯定是通过操作系统内部对学校服务器的IP地址进行访问。所以当我们与学校服务器建立连接之后,那么此时在数据链路层看来,我的目的MAC地址就是学校服务器的MAC地址,那么无论应用层想要给那个外网IP地址发送数据,因为已经建立了连接,所以不会再发生根据目的IP地址进行默认路由也就是通过ARP协议获取出口路由器的MAC地址,而是直接将整个IP报文发送给目的MAC地址也就是学校服务器。因此对于学校这种拥有对内网请求或者是外网响应进行检测的服务器,我们就称为代理服务器。当我们搞懂了代理服务器是如何截取局域网内的数据之时。此时问题就来了,代理服务器如何对数据做检查和过滤呢?对于代理服务器对请求或者响应数据的检测最常见的方式可能就是对目的IP地址做分析,看目的IP地址是否符合要求。而除了HTTPS这种加密协议之外,代理服务器更多的是对那些无加密方式的应用层协议做数据检查。当然部分代理服务器还可能使用证书替换的方式来进行数据监测。当然就算是HTTPS协议代理服务器也有监测方法,也就是对服务器证书进行验证,判断该服务器是否合法。而最后我们明确代理服务器也被分为正向代理服务器和反向代理服务器,其中对于正向代理服务器而言,其最明显的特征就是其靠近客户端也就是靠近用户。并且因为其能够缓存资源,所以对于正向代理服务器而言它最大的作用就是提高数据转发效率。而对于反向代理服务器而言,最常见的场景就是一个公司内部有大量的服务器或者说服务器集群,而为了让这些服务器能够实现负载均衡,也就是在用户访问的时候能让每台服务器都发挥作用,不会让请求集中在某些服务器上,此时就需要在该服务器集群中配置一个反向代理服务器,用于接收所有用户的请求数据,然后将这些数据再转发到服务器集群。当然凭借着代理服务器的这些作用,很多技术就可以通过代理服务器来实现,比如游戏加速器或者是访问某些网站。
正式开始学习IO相关知识
由于自身某些原因,这块知识可能会无限期延后。