输入一个URL

2019-04-13 21:56发布

前几天看到一个题目,问在浏览器中输入一个URL会发生神马,这好像是网上比较流行的面试题,而且也被回答烂了,仔细想下来,要是自己遇到这个题目能不能答上来,后来一想,这个题目要完全答出来可以把大学开始的几乎所有知识都用上。呵呵,为了模拟面试,所以都凭印象说的,没有查网络资料,所以估计很多地方都不对,欢迎来拍。
后续可以总结一个非常非常详细的版本,个人感觉真的可以把大学开始的所有的东西都用上,包括连数电模电(全部流程都跑不掉),信息论(gzip压缩),密码学(HTTPS),通讯原理(网络基带传输)这种都可以,本文还是以软件处理过程为主。

硬件层---键盘到CPU

输入网址嘛,那就是键盘输入了,键盘一般用usb或者PS/2口连接电脑,现在见过PS/2口的人不多了吧,我们就看看usb吧,usb分为主从模式,一般的键盘本身的usb是一个从设备,相应的还有u盘啊,鼠标啊都是从设备,对应的主机端的USBcontroller是一个主设备,这个主设备挂在CPU上,在X86结构的机器上是挂在主板的南桥(好像是的,反正是低速的那个)芯片上,如果是ARM这类嵌入式设备的话,那么就是挂在APB总线上,对这个我熟悉一些,就按ARM这种SoC来说吧,当是在手机上输入URL吧,呵呵。 键盘输入字符以后,通过USB协议(USB协议简单的来说就是一个串行协议,靠一个时钟电信号和一个数据电信号传输数据)将数据传输到APB总线上的USB控制器上。然后这个控制器开始抢总线,总线的APB桥接收到信号以后也开始通过APB总线上的时钟和数据线发送一个中断信号APB桥中,APB桥同时连接在AHP高速总线上,接收完数据以后,它开始抢高速总线,高速总线上有个Arbiter(总线仲裁器),因为高速总线上接的都是内存啊这种家伙,你一个小小的USB不见得抢得过他们,等仲裁器给你时间以后,APB桥开始把中断信号发给CPU。 CPU接收到这个中断以后,要是没有其他更高级的中断需要处理的话就会调用内核中的中断处理函数开始处理中断,中断处理函数又分为底半部和顶半部,首先会是底半部处理,把中断放到处理队列中就返回了,然后顶半部从队列根据注册的的中断号拿到自己对应的中断号进行处理,这时候中断处理函数就算收到这个信号了,相当于硬件的电信号已经传递到软件层了,中断处理函数会调用USB的驱动程序去USB控制器上读取这个输入的字符,这个字符还是通过两条总线(APB和AHB)以独占的方式传递到软件层上,其实呢,是软件控制这个信号写到了内存的某个空间上。 整个流程是这样的
发出中断 :键盘--->usb控制器 ---> APB桥 ---> CPU硬件中断 ---> 中断处理底部 ---> 中断处理函数顶部 ---> 驱动程序 ---> 读取数据 ---> CPU寻址 ---> 写入内存

内核层到应用层

假设我们输入的url以C语言的scanf函数为例,scanf函数会一直在内核态阻塞着,直到中断处理函数接收到了所有的字符并且接受到了一个回车符,这时scanf语句会通过操作系统的read调用把缓冲区的所有字符从内核态拷贝到用户态,这时这些个字符就从电信号传递到了应用程序(浏览器)的软件层了。 整个流程是
scanf ---> 系统调用read ---> 内核态阻塞等待 ---> 读取拷贝数据 ---> 用户态接收数据
因为软件层也不是一个实体层次,其实所有的操作最后都变成了硬件的电信号,所有没办法把流程写得很明白,大概就是这么个意思吧。

网络请求

应用程序(浏览器)接收到这个URL以后,就开始走网络层来获取数据了,这里我们就不深入到底层的电信号了,就按网络这一套来说吧。

DNS解析

首先就要解析域名了,浏览器会先看一下本地的host文件,看有没有url域名对应的ip地址,如果没有的话,会通过DNS协议发送数据包给DNS服务器询问域名的ip地址,DNS服务自己没有对应的ip的话会继续往上寻找,然后把ip地址发回给浏览器。DNS协议是UDP的,但好像有特殊情况是TCP连接,好像是各个DNS服务器之间传输用的TCP吧,不管了,反正通过UDP这个传输层协议之上的DNS应用层协议把url对应的ip地址得到了。

传输数据准备

拿到ip地址以后,假设我们输入的网址是https://www.baidu.com/,百度的服务器在北京,而我们在上海,浏览器就通过connect开始连接这个这个北京的ip地址了,连接跑到tcp/ip协议栈以后,协议栈一看这个IP和本地IP根本就不在一个段上啊,那ARP也不发了,直接把数据包转发到网关上,也就是家里的路由器上了,路由器拿到地址,查一下本地的路由表,呀,我这小路由表上没这个网段的啊,那我不管了,给我的上级路由吧(也许是小区的大路由器了),小区路由一看,我这也没有啊,这样一级一级传递到了上海的城际路由上,然后到了北京的城际路由,这么一层一层下来终于传到了百度的服务器上。 在这里看上去简单,但是路由的算法是很复杂的,这一块我也不太懂没弄过,但是Dijkstra选路算法还是明白的,别问我为什么记得这个单词,大学计算机网络课的课程作业啊,就是实现这个Dijkstra啊,通过路由算法,终于把第一个数据包发送给百度的服务器了。

建立连接

这个数据包是神马呢,就是我们熟悉的TCP三次握手的第一握了,SYN=1的那个数据包,关于三次握手就不多说了,大家都知道,关键是我不记得细节了,反正就是大家都懂的,握手完了连接就建立完了。为什么建立连接需要三次握手,关闭连接需要四次握手,呵呵,写不动了。 同时,在百度服务器这边,有个web服务器的应用程序(比如Nginx),一直在监听着80端口,收到这个数据包以后也同时和客户端建立起了连接了。

传输数据

连接建立好以后,是TCP连接建立了,这时通过更上层的HTTP协议开始传输数据,HTTP协议本身很复杂,这里我们简单的来说,就是浏览器发送了一个GET / HTTP/1.1 字符串给了服务器,服务器接受到这个字符串以后,通过协议栈传递给了上层的Nginx应用程序。 应用程序一看这个地址是/,然后对照一下自己的配置文件nginx.conf,有个配置告诉他碰到这种请求,直接把本地的index.html吐出去,于是Nginx读取index.html并把数据通过这条TCP连接回复给了客户端。 由于http协议是无状态的,所以本次传输完数据以后,这个链接就关闭了。

完成显示

好了,后面的就是接受到数据的显示了,关于webkit内核的细节就真不清楚了,就是解DOM树,执行JS代码,重新请求CSS和图片,然后把页面画出来吧。 哦了,题目做完了,其实还有很多细节没有说的,比如网络寻址的时候的ARP协议啊,路由器寻路的其他很多算法啊,Nginx处理请求的时候的几个阶段解读啊,是否需要反向代理到后端的服务器上啊,最后显示的时候还需要操作显卡进行显存的操作,如果页面中有复杂的图形效果还需要GPU参与运算之类的,要写就写不完了。
如果你觉得不错,欢迎转发给更多人看到,也欢迎关注我的公众号,主要聊聊搜索,推荐,广告技术,还有瞎扯。。文章会在这里首先发出来:)扫描或者搜索微信号XJJ267或者搜索西加加语言就行