网络是怎样连接的 (一) Web浏览器

第一章 Web浏览器

第一节 生成HTTP请求消息

1. 输入网络地址

网址,即URL(Uniform Resource Locator)统一资源定位符,通俗理解就是网站,指资源等在网络中的地址。

访问目标不同URL的写法有区别:

  • 访问Web服务器 http:XXX
  • 访问FTP服务器 ftp:XXX (FTP 文件传送协议,通常在上传下载文件时使用)
  • 访问本地文件 file:XXX
  • 发送电子邮件 mailto:XXX
  • 阅读新闻组文章 news:XXX

不同的访问方法就表示访问时遵照不同的协议,协议是通信操作时遵守的规则,file是访问本地文件不涉及网络传输,所以理解为访问方法即可。

2. 浏览器解析URL

浏览器第一步任务就是解析URL,根据HTTP等规格,分别对URL进行切分和理解。

1
2
如http://www.baidu.com/a/b.html
可以解析出http协议,//后面获取服务器地址,再后面获取目录和文件,即文件的访问地址。

省略文件名:以”/”结尾,表示访问默认文件(如index.html等),若连此符号都没,也是允许的,会访问根目录下事先设置的默认文件(远古时代叫主页,现在已不合适了)。

2. HTTP协议

HTTP协议定义了客户端和服务器之间的交互内容和步骤:客户端发送请求消息,包括URI和方法,就是对什么和进行什么操作两部分。

对什么就是指URI,Uniform Resource Identifier统一资源标识符。可以指所有的可访问目标。

进行什么操作就是指方法,用来告知Web服务器想要完成的操作,在REST中使用频率很高。

方法一般如下:

方法 HTTP1.0 HTTP1.1 含义
GET 获取URI指定的信息,若URI指定的是文件则返回文件的内容,若指定的是CGI程序,则返回程序的输出数据。
POST 从客户端向服务器发送数据,一般用于发送表单中数据等情况下
HEAD 和GET基本相同,不过它只返回HTTP的消息头,不返回数据的内容。用于获取文件最后更新时间等属性信息
OPTIONS 用于通知或查询通信选项
PUT 替换URI指定的服务器上的文件。如果URI指定的文件不存在,则创建该文件
DELETE 删除URI指定的服务器上的文件
TRACE 将服务器收到的请求行和头部直接返回给客户端。用于在使用代理的环境中检查改写请求的情况
CONNECT 使用代理传输加密消息时使用的方法

△非正式规格,附加功能。

除以上内容外,HTTP消息中还有一些用来表示附加信息的头字段(header),客户端向Web服务器发送数据时,会先发送头字段,然后再发送数据。头字段数据可有可无。

收到请求消息后,Web服务器对内容解析,根据要求完成对应工作,将结果存放在响应消息中。

响应消息开头会有一个状态码,它表示操作的执行结果是成功还是有错误。找不到文件时所返回的404错误信息对应的就是状态码。

客户端接收到响应消息,读取数据并显示,HTTP的工作完成。

一次(成功的)GET请求的访问过程:

请求消息中标明GET方法,在URI中写存放网页相关数据的文件”/xx/xx.html”,Web服务器收到消息,打开文件并读取出其中数据,存放到响应消息中返回给客户端,客户端浏览器接收到数据并显示。

POST请求:

网页中带有输入信息的部分就是表单,使用POST请求,URI指向Web服务器中运行的一个应用程序的文件名(.cgi,.php等),除了方法和URI外还要携带输入的信息数据给应用或脚本。

有了这些HTTP方法,Web服务器甚至可以作为文件服务器,但出于安全等考虑,一般很少使用GET,POST之外的方法。

GET和POST方法区别:

参照w3school教程:

http://www.w3school.com.cn/tags/html_ref_httpmethods.asp

GET POST
后退/刷新 无害 数据会被重新提交
书签 可收藏为书签 不可收藏为书签
缓存 能被缓存 不能被缓存
编码类型 application/x-www-form-urlencoded application/x-www-form-urlencoded或multipart/form-data 二进制数据使用多重编码
历史 参数保留在浏览器历史中 参数不会保存在浏览器历史中
对数据长度的限制 有限制,GET方法向URL中添加数据,URL长度受限制,最大2048字符 无限制
对数据类型的限制 只允许ASCII 字符 无限制,二进制数据也可以
安全性 发送数据是URL的一部分,不应在处理敏感数据时使用 POST比GET更安全,参数不会被保存在浏览器历史或Web服务器日志中
可见性 数据在URL中是可见的 数据不会显示在URL中

为了避免一直重复提交一般有以下方法:

  • PRG 若是POST请求跳转,请求后根据结果重定向到其他界面
  • POST只请求数据,前端加处理,加唯一键,用submit+return false来锁定,避免重复提交

3. 生成HTTP请求消息

浏览器根据解析URL的信息来生成HTTP请求消息。

请求消息格式:

1
2
3
4
5
6
<方法><space><URI><space><HTTP版本>
<字段名>:<字段值>


<空行>
<消息体>
  1. 第一行是请求行,方法告诉Web服务器需要进行那种操作。

方法有多种,需要根据浏览器的工作状态来判断是哪种方法,比如在地址栏输入访问,或是点击超链接,又或是点击表单提交按钮等。地址栏输入访问就是GET方法,表单,在HTML中会在表单属性指定方法,可以是GET或POST。

  1. 消息体包含客户端向服务器发送的数据。

如POST请求向服务器提交的表单数据,GET提交表单时数据作为参数写入URI中。

  1. 第二行开始中间的部分为消息头。

消息头中定义了很多项目数据,是非常细节的信息,主要头字段如下:日期,客户端支持数据类型,语言,压缩格式,客户端和服务器软件名称和版本等。

(表格暂缺,头字段实在是太多了)

  1. 浏览器收到响应消息

响应消息和请求消息格式大致相同,区别在第一行。

1
<状态码><space><响应短语>

用来表示执行的结果

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

1条请求消息中只能写一个URI,即一次请求只能请求一个文件。
所以请求一个网页时(含图片),会一次发送多次请求。

2. 向DNS服务器查询Web服务器的IP地址

1. IP地址

浏览器解析网址生成HTTP消息后,需要将消息发送出去,但浏览器本身不具有这一功能,需要委托操作系统来实现。

在此之前需要查询服务器域名对应的IP地址,就像委托一位刺客暗杀对手,需要提供一份刺客可以看懂的身份地址信息,操作系统需要的就是IP地址。

TCP/IP体系结构大致就是由最小的子网(通过集线器连接的一些计算机组成)通过路由器连接起来组成一个网络。在这个体系中,整个子网会分配一层地址,而每个计算机则会获得子网分配的下一层地址,这个地址整体叫做IP地址

IP地址是一串32bit的数字,一组8bit分为4组,分别用10进制表示用圆点隔开。

网络号和主机号组合起来共32bit,但各占多少是不固定的,用户可以自由决定它们之间的分配,所以需要子网掩码来确定IP地址的内部结构。

子网掩码,是一串和IP相同长度的32bit数字,子网掩码为1的部分为网络号,0的部分为主机号。

关于IP地址的知识在大学计算机网络这门课中已经讲的比较全面了,这里就不再详细描述了。

2. 域名和IP地址并用的理由

互联网使用经验告诉我们用IP地址来代替域名是可以的,但数字是一串无规律串相较文字性的域名不适合人类使用习惯。

那为什么不直接用域名代替IP地址?

从运行效率上看是不行的,IP地址长度是32bit,也就是4个字节,而域名起码要几十个字节,最大255个字节,使用IP地址时只要处理4字节数字,而域名则要处理几十倍的数字,而且长度不固定,有代码经验就可以体会到不固定长度相较固定长度的复杂。在路由器不断提升的同时,要处理的数据量也不断的提高,从设计角度看,使用域名来确定通信对象就不是一个好的设计。

DNS:通过名称来查询IP地址的机制

3. Socket库提供查询IP地址的功能

询问最近的DNS服务器某网址的IP地址,也就是向DNS服务器发送查询消息,计算机本地的DNS客户端叫DNS解析器,这个过程又叫域名解析

解析器包含在操作系统的Socket库中。Socket库中主要包含给应用程序调用的相关网络功能组件,解析器就是其中一个组件。

4. 通过解析器向DNS发出查询

编写浏览器等程序时,只要调用解析器实现调用方法:配置解析器程序名称,要查询的Web域名,解析器会将IP地址写入指定的内存地址。

5. 解析器内部原理

1
2
<内存空间> = gethostbyname(“www.xxxx.com”);
……

解析器DNS服务器发送查询消息(二进制数据,UDP消息),这个发送是委托OS内部的协议栈TCP/IP来执行。

DNS服务器对查询消息中内容进行查询,将查询结果写入响应消息,然后返回给客户端,经协议栈传递给解析器解析器取出IP地址,写入浏览器指定内存地址,浏览器发送消息时只要从内存地址中取出IP地址,将其和HTTP请求消息一起给OS即可。

计算机和网络中的大部门流程都是这样一层一层的分工协作,每一层完成一部分工作然后委派。(DNS服务器的IP地址是预先设置好的,不同OS设置方法可能不同,可以在windows等系统中配置TCP/IP属性了解)

3. DNS服务器间接力

1. DNS服务器基本工作

接收客户端查询消息(域名,Class-IN表示互联网,记录类型-A表示域名是IP地址-MX表示邮件服务器等),根据消息内容返回相应的响应。

2. 域名的层次结构

存储互联网中服务器信息的DNS服务器肯定是有一定数量的,所以DNS服务器间需要有机制来存储查询这些数据。
首先DNS服务器中所有信息按域名分层次结构储存,每一层用句号.来分割,一层就是一个整体,越右层级越高,层级可扩展,可以任意分配。

3. 寻找对应DNS服务器

DNS服务器会依照域,上一级DNS服务器管理上一级域,下一级的DNS服务器会注册在上级DNS服务器中,域的上下级对应服务器的上下级。

根域是最上级域,一般被忽略,可以在com这一级域后加.,其服务器中保存com等服务器信息,可以一层层的找到任意一个域的服务器,根域服务器地址保存在任意DNS服务器中,因此所有DNS服务器都可以通过从上向下查询任意域服务器。

4. 通过缓存加快DNS服务器的响应

一台服务器可以管理多个域,所以查询时并非一定一层转一个服务器,因为地址一般不会更改,所以DNS服务器中有一个缓存功能,记录查询过的域名,若域名在缓存中找到就不用再去其他DNS服务器查询了,但缓存信息可能会随时间失效不准确,所以会设置一个有效期,超过有效期会删除,DNS也会告知客户端返回结果是从缓存还是真实记录地址的DNS服务器查询的。

4 委托协议栈发送消息

1. 数据收发

HTTP消息是一种数字消息,所有应用程序相关操作都是类似的委托协议栈接收和发送数字消息的过程,需要使用Socket库中的程序组件。

向操作系统内部的协议栈发送委托时,需要按照指定的顺序来调用Socket库中的程序组件。
(socket就是套接字)

收发数据流程:

  1. 服务器先创建socket,等待(一般发生在服务器启动时)
  2. 客户端创建socket链接到服务器端socket上,创建数据通道
  3. 收发数据
  4. 断开通道,删除socket

2. 创建socket阶段

1
2
3
4
5
6
7
8
9
10
11
12
<内存地址> = gethostbyname(“www.xxxx.com”);

<描述符> = socket(<使用Ipv4><流模式>,…);//1.准备,从DNS服务器查询域名对应的信息

connect(<描述符><服务器的IP地址和端口号>,…);//2.连接Web服务器

write(<描述符><发送数据><发送数据长度>);//3.发送

<接收数据长度> = read(<描述符><接收缓冲区>,…);//3.`接收

close(<描述符>);//4.断开

描述符是标识一次连接的socket,协议栈以此来判断程序希望使用哪个socket来连接或收发数据

3. 连接阶段,创建通道

应用程序调用Sockey库中的connect程序组件来完成此操作。

connect需要参数:描述符,服务器IP地址,端口号。(IP地址+端口号可以确定socket,描述符只用于应用和协议栈之间交互,连接的另一方无法得知,所以一套描述符本机识别,一套IP+端口网络双方识别)

4. 通信阶段,传递消息

socket连接起来了,但应用程序无法直接接触socket,需要通过Socket库委托协议栈来操作,调用write组件,然后协议栈发送数据给连接的通信对象,服务器接收,解析,执行相应操作,返回响应消息。然后通过Socket库中read组件委托协议栈读取数据到指定内存地址。

5. 断开阶段,收发数据结束

通信结束,双方都可能执行断开操作,调用Socket库中close组件断开连接,对方的socket也会进入断开阶段。HTTP协议规定,Web服务器执行响应后应主动断开连接,所以服务器先断开,传送到客户端,客户端socket也进入断开阶段,浏览器调用read接收数据时得知socket连接断开,也会调用close进入断开阶段(socket断开和最终断开区别)。

因此传输一个对象,一次数据,就要执行一遍上述过程,重复的操作是很不合理的,因此HTTP1.1之后一次连接就可以发出多个请求和响应了,操作都结束后才会断开连接。


参考博客和文章书籍等:

《网络是怎样连接的》

因博客主等未标明不可引用,若部分内容涉及侵权请及时告知,我会尽快修改和删除相关内容