浏览器是怎样向网卡发送数据的

浏览器是怎样向网卡发送数据的

从浏览器到浏览器内核


当咱们在浏览器的地址栏中输入地址并回车后,浏览器可能会作一些预处理,好比 Chrome 会根据历史统计来预估所输入字符对应的网站,好比输入了“bai”,根据以前的历史发现会有很大的几率会访问 www.baidu.com ,所以就会在输入回车前就立刻开始创建 TCP 连接甚至渲染了,这里面还有不少其它策略,感兴趣的同窗推荐阅读 High Performance Networking in Chrome(http://aosabook.org/en/posa/high-performance-networking-in-chrome.html)。html

接着是输入 URL 后的“回车”,这时浏览器会对 URL 进行检查,首先判断协议,若是是 http 就按照 Web 来处理,另外还会对这个 URL 进行安全检查,而后直接调用浏览器内核中的对应方法,好比 WebView 中的 loadUrl 方法。linux

在浏览器内核中首先会检查缓存,而后设置 UA 等 HTTP 信息,接着调用不一样平台下的网络请求的方法。chrome

浏览器和浏览器内核是两个不一样的概念,浏览器指的是 Chrome、Firefox,而浏览器内核则是 Blink、WebKit、Gecko等,浏览器内核只负责渲染,GUI 及网络链接等跨平台工做则是由浏览器实现的浏览器

发送HTTP 请求


由于网络的底层实现与内核相关,因此在这里须要针对不一样平台进行处理,从应用层角度来看主要是作两件事情:缓存

  1. 经过 DNS 查询 IP安全

  2. 经过 Socket 发送数据

接下来就分别介绍这两方面的内容。服务器

DNS 查询


DNS 查询实际上是基于 UDP 来实现的,这里咱们经过一个具体例子来了解它的查找过程,如下是使用 dig fex.baidu.com +trace 命令获得的结果:网络

1> dig fex.baidu.com +trace
 2
 3; <<>> DiG 9.11.4-P2-RedHat-9.11.4-16.P2.el7_8.6 <<>> fex.baidu.com +trace
 4;; global options: +cmd
 5.            11950   IN  NS  f.root-servers.net.
 6.            11950   IN  NS  k.root-servers.net.
 7.            11950   IN  NS  l.root-servers.net.
 8.            11950   IN  NS  m.root-servers.net.
 9.            11950   IN  NS  b.root-servers.net.
10.            11950   IN  NS  c.root-servers.net.
11.            11950   IN  NS  e.root-servers.net.
12.            11950   IN  NS  a.root-servers.net.
13.            11950   IN  NS  g.root-servers.net.
14.            11950   IN  NS  d.root-servers.net.
15.            11950   IN  NS  i.root-servers.net.
16.            11950   IN  NS  h.root-servers.net.
17.            11950   IN  NS  j.root-servers.net.
18;; Received 251 bytes from 192.168.0.1#53(192.168.0.1) in 12 ms
19
20com.            172800  IN  NS  a.gtld-servers.net.
21com.            172800  IN  NS  b.gtld-servers.net.
22com.            172800  IN  NS  c.gtld-servers.net.
23com.            172800  IN  NS  d.gtld-servers.net.
24com.            172800  IN  NS  e.gtld-servers.net.
25com.            172800  IN  NS  f.gtld-servers.net.
26com.            172800  IN  NS  g.gtld-servers.net.
27com.            172800  IN  NS  h.gtld-servers.net.
28com.            172800  IN  NS  i.gtld-servers.net.
29com.            172800  IN  NS  j.gtld-servers.net.
30com.            172800  IN  NS  k.gtld-servers.net.
31com.            172800  IN  NS  l.gtld-servers.net.
32com.            172800  IN  NS  m.gtld-servers.net.
33com.            86400   IN  DS  30909 8 2 E2D3C916F6DEEAC73294E8268FB5885044A833FC5459588F4A9184CF C41A5766
34com.            86400   IN  RRSIG   DS 8 1 86400 20200625050000 20200612040000 48903 . OwfRn9tBOE2btL/z3HG5PQVyTXu2OUcZGLi9svkHFV0tomeI1p9bHhqr GF/UDjf5a8VXNRoaSsSEQfgqwJT3UAOANK1vb3e+5jH2bV3Hg6/MAGG0 SuBfKv8Y1fjGgiLNC3NKmTWJ28WABHngymnGDpuqoC6xKmkVoD14ON7E uHbBGxC0Uxt6D5R3WfbAAfbzZXzyPcD3WK1OpGaL6ASMB2xvdAZIkp/Z l8QDmqZd86RX7haiVhxVG0mMrWxsN7XL2jVyRRFFl9UkApMk9/thPwNK Rgkd4BPCvMPZTvsb+mPZA4InLxP6oPliZQm5sIWH8fEiyS+LgEReROzG sqrpyw==
35;; Received 1173 bytes from 198.97.190.53#53(h.root-servers.net) in 206 ms
36
37baidu.com.        172800  IN  NS  ns2.baidu.com.
38baidu.com.        172800  IN  NS  ns3.baidu.com.
39baidu.com.        172800  IN  NS  ns4.baidu.com.
40baidu.com.        172800  IN  NS  ns1.baidu.com.
41baidu.com.        172800  IN  NS  ns7.baidu.com.
42CK0POJMG874LJREF7EFN8430QVIT8BSM.com. 86400 IN NSEC3 1 1 0 - CK0Q1GIN43N1ARRC9OSM6QPQR81H5M9A NS SOA RRSIG DNSKEY NSEC3PARAM
43CK0POJMG874LJREF7EFN8430QVIT8BSM.com. 86400 IN RRSIG NSEC3 8 2 86400 20200618045106 20200611034106 39844 com. nL7GSwad11x22Ff4/a3sjIA27DplTa0SZWNb9jnTs0+PYEehVKCT4a2g TWgi5YHeqolDbwsK9oy7Hy1ZO3yhlhWUUAIyE5DE+iKuJCnD6fIvmXdq lXsBBvUHK6wtHzIAPJ8PbCAl/PwSNjpZUZvv4YcEtLWU14yTsPPAM/wB BxatwSt88sQrwYrLKqjnojEsmKVX1yi98pdT87BI/zKxzQ==
44HPVU6NQB275TGI2CDHPDMVDOJC9LNG86.com. 86400 IN NSEC3 1 1 0 - HPVVN3Q5E5GOQP2QFE2LEM4SVB9C0SJ6 NS DS RRSIG
45HPVU6NQB275TGI2CDHPDMVDOJC9LNG86.com. 86400 IN RRSIG NSEC3 8 2 86400 20200619061821 20200612050821 39844 com. Iz4sOw47dg/aDbs/T9JSAXDiE88bqoj/kYbDQW5dO9NnQicyC5ZqEj0o l1hxJHirVmJtCIXevkSy3eH1rrOH/Ni+oLlWZEBzQnucFK1C4WdBylF2 0OsgaG/AyHSD+9tWgMcQY+i28WBpxmxXvDLHY0oWb89UHMpcduqCh5+n YXnbOHzjvaER/hX1ljveDo0z+HJIBtgY6/0NeFFY0ZWkcA==
46;; Received 761 bytes from 192.43.172.30#53(i.gtld-servers.net) in 248 ms
47
48fex.baidu.com.        600 IN  CNAME   sugar.n.shifen.com.
49n.shifen.com.        86400   IN  NS  ns5.n.shifen.com.
50n.shifen.com.        86400   IN  NS  ns2.n.shifen.com.
51n.shifen.com.        86400   IN  NS  ns4.n.shifen.com.
52n.shifen.com.        86400   IN  NS  ns3.n.shifen.com.
53n.shifen.com.        86400   IN  NS  ns1.n.shifen.com.
54;; Received 241 bytes from 112.80.248.64#53(ns3.baidu.com) in 32 ms

能够看到这是一个逐步缩小范围的查找过程,首先由本机所设置的 DNS 服务器( 192.168.0.1 )向 DNS 根节点查询负责 .com 区域的域务器,而后经过其中一个负责 .com 的服务器查询负责 baidu.com 的服务器,最后由其中一个 baidu.com 的域名服务器查询 www.baidu.com 域名的地址。socket

你在查询某些域名的时会可能会发现和上面不同,最后将会看到有个奇怪的服务器抢先返回结果。。。tcp

这里为了方便描述,忽略了不少不一样的状况,好比 127.0.0.1 其实走的是 loopback,和网卡设备不要紧;好比 Chrome 会在浏览器启动的时预先查询 10 个你有可能访问的域名;还有 Hosts 文件、缓存时间 TTL(Time to live)的影响等。

经过 Socket 发送数据


有了 IP 地址,就能够经过 Socket API 来发送数据了,这时能够选择 TCP 或 UDP 协议,具体使用方法这里就不介绍了,推荐阅读 Beej’s Guide to Network Programming(http://beej-zhcn.netdpi.net/)。

HTTP 经常使用的是 TCP 协议,因为涉及到 TCP 协议的具体细节的资料很容易就能找到,因此本文就不赘述了,只在这里谈一下 TCP 的 队首阻塞 问题:假设客户端发送了 3 个 TCP 片断(segments),编号分别是 一、二、3,若是编号为 1 的包传输时丢了,那么即使编号 2 和 3 已经到达也只能等待,由于 TCP 协议须要保证前后顺序,这个问题在 HTTP pipelining 下更严重,由于 HTTP pipelining 可让多个 HTTP 请求经过一个 TCP 发送,好比发送两张图片,可能第二张图片的数据已经全收到了,但还得等第一张图片的数据传到。

为了解决 TCP 协议的性能问题,Chrome 团队提出了 QUIC 协议,它是基于 UDP 实现的可靠传输,比起 TCP,它能减小不少往返(round trip)时间,还有前向纠错码等功能。目前 Gmail、Google Search、blogspot、Youtube 等几乎大部分 Google 产品都在使用 QUIC,你能够在 Chrome 中的 chrome://flags/#enable-quic 页面找到它的配置。

虽然国内不少大厂也在研究 QUIC 的应用,但离大范围普及还有较长的一段距离,由于若是针对 TCP 进行优化,须要升级系统内核。

浏览器对同一个域名有链接数是有限制得,[通常是 6 个(http://www.browserscope.org/?category=network&v=top),Chrome 团队曾作过实验,发现从 6 改为 10 后性能反而降低了,形成这个现象的因素有不少,如创建链接的开销、拥塞控制等问题,而像 SPDY、HTTP 2.0 协议尽管只使用一个 TCP 链接来传输数据,但性能反而更好,并且还能实现请求优先级。

另外,由于 HTTP 请求是纯文本格式的,因此在 TCP 的数据段中能够直接分析 HTTP 的文本。

Socket 在内核中的实现


前面说到浏览器的跨平台库经过调用 Socket API 来发送数据,那么 Socket API 是如何实现的呢?

以 Linux 为例,它实如今 socket.c(http://lxr.linux.no/linux+v3.14.4/net/socket.c) 中,若是你想深刻研究一下,推荐看 Linux kernel map(http://www.makelinux.net/kernel_map/),它标注出了关键路径的函数,方便学习从协议栈到网卡驱动的实现

底层网络协议的具体例子


接下来若是继续介绍 IP 协议和 MAC 协议可能会把你们搞晕,因此下面用 tcpdump 来经过具体例子讲解,如下是在请求百度首页时抓取到的网络数据:

浏览器是怎样向网卡发送数据的
能够看到最前面的三次通讯是 TCP 协议的三次握手过程,在第四次通讯中被选中的部分为 HTTP 协议(Hypertext Transfer Protocol),在 HTTP 以前有 54 字节(0x36),这就是底层网络协议所带来的开销,咱们接下来对这些协议进行分析。

在 HTTP 之上是 TCP 协议(Transmission Control Protocol),它的具体内容以下图所示:
浏览器是怎样向网卡发送数据的

经过底部的二进制数据,能够看到 TCP 协议是加在 HTTP 文本前面的,它有 20 个字节,其中定义了本地端口(Source port)和目标端口(Destination port)、顺序序号(Sequence Number)、窗口长度等信息,如下是 TCP 协议各个部分数据的完整介绍:

浏览器是怎样向网卡发送数据的
具体每一个字段的做用这里就不介绍了,感兴趣的同窗能够经过阅读 RFC 793(http://tools.ietf.org/html/rfc793),并结合抓包分析来理解

须要注意的是,在 TCP 协议中并无 IP 地址信息,由于这是在上一层的 IP 协议中定义的,以下图所示:

浏览器是怎样向网卡发送数据的
IP 协议一样是在 TCP 前面的,它也有 20 字节,在这里指明了版本号(Version)为 4,源(Source) IP 为 192.168.1.106,目标(Destination) IP 为 119.75.217.56,所以 IP 协议最重要的做用就是肯定 IP 地址。

由于 IP 协议中能够查看到目标 IP 地址,因此若是发现某些特定的 IP 地址,某些路由器就会。。。

可是,光靠 IP 地址是没法进行通讯的,由于 IP 地址并不和某台设备绑定,好比你的笔记本的 IP 在家中是 192.168.0.11,但到公司就变成 10.0.11.11 了,因此在底层通讯时须要使用一个固定的地址,这就是 MAC(media access control) 地址,每一个网卡出厂时的 MAC 地址都是固定且惟一的。

所以再往上就是 MAC 协议,它有 14 字节,以下所示:

浏览器是怎样向网卡发送数据的
当一台电脑加入网络时,须要经过 ARP 协议告诉其它网络设备它的 IP 及对应的 MAC 地址是什么,这样其它设备就能经过 IP 地址来查找对应的设备了。

如今咱们搞清了标题中的问题,不过这里面还有大量的细节没介绍,建议你们经过下面的书籍进一步学习。

扩展学习

相关文章
相关标签/搜索