【读书笔记-《网络是怎样连接的》- 1】Chapter1-从Web浏览器开始

网络之旅的第一章,我们从在浏览器中输入url开始。本章主要介绍三部分内容。首先是在Web浏览器中输入URL后,浏览器是如何解析URL并生成HTTP请求消息的。生成请求消息后,浏览器需要将请求发送给Web服务器,需要知道Web服务器的IP地址。这里讲解DNS服务器的工作原理,如何通过域名查询到IP地址。最后是委托协议栈发送请求消息,本章先讲解协议栈发送消息的基本过程,而详细内容会在第二章继续展开。

1. HTTP请求消息

1.1 URL解析

访问网络,从我们在浏览器中输入网址开始。网址是什么呢?准确来说,叫做URL(Uniform Resource Locator,同一资源定位符)。比如如下所示的URL:

clike 复制代码
http://user:password@www.glasscom.com:80/dir/file1.html

在浏览器中输入URL之后,浏览器首先会对URL进行解析。以上的URL中,user:password为用户名和密码,可以省略;www.glasscom.com表示Web服务器的域名;后面的80为端口号,端口号后的/dir/file1.htm则为需要访问的文件路径。而开头的http,表示的是浏览器使用的访问方法,访问Web服务器时需要使用HTTP协议。此外,还有ftp,mailto等不同的协议。

通过URL,浏览器就可以了解到,需要访问www.glass.com的Web服务器上路径为/dir/file1.html的文件。看起来很简单。

但很多时候,我们输入的URL后面可能是一个目录,比如

clike 复制代码
http://user:password@www.glasscom.com/dir/

更有的时候,干脆连目录都省了:

clike 复制代码
http://user:password@www.glasscom.com

这时候浏览器要如何处理呢?这种情况下,会访问根目录"/"下的默认文件。

1.2 生成HTTP请求消息

解析了URL,浏览器现在知道去哪里获取需要的资源了。接下来就会生成HTTP请求消息。

HTTP协议定义了客户端和服务器端之间交互的消息内容和步骤。首先,客户端向服务器端发送请求消息。请求消息主要包含两个部分:目标和执行的操作。

目标部分被称为URI(Uniform Resource Identifier,统一资源标识符),其内容一般是一个存放网页数据的文件名或一个CGI程序的文件名,也可以直接使用"http:"开头的URL作为URI。

执行的操作被称为方法,表示需要让Web服务器完成怎样的工作。用的较多的有GET、POST、PUT等。

  • GET:: 获取URI指定的信息。如果URI指定的是文件,返回文件的内容;如果是CGI程序,返回该程序的输出数据
  • POST: 从客户端向服务器发送数据,一般用于发送表单中填写的数据等。
  • PUT:: 替换URI指定的服务器上的文件,如果指定的文件不存在,则创建该文件。
  • DELETE: 删除URI指定的服务器上的文件

此外请求消息中还有一些表示附加信息的头字段。

生成的HTTP请求消息的格式是这样的:

clike 复制代码
<方法><空格><URI><空格><HTTP版本>
<字段名>:<字段值>
......
......
<空行>
<消息体>

第一行称为请求行,包括了方法、URI和HTTP版本。根据实际需要,方法选择上面的GET、POST等其中的一种。URI可以根据URL获取,这也没什么问题。此外由于不同版本的HTTP所支持的方法还略有不同,所以这里还要附上HTTP版本号。

第二行开始就是消息头了,包含了一些额外的详细信息。完全弄懂这些信息需要对HTTP协议有很深入的了解,这里就先不深究了。消息头一般在几行到十几行不等。

消息头结束之后,需要添加一个空行,然后是需要发送的请求体。对于GET方法,这部分是不需要填写的。请求体结束之后,整个消息也就结束了。

在接收到Web浏览器的请求消息之后,Web服务器会返回响应消息。响应消息的格式是这样的:

clike 复制代码
<HTTP版本><空格><状态码><空格><响应短语>
<字段名>:<字段值>
......
......
<空行>
<消息体>

在响应消息中,第一行会包含状态码与响应短语,用来表示请求结果是否成功。状态码是一个数字,响应短语则是一段文字,用于告知执行的结果。

状态码 含义
1xx 告知请求的处理进度和情况
2xx 成功
3xx 表示需要进一步操作
4xx 客户端错误
5xx 服务器错误

返回响应消息之后,浏览器将数据提取出来并显示在屏幕上。

如果网页的内容只有文字,那么到这里就结束了。

如果网页的内容包含图片,则是在网页中的相应位置嵌入表示图片文件的标签的控制信息。浏览器在显示文字时会搜索相应的标签,遇到图片相关的标签时就会预留出用来显示图片的空间,接着再次访问Web服务器,获取到图片文件,显示到对应的位置。

1条请求消息中只能写1个URI,所以如果需要获取多个文件,每个文件都需要单独发送一条请求。

2. 通过DNS服务器获取IP地址

2.1 IP地址

HTTP消息有了,需要把消息发送给Web服务器。但是在此之前我们还需要知道服务器域名的IP地址。

在TCP/IP协议中,用集线器把几台计算机连接起来,形成一个子网;而把子网通过路由器连接起来,就组成了一个大的网络。在网络中的设备都会被分配一个地址用于通信,这就是IP地址。类似与我们现实生活中的通信地址,通过IP地址我们就可以把消息发送到想要进行通信的设备。

IP地址是一串32比特的数字,8比特为一组分为4组,每一组用十进制表示,再通过点隔开。IP地址中包含了网络号和主机号,通过子网掩码来区分,如下所示:

clike 复制代码
10.11.12.13/255.255.255.0

子网掩码是一串与IP地址长度相等的数字,与IP地址对齐之后,子网掩码为1对应的部分为网络号,为0的部分则对应主机号。

上面的例子,网络号即为10.11.12,主机号为13。此外主机号部分全部为0,表示整个子网;全部为1,表示向子网的所有设备发送包,即广播。

clike 复制代码
10.11.12.0/255.255.255.0		此IP地址代表整个子网
10.11.12.255/255.255.255.0		此IP地址表示对整个子网广播

通过域名可以定位服务器,通过IP地址也可以定位服务器,但在实际应用的过程中,采用的是人使用域名,而路由器使用IP的方式。对于人来说,域名毕竟要比IP地址容易记忆一些;而对于路由器来说,主要的问题在于域名的长度是不固定的,而且长度可能会很长,处理这样的数据需要耗费路由器很大的计算能力。综合考虑,实际的网络通信中综合使用了域名和IP地址。而为了获取域名对应的IP地址,就需要用到DNS服务器了。通过调用Socket库中的解析器函数"gethostbyname",将需要查询的域名传入,gethostname函数就会向DNS服务器发送请求,获得该域名的IP地址了。

2.2 DNS服务器的工作原理

DNS服务器如何根据域名查询到对应的IP地址呢?

发送给DNS服务器的查询消息包含以下三部分内容。

(1)域名,服务器的名称。

(2)Class,代表互联网的IN

(3)记录类型,表示域名对应何种类型的记录。比如类型为A时,表示域名对应IP地址,为MX时,表示域名对应邮件服务器。

DNS服务器中保存有包含以上三部分信息的记录数据。DNS服务器就是这些信息来对请求做出响应的。

如上表所示,如果要查询www.lab.glasscom.com这个域名对应的IP地址,客户端会向DNS服务器发送包含以下信息的查询消息:

(1)域名:www.lab.glasscom.com

(2)Class: IN

(3)记录类型:A

DNS服务器从已有的记录中查找三项内容都符合的记录,也就找到了对应的IP地址。

看起来原理很简单,但实际网络中存在着不计其数的设备,我们并不知道要查找的域名记录位于哪一台服务器上,这该怎么办呢?

我们先来了解一下域名的层次结构。如下面的例子:

clike 复制代码
www.lab.glasscom.com

越靠右的位置,表示其层级越高。一个层级称为一个域,这里com域的下一层是glasscom域,再下一次层是lab域,最后是www这个名字。

这种具有层次结构的域名信息,在注册到DNS服务器中时,每个域都要作为一个整体,保存在同一台DNS服务器中,而不能拆开保存在多台服务器中。(一台DNS服务器中也可能保存着多个域的信息)

在实际的网络中,通过划分不同的下级域,就构成了这样具有层次结构的域名信息,每一层级的DNS服务器的IP地址,都会注册到它的上一级DNS服务器中,最顶层的是根域,而根域的IP地址在全世界只有13个,根域的地址信息是保存在所有DNS服务器中的。

这样一来,如果我们想要知道查找的域名记录位于哪一台DNS服务器上,可以直接发送请求给根域DNS服务器,从根域服务器开始一层一层地往下寻找。比如根域DNS服务器中,保存了com域DNS服务器的IP地址,这样我们可以找到com域的DNS服务器;而com域的DNS服务器中,又保存了glasscom域的DNS服务器的IP地址,我们可以继续找到glasscom域的DNS服务器......这样一层一层地找下去,我们最终会找到保存着我们想要查询的域名的那台DNS服务器,并获取到对应的IP地址。这个过程,就像一个个DNS服务器的接力。

此外,为了加快访问速度,DNS服务器还具有缓存功能。将查询过的域名保存在缓存中,下一次查询同样的域名时可以先从缓存中查找,如果找到了就直接返回,而无需再从根域服务器逐级向下查找。有时候,将信息保存到缓存中之后,原来的注册信息可能发生了变化,这时候缓存的信息可能就不正确了。所以DNS服务器中缓存的信息有一个有效期限,超过期限的缓存信息会被删除。

3. 委托协议栈发送请求消息

HTTP请求消息有了,IP地址也知道了,接下来就可以把消息发送给Web服务器了。不过这一过程Web浏览器自身无法完成,需要通过网络协议栈来完成。简单来说,可以理解为在客户端与服务器端之间建立了一条数据管道,数据从管道一端进入,然后从另一端被取出。整个过程可以分为四个过程:

(1) 创建套接字

(2) 将管道连接到服务器端的套接字

(3) 收发数据

(4) 断开管道并删除套接字

这四个过程也需要分别调用Socket库中的对应函数。下面分别进行讲解。

3.1 创建套接字(Socket)阶段

建立数据管道,关键在于管道两端的数据出入口,称为套接字(Socket)。实际的通信过程中,服务器一方先创建好一个套接字等待客户端向该套接字连接管道。服务器进入准备状态之后,客户端就可以创建套接字并连接管道了。客户端创建套接字需要调用Socket库中的socket函数。该函数会返回一个描述符。由于客户端可能创建许多不同的套接字,用于不同的通信,因此该描述符用于识别不同的套接字。

3.2 连接阶段

客户端的套接字创建好之后,需要将其与服务端的套接字连接起来。这里调用的是Socket库中的函数connect。该函数需要传入的参数为描述符、服务器IP地址和端口号。

描述符即上一阶段创建套接字时返回的描述符,用来区分客户端用哪一个套接字去连接服务器端;服务器IP地址,即通过DNS服务器查询得到的IP地址;而端口号,与IP地址搭配,用于定位服务器端的套接字。也就是说,通过服务器IP地址和端口号,我们可以确定连接到服务器端的哪一个套接字。

服务器上的端口号是根据应用种类规定好的。比如Web服务使用的就是80端口号,电子邮件则是25。根据指定的端口号,就可以确定连接到服务器端的哪个套接字了。类似地,客户端在创建套接字时,协议栈会分配一个端口号,执行连接操作时,这个端口号会被通知给服务器,这样服务器也是通过客户端的端口号来找到客户端的套接字。

连接成功后,对方的IP地址与端口号等信息会被保存在套接字中,接下来就可以开始收发数据了。

3.3 通信阶段

套接字的连接建立好之后,只需要将数据送入套接字,对方就会从套接字中获取到数据。将数据送入套接字需要调用Socket库中的write函数,其需要传入的参数为描述符和发送的数据。描述符用来定位己方的套接字。由于套接字中保存了对方的IP地址与端口号,目标明确,这样数据就会被传送到服务器端。

接受返回消息时,则需要调用read函数,并指定存放响应消息的内存地址,即缓冲区。通过read函数,返回消息被读入到缓冲区中。

3.4 断开阶段

数据收发过程结束,就可以调用close函数进入断开阶段了。根据应用种类的不同,有些是客户端先调用close函数,而有些则是服务器端先调用。最终套接字之间的管道被断开,套接字也被删除,通信过程结束。

本章简单介绍了从浏览器输入网址,到HTTP信息由协议栈发送给服务器端之间的过程。这一过程实际上离不开协议栈、网卡驱动和网卡。下一章会详细探讨协议栈与网卡部分的工作,敬请期待。

相关推荐
aloha_7892 小时前
从零记录搭建一个干净的mybatis环境
java·笔记·spring·spring cloud·maven·mybatis·springboot
dsywws3 小时前
Linux学习笔记之vim入门
linux·笔记·学习
A-超6 小时前
vue3展示pag格式动态图
笔记
u0101526586 小时前
STM32F103C8T6学习笔记2--LED流水灯与蜂鸣器
笔记·stm32·学习
weixin_518285056 小时前
深度学习笔记10-多分类
人工智能·笔记·深度学习
丘狸尾6 小时前
ubuntu【桌面】 配置NAT模式固定IP
笔记
王俊山IT7 小时前
C++学习笔记----10、模块、头文件及各种主题(二)---- 预处理指令
开发语言·c++·笔记·学习
慕卿扬7 小时前
基于python的机器学习(二)—— 使用Scikit-learn库
笔记·python·学习·机器学习·scikit-learn
齐 飞9 小时前
MongoDB笔记02-MongoDB基本常用命令
前端·数据库·笔记·后端·mongodb
flying robot9 小时前
Go结构体(struct)
笔记