客户端与服务器断开连接,客户端解释HTML文档,并将图形结果渲染到客户端屏幕上;
一个简单的HTTP事务就这样实现了,看上去很复杂,其实原理挺简单的,需要注意的是,客户端与服务器的通信是非持久连接,也就是当服务器发送完一个响应后就断开与客户端的连接,等待下一次请求。
当用户在浏览器中输入域名,如:并按下回车键时,DNS解析过程一般如下:
DNS解析过程
浏览器缓存检查(本机)
浏览器会先搜索自己的DNS缓存(缓存时间比较短,只有1分钟左右,并且只能容纳1000个缓存),看自己的缓存中是否有对应的条目并且没有过期,如果有,那么解析到此结束。
浏览器缓存域名也是有限制的,不仅浏览器缓存大小有限制,而且缓存时间也有限制,通常从几分钟到几小时不等。可以通过TTL属性来设置域名缓存的时间限制。这个缓存时间太长或者太短都不行,如果缓存时间太长,一旦域名解析到的IP地址发生变化,客户端缓存的域名就无法解析到变化后的IP地址,这样域名就无法正常解析。在这段时间内,部分用户可能无法访问网站,如果时间设置太短,用户每次访问网站都要重新解析域名。
注意:我们如何查看自己的缓存?您可以使用
检查你自己的 DNS 缓存
操作系统缓存检查(本地机器)+hosts解析(本地机器)
如果浏览器在自己的缓存中没有找到对应的条目,那么操作系统其实会有一个域名解析的过程,它会先去操作系统自身的DNS缓存中查找是否有这个域名对应的DNS解析结果,如果找到了并且还没有过期,那么就会停止查找和解析。
其次,在Linux中可以通过/etc/hosts文件进行设置,可以将任意域名解析到任意可访问的IP地址,如果在这里指定了某个域名对应的IP地址,那么浏览器会优先使用这个IP地址。在这个配置文件中解析到某个域名时,操作系统会将解析结果缓存到缓存中,而缓存时间也是由域名的过期时间和缓存空间大小控制的。
本地DNS服务器解析
如果在hosts文件中没有找到对应的条目,那么浏览器就会发起DNS系统调用,向本地配置的首选DNS服务器(LDNS一般由电信运营商提供,也可以使用类似服务提供的DNS服务器)发起域名解析请求(通过UDP协议向DNS的53端口发起请求,该请求是递归请求,也就是说运营商的DNS服务器必须给我们提供域名的IP地址)。
在我们的网络配置中,会有一项叫做“DNS服务器地址”,这个地址就是为了解决上面提到的如果两个进程无法解析,操作系统就会把域名发送给这里设置的LDNS,也就是本地的域名服务器。这个DNS一般是为你本地上网提供一个DNS解析服务,比如你在学校上网,那么你的DNS服务器就一定在你的学校,如果你在小区上网,那么这个DNS就是上网的应用提供商,也就是电信或者联通给你提供的,也就是通常所说的SPA,那么这个DNS一般会在你所在城市的某个角落,一般不会太远。这个专门的域名解析服务器性能不错,他们一般会把域名解析结果缓存起来,当然缓存时间是由域名的过期时间来控制的,一般缓存空间并不是影响域名过期的主要因素。大约80%的域名解析都是在这里完成的,所以LDNS主要承担域名解析的工作。
运营商DNS服务器首先查找自身的缓存,找到对应的条目,如果没有过期,则解析成功。
运营商的 DNS 服务器
根DNS服务器解析(Root)
如果LDNS没有找到对应的条目,那么运营商的DNS就会代替我们的浏览器发起迭代的DNS解析请求,它会先去寻找根域DNS的IP地址(这台DNS服务器内置了13个根域DNS的IP地址),一旦找到根域DNS地址,就会向其发起请求(这个域名的IP地址是什么?)。
根域名服务器将所查询域的主域名服务器(gTLD)地址返回给本地域名服务器。gTLD是国际顶级域名服务器,例如.com、.cn、.org等。全球大概只有13台gTLD服务器。
根域发现这是一个顶级域com的域名,于是就告诉运营商的DNS,我不知道这个域名的IP地址,但是我知道com域的IP地址,让你去找。
本地域名服务器(Local DNS)向上一步返回的gTLD服务器发送请求。
于是运营商的DNS就获取到了com域的IP地址,并向com域的IP地址发起请求(这个域名的IP地址是什么?),com域里的服务器告诉运营商的DNS,我不知道这个域名的IP地址,但是我知道这个域的DNS地址,让你去找。
收到请求的gTLD服务器查找并返回这个域名对应的Name域名服务器的地址,这个Name一般就是你注册的域名服务器,比如你从某个域名服务商那里申请域名,那么域名解析任务就由这个域名提供商的服务器来完成。
然后运营商的DNS就会向这个域名的DNS地址发起请求(这个一般是由域名注册商提供的,比如万网、新网等) (这个域名的IP地址是多少?)。这时候域名的DNS服务器检查发现确实是在这里,所以就把结果发送给运营商的DNS服务器。这时候运营商的DNS服务器就获得了这个域名对应的IP地址。
Name域名服务器会查询存储的域名与IP映射表,正常情况下根据域名获取目标IP记录并连同TTL值一起返回给DNS域名服务器。
返回域名对应的IP和TTL值,本地DNS会缓存域名与IP的对应关系,缓存时间由TTL值控制。
将解析结果返回给用户,用户根据TTL值缓存在本地系统缓存中,域名解析过程完成。
通过上面的步骤我们最终得到了IP地址,也就是浏览器最终发起请求的时候,根据IP和服务器进行信息交换。实际的DNS解析过程中,可能会有十几个步骤,比如Name可能有多个层级,或者有GTM进行负载均衡控制等,这些都可能影响到域名解析的过程。按照上面的解析过程,整个DNS解析过程分为:递归查询过程和迭代查询过程。如图所示:
DNS解析的整个过程
所谓递归查询过程就是“查询提交者”发生变化,而迭代查询过程则是“查询提交者”保持不变。
比如你想知道一个跟你一起上法律课的女孩的电话号码,你偷偷拍了她的照片。等你回到宿舍告诉一个很讲义气的哥们,这个哥们拍着胸脯二话不说的告诉你,你放心,我帮你查一下(这里完成了一个递归查询,也就是询问者的角色被替换了)。然后他拿着照片问了学院的学长,学长告诉他,这个女孩是xx系的;接着这个哥们马不停蹄的问了xx系办公室主任的助理同学,助理同学说她是xx系yy班的。然后这个很讲义气的哥们就去找xx系yy班的班长要这个女孩的电话号码。(这里完成了几次迭代查询,也就是询问者的角色不变,但是询问的对象被反复替换了)最后他把号码递给了你。 整个查询过程就完成了。
4.2 跟踪域名解析过程##
在Linux系统中,也可以使用dig命令来查询DNS解析过程,如下所示:dig +cmd +trace
使用 dig 查询 DNS 解析过程
上面很清晰的展示了整个域名是如何发起和解析的,从根域名(.)到 gTLD(.com.)再到 Name(.)。也可以看出 DNS 服务器有多个备份,可以从任意一个服务器查询解析结果。
4.3 清除缓存域名##
我们知道,DNS域名解析之后,解析结果会被缓存,缓存结果的地方主要有两个,一个是Local DNS,另一个是用户本地机器。这两个缓存都是通过TTL值和本地缓存大小来控制的,但是最大缓存时间是TTL值。基本上Local DNS的缓存时间都是通过TTL来控制的,很难手动干预,不过我们可以通过下面的方式清除本地缓存。
在Linux中,您可以通过/etc/init.d/nscd清除DNS缓存,如下所示:
在 Linux 中清除 DNS 缓存
JVM缓存DNS解析结果:
在 Java 应用中,JVM 还会缓存 DNS 解析结果。这个缓存是在类中做的,而且缓存时间比较特殊,它有两种缓存策略:一种是缓存正确的解析结果,一种是缓存失败的解析结果。这两种缓存时间由两个配置项控制,配置在 %%\lib\\java. 文件中。这两个配置项分别是 .cache.ttl 和 .cache..ttl,它们的默认值分别是 -1(永不过期)和 10(缓存 10 秒)。
修改这两个值的方法也有几种:直接在java.文件中修改默认值、在Java启动参数中添加..ttl=xxx修改默认值、通过类动态修改。
这里要特别强调的是,如果我们需要用一个类来解析域名,那么必须是单例模式,否则会有严重的性能问题,如果每次都创建一个实例,那么每次都要进行一次完整的域名解析,非常耗时,这一点要特别注意。
4.4 几种域名解析方式##A记录,A代表,用于指定域名对应的IP地址
例如指定115.238.23.241和121.14.24.241。A记录可以将多个域名解析到一个IP地址,但不能将一个域名解析到多个IP地址。
MX记录,即Mail记录,意思是你可以将某个域名下的邮件服务器指向你自己的Mail
例如,域名的 A 记录的 IP 地址为 115.238.25.245,如果将 MX 记录设置为 115.238.25.246,则邮件路由正确,DNS 会将邮件发送到 115.238.25.246 所在的服务器。正常的 Web 请求仍然会解析到 A 记录的 IP 地址。
CNAME记录,全称是Name(别名解析),所谓别名解析就是为一个域名设置一个或多个别名
如果 会被解析为 , 也会被解析为 , 其中 分别是 和 的别名。 前面跟踪域名解析中的“1542 IN CNAME”就是CNAME解析。
NS记录为某个域名指定一个DNS解析服务器,即该域名有指定IP地址的DNS服务器来解析
前面的“.IN NS .”即为NS分辨率。
TXT记录,设置主机名或域名的描述
例如,您可以将TXT记录设置为“|中国”。
4.5 网络抓包分析##
在Linux虚拟机测试中使用wget命令进行请求,发现直接使用浏览器会有很多干扰请求,所以使用wget命令进行请求,但是wget命令只能反向请求index.html,不会请求index.html中包含的静态资源(js、css等文件)。
捕获的截图如下:
抓包截图
数据包1是虚拟机广播,试图获取192.168.100.254(网关)的MAC地址,因为局域网内的通讯是靠MAC地址来通讯的。之所以需要跟网关通讯,是因为我们的DNS服务器IP是外设IP,要出去必须靠网关帮我们出去。
数据包2是网关收到虚拟机的广播后,发送给虚拟机的回应,告诉虚拟机自己的MAC地址,以便客户端找到路由出口。
包3是wget命令,向系统中配置的DNS服务器发起域名解析请求(准确的说是wget发起DNS解析系统调用),请求的域名期望是一个IP6地址(AAAA代表IPv6地址)。
数据包4是DNS服务器对系统的回应,显然目前只有极少数人在使用IPv6,所以无法获取AAAA记录。
数据包5和6仍然请求解析IPv6地址,但是主机名不存在,所以结果是没有这个名字。
数据包7:这是与请求的域名对应的IPv4地址(A记录)。
在第8个数据包中,DNS服务器最终从缓存中或者通过迭代查询得到域名的IP地址,并响应系统。系统接着给出wget命令,wget获取IP地址。这里也可以看出,客户端和本地DNS服务器是递归查询的(即服务器必须给客户端一个结果)。现在我们可以开始下一步,进行TCP三次握手了。
5 发起 TCP 三次握手#
User-Agent(一般指浏览器)在得到域名对应的IP地址之后,就会以随机端口(1024<port<65535)向服务器的WEB程序(常用的有httpd、nginx等)80端口发起TCP连接请求。此连接请求(原始的http请求在TCP/IP四层模型中被层层封装)到达服务器之后(经过各种路由设备,局域网除外)进入网卡,然后进入内核的TCP/IP协议栈(用于识别连接请求,解封装,层层剥离),还可能被防火墙(属于内核的一个模块)过滤,最后到达WEB程序,最终建立TCP/IP连接。
如下所示:
.png
首先发送连接探测。ACK = 0 表示确认号无效。SYN = 1 表示这是一个连接请求或连接接受消息,也表示此数据报不能携带数据。seq = x 表示其初始序列号(seq = 0 表示这是数据包编号 0)。此时客户端进入 状态,表示客户端正在等待服务器的回复。
监听到连接请求报文后,如果同意建立连接,就会发送确认。TCP 报文头中的 SYN 和 ACK 都设置为 1,ack = x + 1 表示期望收到对方的下一个报文段第一个数据字节序号为 x+1,同时也表明到 x 为止的所有数据都已正确接收(ack=1 其实是 ack=0+1,也就是期望收到客户端的第一个数据包),seq = y 表示自己的初始序号(seq=0 表示这是服务端发送的第 0 个数据包)。此时进入服务端,表示服务端已经收到连接请求,正在等待确认。
收到确认之后,需要再发送一个确认,同时发送需要发送的数据。ACK设置为1,表示确认号ack=y+1有效(表示你期待收到服务器发来的第一个包),自己的序列号seq=x+1(表示这是我的第一个包,相对于第0个包而言)。收到确认之后,TCP连接进入状态,可以发起http请求了。
查看抓包截图:
抓包截图
TCP为什么需要三次握手?
举个例子,假设一个外国人在故宫迷路了,看到了小明,于是发生了如下对话:
外国人:我,Can you ?
小明:是的。
外国人:好的,我想要......
在问路之前老外先问小明会不会说英语,小明回答会,然后老外就开始问路。
两台计算机之间的通信是通过协议(目前流行的TCP/IP协议)来实现的,如果两台计算机使用的协议不同,那么就无法通信。因此三次握手相当于测试对方是否遵循TCP/IP协议,协商完成后就可以进行通信了。当然这种理解不是那么准确。
扫一扫在手机端查看
我们凭借多年的网站建设经验,坚持以“帮助中小企业实现网络营销化”为宗旨,累计为4000多家客户提供品质建站服务,得到了客户的一致好评。如果您有网站建设、网站改版、域名注册、主机空间、手机网站建设、网站备案等方面的需求,请立即点击咨询我们或拨打咨询热线: 13761152229,我们会详细为你一一解答你心中的疑难。