在浏览器中输入网址按回车后发生了什么?

文章作者孟宁,首发于读行学(DoctorTalent),未经授权,不得转载!


    当用户在浏览器输入网址(比如http://www.ustc.edu.cn)按回车后,可以看到网址对应的一个网页。从普通用户的角度看一个网址对应了一个页面,符合逻辑常识非常方便。但是从技术的角度看,背后在浏览器、本地主机网络协议栈及网卡、DNS域名服务器、中间设备交换机/路由器和Web服务器上会引发一系列复杂的活动,大致具体如下:

  1. 将网址中的域名部分(如www.ustc.edu.cn)通过分布式DNS域名存储系统解析成IP地址;

  2. 通过TCP三次握手建立连接,然后发送封装到TCP分段中的HTTP请求到对应的Web服务器IP地址和TCP端口上;

  3. IP协议栈将TCP分段封装成IP数据包,然后根据目的IP地址查询路由表得到下一跳(next hop)的IP地址,在本机和路过的每一个路由器上都会发生路由查询得到下一跳的IP地址;

  4. 知道了下一跳的IP地址怎么样将IP数据包传输到下一跳呢?这需要借助本地物理网络来传输,那首先要知道下一跳的IP地址对应的物理地址,地址解析协议ARP就是将IP地址通过查询ARP缓存得到本地网络的物理地址(如以太网MAC地址)。从本机到目的IP会经过若干物理网络,其中都会发生将下一跳IP地址解析成物理地址的ARP地址解析过程;

  5. 知道了下一跳的IP地址及对应的物理地址,就可以将IP数据包封装到本地物理网络的数据帧(如以太网MAC帧)中发送到网络接口(网卡)上。以交换以太网为例,MAC帧可能会经过多个交换机才能到达目的MAC地址,每一台交换机做MAC帧转发时通过查询过滤数据库进行定向转发,减少冲突提高网络传输效率;

  6. 在IP数据包传输到目的IP的过程中经过的每一个网络接口,包括本地网卡、交换机/路由器的网口和目的IP服务器的网卡,它们负责二进制数据帧的收发工作,我们以以太网网卡为例,在发送MAC帧时根据CSMA/CD来决定发送的时机,以7个字节的10101010和一个字节的10101011作为前导符来识别一个MAC帧进行接收。

       我们大致可以将整个网络背后发生的复杂活动简要总结为以上7个部分,接下来通过不同的视角由浅入深一步步来理解这一系列复杂的活动。

程序员视角

        从浏览器软件的角度看,浏览器调用了gethostbyname进行域名解析,然后调用Socket API发送和接收HTTP请求/响应,最后渲染网页页面。

    具体来说,首先浏览器通过gethostbyname进行DNS域名解析,如果本地没有查到域名对应的IP地址,gethostbyname将构造DNS查询请求报文通过UDP Socket API发送给本地DNS域名服务器,从而获得域名对应的IP地址。

//相关头文件
#include <netdb.h>
#include <sys/socket.h>
//相关数据结构
struct hostent {
     char *h_name;       /*主机的规范名*/
     char **h_aliases;   /*主机的别名*/
     /*主机ip地址的类型,到底是ipv4(AF_INET),还是ipv6(AF_INET6)*/
     int h_addrtype;
     int h_length;      /*主机ip地址的长度*/
     char **h_addr_list;/*主机的ip地址,是以网络字节序存储的*/
};
// gethostbyname的函数原型
struct hostent *gethostbyname(const char *name);
// gethostbyname域名解析范例代码
struct hostent *hp = gethostbyname(“staff.ustc.edu.cn");
if (hp == NULL) {
     fprintf(stderr,"gethostbyname() failed\n"); 
} else {
     printf("%s = ", hp->h_name);
     unsigned int i=0;
     while ( hp -> h_addr_list[i] != NULL) {
          printf( "%s ", inet_ntoa( *(struct in_addr*)(hp -> h_addr_list[i])));
          i++;
     }
     printf("\n");
}

        然后浏览器构造HTTP请求报文并通过socket、connect、send将请求报文通过TCP连接发送给域名对应IP地址所在的Web服务器。浏览器就是一个TCP客户端软件,Web服务器就是一个TCP服务端软件,大致的Socket API调用过程如下图所示。

79c6499caf934c2623f363b2d6077801.png

        最后浏览器对服务器回传的HTTP响应报文HTML进行解析、执行和渲染,其中会根据HTML的内容触发多次HTTP请求获取相关的CSS/Javascript等内容完成整个页面的渲染输出。

网络体系结构视角

DNS域名存储体系及递归查询机制

        通过gethostbyname进行DNS域名解析大致分成两大步骤:

  • 一是程序员视角能够间接触及的,由UDP Socket方式进行DNS请求和响应;

  • 二是本地DNS服务器负责在DNS域名分布式存储系统中进行递归查询的过程。

        尽管DNS属于应用层协议,但是DNS域名存储体系及递归查询机制是互联网的基础设施,我们从网络体系结构的角度看DNS域名存储体系及递归查询机制是一个关键环节,如下图。

5be9f2f13881886d72b0572ece1cd0fd.png

        DNS查询过程所使用的UDP Socket与HTTP协议所使用的TCP Socket相比在传输层更为简单,更底层的网络技术完全相同,这里不再展开,请参照下面HTTP及TCP等相关内容来理解。

面向连接的、可靠的字节流协议TCP

        HTTP协议本身的机制相对简单不具有网络体系结构视角上的关键价值,您可以简单理解为HTTP请求和响应的简单应答过程。但是HTTP使用TCP协议进行数据传递,而TCP是面向连接的、可靠的字节流协议,这里面涉及连接建立过程的三次握手、滑动窗口机制/拥塞控制和关闭连接过程,这些会在浏览器所在主机操作系统和Web服务器所在主机操作系统中的TCP/IP协议栈中处理。

路由选择和存储转发

        路由选择是整个互联网体系结构中最为关键的环节之一,理解路由选择首先要搞清楚三个基本的概念:

  • 网络地址

    网络地址是IP地址和子网掩码netmask做按位与操作得来,比如192.168.0.1/24,子网掩码24位即255.255.255.0,按位与操作得出192.168.0.0即为网络地址。这种做法有一个历史演化过程,最早IPv4网络地址分为A类、B类、C类等,也就是子网掩码8位、16位、24位,由于IPv4地址枯竭有灵活划分子网的需求,同时为了减少路由表项提高路由查询效率有合并网络形成超网的需求,于是就从有类别域间路由演变为无类别域间路由CIDR。

 路由表

a1e130135770a370d8a96003294e9a67.png

  • 下一跳的IP地址

    我们在配置主机上网时会手动或通过DHCP自动配置本机IP地址、默认网关和DNS服务器,其中默认网关就是本机的默认路由。同样作为中间设备的路由器也需要配置路由表项,也是可以通过手工配置路由表或通过RIP、OSPF等路由协议自动配置更新路由表。通过IP数据包中目的IP地址所在的网络地址查询路由表得到的一个关键信息就是下一跳的IP地址,IP数据包是通过路由选择传输到下一跳、下一跳...逐渐靠近目的网络和目的主机的。

    d3cdb609694087987b2369d249233c18.png

  • 存储转发

    存储转发是路由器的核心工作机制,也就是路由器收到一个IP数据包先存储下来,然后通过路由选择找到下一跳的IP地址,最后转发IP数据包到下一跳。

        有了这三个基本概念我们大致上可以类比从一个小村庄去另外一个城市的某个村庄走亲戚,具体经过大致如下:

  1. 和家里人一合计走亲戚要先到镇上的车站,也就是下一跳就是镇上的车站,大概相当于默认网关;

  2. 到镇上的车站一打听要先去县城车站(下一跳),自然打听的时候你说的目的地应该要去的那个城市,而不是目的村庄,也就基于网络地址的路由查询;

  3. 到了县城车站再打听,有没有直达目的城市的班车?没有的话下一跳要先到市里车站,正好有直达班车,那下一跳就是目的城市了;

  4. 到了目的城市,要打听目的村庄所在的乡镇怎么走,结果下一跳要到某镇车站;

  5. 到了某镇车站离目的村庄就很近了,一打听目的村庄怎么走?不管打的、步行还是通知亲戚来接,总之下一跳就到目的地了。

        有同学会说这多落后呀,现在我们年轻人都是滴滴打车通过导航直达目的地。与此类似网络流量也有导航了,就是软件定义网络SDN,可以规划一个路径直达目的地。但是就像滴滴打车只在人口密切的城市区域提供服务一样,SDN也仅能在数据中心或企业网内部使用,更广大的区域还是要用传统的老办法。

ARP地址解析

        通过路由查询知道了下一跳的IP地址,就像知道了要先去某某车站,但是怎么到达某某车站呢?比如打的,的士司机师傅可能知道某某车站的具体位置,也可能没听说某某车站,你就要告诉司机师傅某某车站在哪条路以及门牌号,这大概就相当于把下一跳的IP地址解析成本地网络的物理地址(如以太网MAC地址),ARP地址解析协议就是负责把IP地址解析成MAC地址。

ARP cache table

fd8dfe5d171acef73947b72e79455b3f.png

        ARP协议栈维护了如上这么一个ARP缓存表,当需要解析一个IP地址对应的MAC地址时就查一下这张表,如果在表中找不到对应的MAC地址就需要发送一个ARP请求消息到网络上,大致相当于在村子里吼一嗓子,“二狗子家门牌号是几号来?”,二狗子听到了就回一句“我们家门牌号263”。

        换成我们网络的说法就是存有需要解析的IP地址的ARP请求消息是封装在一个MAC帧中,目的MAC地址是一个广播地址,类型Type是0x0806(IP数据包所在MAC帧类型是0x0800),本地网络中所有主机都可以收到这个ARP请求消息,因为类型是0x0806所以本地网络所有主机上都是ARP协议栈负责处理这个ARP请求,只有主机IP地址和需要解析的IP地址相同的主机才会回复包含对应MAC地址的ARP响应消息。

交换机中的学习和过滤机制

        根据目的IP地址找到了IP数据包要到达的下一跳IP地址,又将下一跳的IP地址解析得到了对应的MAC地址,这样就能将IP数据包封装成MAC帧通过网卡发送出去了,以以太网为例发送的方法要遵守的CSMA/CD协议我们稍后再谈,我们先聚焦在二层链路层上的交换网络,也就是MAC帧如何到达目的MAC地址所在的主机,其中可能会经过多台交换机/网桥。

        交换机/网桥是工作在二层链路层上,具备智能学习和过滤的能力,其中维护这一个过滤数据库,如下图所示交换网络结构及交换机对应的过滤数据库。

交换机上的过滤数据库

eb42bebae005eb8a3d46eaaae2259a0d.png

        这个过滤数据库是通过学习得到的,大致学习过程是这样,交换机在某个端口上收到一个MAC帧,就将MAC帧的源MAC地址和该端口的编号存入过滤数据库。这样交换机需要转发MAC帧时就可以通过目的MAC地址查询过滤数据库确定转发到哪个端口上,从而避免了全网广播。通过智能学习和过滤机制交换机/网桥将网络分成多个网段,减小了冲突域。

以太网CSMA/CD和网卡接收数据包的同步机制

      CSMA/CD(Carrier Sense Multiple Access with Collision Detection)即带冲突检测的载波监听多路访问技术(载波监听多点接入/碰撞检测)。在传统的共享以太网中,所有的节点共享传输介质。如何保证传输介质有序、高效地为许多节点提供传输服务,就是以太网的介质访问控制协议要解决的问题。其原理简单总结为:先听后说,边听边说;一旦冲突,立即停说;等待时机,然后再说。我们如上讨论的主机、服务器、交换机、路由器等设备在发送一个MAC帧到网络上的时候都遵循这个CSMA/CD机制。

       清楚了网卡如何发送一个MAC帧,网卡怎么知道需要接收一个MAC帧呢?这就需要发送的网卡与接收的网卡进行同步,就课堂上老师讲到重点的内容希望同学们能同步接收到这些信息,会敲黑板划重点一样,网卡在发送一个MAC帧之前会先“敲黑板”,只是网卡是通过发送8个字节的特殊高低震荡的电信号来实现的。如下图即为8个字节的Preamble and Delimiter。

7316bb308b23b8b5a9ff5ef4f856f73a.png

       一个网卡一“敲黑板”,同一个冲突域的本地网段上的所有网卡都注意听讲了,都将接下来发送的MAC帧接收保存下来,只有MAC地址与MAC帧中的目的MAC地址相同的网卡会发出中断信号让操作系统来接收处理这个MAC帧,其他的网卡一听不是自己需要的“重点”就直接丢弃“充耳不闻”了。

       CPU接到中断信号就执行操作系统中对应的中断处理程序来负责接收和处理这个MAC帧,其中重点就是根据MAC帧的类型决定将MAC帧里面的数据交给哪个协议栈来处理,如下图所示。

72e9f8f9572371fef7ef4d76ac5fe98d.png

更多

  • 如果本地网络为私有IP地址,还需要经过NAT网络地址转换才能访问公网;

  • IP数据包在经过某个网络或路由器时发生拥塞丢包则可能会触发ICMP消息发送;

  • IP数据包经过防火墙等监控设备时可能会触发过滤规则或被记录或被修改;

  • ......

总结

       我们讨论了两个应用层协议HTTP和DNS,它们通过Socket API分别使用了TCP和UDP这两个传输层协议。TCP和UDP都会被封装到IP数据包中,每一个IP数据包发送之前都需要根据目的IP地址查询路由表获得下一跳的IP地址,也都需要将下一跳的IP地址解析成MAC地址,然后才能将IP数据包封装到MAC帧中通过网卡发送到本地网络上,发送的过程需要遵守CSMA/CD,在本地交换网络上还可能触发交换机的学习和转发过滤。

操作系统成长记

换种方法学操作系统,轻松入门Linux内核

庖丁解牛Linux网络核心源代码分析

未来X网络开启数字化新纪元,延伸阅读参阅贝尔实验室最新官方图书《The Future X Network 下一代网络》见【原文】链接

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农孟宁

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值