网络是怎样连接的---DNS服务器和数据收发操作

DNS服务器

尽管浏览器能够解析网址并生成 HTTP 消息,但它本身并不具备将消息发送到网络中的功能,因此这一功能需要委托操作系统来实现 。在委托操作系统发送消息时,必须要提供的不是通信对象的域名,而是它的 IP 地址。因此,在生成 HTTP 消息之后,下一个步骤就是根据域名查询 IP 地址。

IP地址和子网掩码

互联网和公司内部的局域网都是基于 TCP/IP 的思路来设计的,所以先来了解 TCP/IP 的基本思路。TCP/IP 的结构就是由一些小的子网,通过路由器连接起来组成一个大的网络。在网络中,所有的设备都会被分配一个地址。这个地址就相当于现实中某条路上的“×× 号 ×× 室”。“号”对应的号码称为网络号,“室”对应的号码称为主机号,这个地址的整体称为 IP 地址。通过 IP 地址我们可以判断出访问对象服务器的位置,从而将消息发送到服务器。
实际的 IP 地址是一串32 比特的数字,按照 8 比特(1 字节)为一组分成 4 组,分别用十进制表示然后再用圆点隔开。但仅凭这一串数字我们无法区分哪部分是网络号,哪部分是主机号,需要另外的附加信息来表示 IP 地址的内部结构。这一附加信息就是子网掩码,是一串与 IP 地址长度相同的 32 比特数字,其左边一半都是 1,右边一半都是0。其中,子网掩码为 1 的部分表示网络号,子网掩码为 0 的部分表示主机号。可以采用和IP地址相同的格式表示子网掩码,写在 IP 地址的右侧,如192.168.1.2/255.255.255.0;也可以把 1 的部分的比特数用十进制表示并写在 IP 地址的右侧,如192.168.1.2/24。这两种方式只是写法上的区别,含义是完全一样的。
TCP/IP 网络是通过 IP 地址来确定通信对象的,需要有一个机制能够通过名称来查询 IP 地址,或者通过 IP 地址来查询名称,这个机制就是 DNS。

通过DNS查询IP地址

查询 IP 地址的方法非常简单,只要询问DNS服务器指定的域名的IP地址是什么,并接收DNS 服务器返回的响应。对于 DNS 服务器,我们的计算机上一定有相应的 DNS 客户端,而相当于 DNS 客户端的部分称为 DNS 解析器,或者简称解析器。通过 DNS 查询 IP 地址的操作称为域名解析。
解析器实际上是一段程序,它包含在操作系统的 Socket 库中(Socket 库是用于调用网络功能的程序组件集合)。通过解析器向 DNS 服务器发出查询具体就是在编写浏览器等应用程序的时候,写上解析器的程序名称“gethostbyname”以及 Web 服务器的域名“www.lab.glasscom.com”,这样就完成了对解析器的调用。(根据域名查询 IP 地址时,浏览器会使用 Socket 库中的解析器。)

<应用程序名>(<参数>)
{
	...
	...
	<内存地址> = gethostbyname("www.lab.glasscom.com");
	...
	...
	<发送HTTP消息>
	...
}

调用解析器后,解析器会向 DNS 服务器发送查询消息,然后 DNS 服务器会返回响应消息。响应消息中包含查询到的 IP 地址,解析器会取出 IP地址,并将其写入浏览器指定的内存地址中。
发送消息这个操作并不是由解析器自身来执行,而是要委托给操作系统内部的协议栈来执行。这是因为和浏览器一样,解析器本身也不具备使用网络收发数据的功能。解析器调用协议栈后,控制流程会再次转移,协议栈会执行发送消息的操作,然后通过网卡将消息发送给 DNS 服务器。
调用解析器时计算机内部的工作流程
DNS 服务器会从域名与 IP 地址的对照表中查找相应的记录,并返回 IP 地址。然而,互联网中存在着不计其数的服务器,将这些服务器的信息全部保存在一台 DNS 服务器中是不可能的,因此要将信息分布保存在多台 DNS 服务器中,这些 DNS 服务器相互接力配合,从而查找出要查询的信息。

DNS服务器的内部查询

DNS 中的域名都是用句点来分隔的,比如 www.lab.glasscom.com,这里的句点代表了不同层次之间的界限,在域名中,越靠右的位置表示其层级越高,其中,相当于一个层级的部分称为域。实际上,互联网中的域也是一样,通过创建下级的域来分配给不同的国家、公司和组织使用。最上层的 com 代表分配给中国这个国家的域;下一层的 glasscom 是中国国内进行分类的域,代表公司;再下层的 lab 就是分配给某个公司的域;最下层的 www 就是服务器的名称。
一个域的信息是作为一个整体存放在 DNS 服务器中的,不能将一个域拆开来存放在多台 DNS 服务器中。不过,DNS 服务器和域之间的关系也并不总是一对一的,一台 DNS 服务器中也可以存放多个域的信息。为了避免把事情搞得太复杂,这里先假设一台 DNS 服务器中只存放一个域的信息。
首先,将负责管理下级域的 DNS 服务器的 IP 地址注册到它们的上级 DNS 服务器中,然后上级 DNS 服务器的 IP 地址再注册到更上一级的 DNS 服务器中,以此类推。也就是说,负责管理 lab.glasscom.com 这个域的 DNS 服务器的 IP 地址需要注册到 glasscom.com 域的 DNS服务器中,而 glasscom.com 域的 DNS 服务器的 IP 地址又需要注册到 com域的 DNS 服务器中。这样,我们就可以通过上级 DNS 服务器查询出下级DNS 服务器的 IP 地址,也就可以向下级 DNS 服务器发送查询请求了。实际上在互联网中,com 和 jp 的上面还有一级域,称为根域。在一般书写域名时经常被省略,如果要明确表示根域,应该像 www.lab.glasscom.com. 这样在域名的最后再加上一个句点,而这个最后的句点就代表根域。
DNS 服务器之间的查询操作
1、客户端首先会访问最近的一台 DNS 服务器,由于最近的 DNS 服务器中没有存放 www.lab.glasscom.com 这一域名对应的信息,所以我们需要从顶层开始向下查找。
2、最近的 DNS 服务器中保存了根域 DNS 服务器的信息,因此它会将来自客户端的查询消息转发给根域 DNS 服务器,根域服务器中也没有 www.lab.glasscom.com 这个域名,但根据域名结构可以判断这个域名属于 com 域,因此根域 DNS 服务器会返回它所管理的 com 域中的DNS 服务器的 IP 地址。
3、接下来,最近的 DNS 服务器又会向 com 域的DNS 服务器发送查询消息com 域中也没有www.lab.glasscom.com这个域名的信息,和刚才一样,com 域服务器会返回它下面的 glasscom.com域的 DNS 服务器的 IP 地址。
4、以此类推,可以找到目标 DNS 服务器,要向目标 DNS 服务器发送查询消息,就能够得到我们需要的答案,也就是 www.lab.glasscom.com 的 IP 地址了。
这是寻找相应DNS服务器并获取IP地址的基本原理。实际上,一台 DNS 服务器可以管理多个域的信息,中上级域和下级域有可能共享同一台 DNS 服务器,在这种情况下,访问上级 DNS 服务器时就可以向下跳过一级 DNS 服务器,直接返回再下一级 DNS 服务器的相关信息。同时,DNS 服务器有一个缓存功能,可以记住之前查询过的域名。如果要查询的域名和相关信息已经在缓存中,那么就可以直接返回响应,接下来的查询可以从缓存的位置开始向下进行。并且,当要查询的域名不存在时,“不存在”这一响应结果也会被缓存。这样,当下次查询这个不存在的域名时,也可以快速响应。

数据的收发操作

知道了 IP 地址之后,就可以委托操作系统内部的协议栈向这个目标 IP地址,也就是我们要访问的 Web 服务器发送消息了。向操作系统内部的协议栈发出委托时,需要按照指定的顺序来调用 Socket 库中的程序组件。
在进行收发数据操作之前,双方需要先建立起类似管道的数据通道才行,将数据从一端送入管道,数据就会到达管道的另一端然后被取出。数据可以从任何一端被送入管道,数据的流动是双向的。
建立管道的关键在于管道两端的数据出入口,这些出入口称为套接字。我们需要先创建套接字,然后再将套接字连接起来形成管道。首先,服务器一方先创建套接字,然后等待客户端向该套接字连接管道,客户端也会先创建一个套接字,然后从该套接字延伸出管道,最后管道连接到服务器端的套接字上。接下来,只要将数据送入套接字就可以收发数据了。当数据全部发送完毕之后,连接的管道将会被断开。管道在连接时是由客户端发起的,但在断开时可以由客户端或服务器任意一方发起。其中一方断开后,另一方也会随之断开,当管道断开后,套接字也会被删除。

创建套接字

客户端创建套接字的操作非常简单,只要调用 Socket 库中的 socket 程序组件就可以了。套接字创建完成后,协议栈会返回一个描述符,应用程序会将收到的描述符存放在内存中。
描述符是用来识别不同的套接字的,同一台计算机上可能同时存在多个套接字,在这样的情况下,我们就需要一种方法来识别出某个特定的套接字,这种方法就是描述符。
应用程序是通过“描述符”这一类似号码牌的东西来识别套接字的。只要我们出示描述符,协议栈就能够判断出我们希望用哪一个套接字来连接或者收发数据了。

管道连接

接下来,需要委托协议栈将客户端创建的套接字与服务器那边的套接字连接起来。
管道的连接通过调用 Socket 库中的名为 connect 的程序组件来完成这一操作。该函数需要3个参数:描述符、服务器IP地址、端口号。不能仅仅使用描述符来识别套接字,因为描述符是和委托创建套接字的应用程序进行交互时使用的,并不是用来告诉网络连接的另一方的,因此另一方并不知道这个描述符。所以,我们需要另外一个对客户端也同样适用的机制,而这个机制就是端口号。
服务器上所使用的端口号是根据应用的种类事先规定好的,比如 Web 是 80 号端口,电子邮件是 25 号端口。只要指定了事先规定好的端口号,就可以连接到相应的服务器程序的套接字。
描述符:应用程序用来识别套接字的机制
IP 地址和端口号:客户端和服务器之间用来识别对方套接字的机制

传递消息

只要将数据送入套接字,数据就会被发送到对方的套接字中。当然,应用程序无法直接控制套接字,因此还是要通过 Socket 库委托协议栈来完成这个操作。这个操作需要使用 write 这个程序组件。
由于套接字中已经保存了已连接的通信对象的相关信息,所以只要通过描述符指定套接字,就可以识别出通信对象,并向其发送数据。接着,发送数据会通过网络到达我们要访问的服务器。
当消息返回后,需要执行的是接收消息的操作。接收消息的操作是通过 Socket 库中的 read 程序组件委托协议栈来完成的,read 就会负责将接收到的响应消息存放到指定的内存地址中。

断开连接

当浏览器收到数据之后,收发数据的过程就结束了。接下来,我们需要调用 Socket 库的 close 程序组件进入断开阶段。最终,连接在套接字之间的管道会被断开,套接字本身也会被删除。
客户端和服务器的一方首先调用close 来断开连接断开操作传达到另一方之后,另一方的套接字也会进入断开阶段。接下来,当浏览器调用 read 执行接收数据操作时,read 会告知浏览器收发数据操作已结束,连接已经断开。浏览器得知后,也会调用close 进入断开阶段。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值