Fork me on GitHub

Note for Computer Network 2

Note for Computer Network 2

副标题:阅读《网络是怎么连接的(户根勤)》读书笔记2

生成 HTTP 请求消息

动作:对URL 进行解析
效果:浏览器确定了 Web 服务器和文件名
后续:根据这些信息来生成 HTTP 请求消息

1

  • 消息头存放“请求行没说清楚的”额外信息,消息头的规格中定义了很多项目,如日期、客户端支持的数据类型、语言、压缩格式、客户端和服务器的软件名称和版本、数据有效期和最后更新时间等。比如Date、Pragma、Cache-control、Connection、Transfer-Encoding、Via等,参考HTTP头字段-wiki百科
  • 写完消息头之后,还需要添加一个完全没有内容的空行,然后写上需要发送的数据(即消息体)

2

  • 响应消息与请求消息差别仅在第一行,内容为状态码和响应短语,用来表示请求的执行结果是成功还是出错。
状态码 含义
1xx 告知请求的处理进度和情况
2xx 成功
3xx 表示需要进一步操作
4xx 客户端错误
5xx 服务器错误
  • 返回响应消息之后,浏览器会将数据提取出来并显示在屏幕上,我们就能够看到网页的样子了。如果网页的内容只有文字,那么到这里就全部处理完毕了,但如果网页中还包括图片等资源,则还有下文
  • 当网页中包含图片时,会在网页中的相应位置嵌入表示图片文件的标签的控制信息。浏览器会在显示文字时搜索相应的标签,当遇到图片相关的标签时,会在屏幕上留出用来显示图片的空间,然后再次访问 Web服务器,按照标签中指定的文件名向Web服务器请求获取相应的图片并显示在预留的空间中
    [扩展思考]就是因为图文的异步,所以可以考虑采用多线程的方式,先刷出文字,后刷出图片,提升浏览器阅读体验
  • 由于每条请求消息中只能写 1 个 URI,所以每次只能获取 1 个文件,如果需要获取多个文件,必须对每个文件单独发送 1 条请求。即,3张图片==额外3次request

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

  • 浏览器虽然可以生成标准Http消息,但不具备发送功能,需要借助os来完成
  • os发送Http消息时,需要知道目标的IP地址,而非域名,所以发送前需要通过域名查询到IP地址,之后才能委托给os

IP地址

  • IP地址主体表示为:10.12.13.14格式,网络号和主机号连起来总共是 32 比特,但这两部分的具体结构是不固定的
  • 在组建网络时,用户可以自行决定它们之间的分配关系,因此,我们还需要另外的附加信息(即子网掩码)来表示 IP 地址的内部结构
  • 子网掩码为1的部分表示网络号、为 0的部分表示主机号,子网掩码表示网络号与主机号之间的边界
  • 带子网掩码的IP地址为:10.1.2.3/255.255.255.0或者10.1.2.3/24,两者含义完全一致(24表示子网掩码中1有24位)
十进制表示 二进制
IP地址 10.1.2.3 00001010.00000001.00000010.00000011
子网掩码 255.255.255.0 11111111.11111111.11111111.00000000
网络号 10.1.2 00001010.00000001.00000010
主机号 3 00000011
[注]上例中,子网掩码刚好分隔在小数点。。事实上化分在字节中间亦可

3

DNS服务器&DNS解析器

  • DNS解析器向DNS服务器发送查询IP的消息,并接受响应消息
  • 解析器其实是OS的socket库中的一段程序(一种程序组件),Socket库也是一种库(一堆程序组件),其中包含的程序组件可以让其他的应用程序调用操作系统的网络功能
  • 在编写浏览器等应用程序的时候,只要写上解析器的程序名称“gethostbyname”以及 Web服务器的域名(待解析),就完成了对解析器的调用。
1
2
3
4
<!--网络应用程序,
运行以下代码后,服务器的IP地址就会被写入内存地址中-->
<内存地址> = gethostbyname("www.baidu.com");
<!--发送Http消息-->

解析器内部工作原理

  • 解析器发送查询消息的过程,与浏览器生成要发送给 Web 服务器的 HTTP请求消息的过程类似,但发送消息的操作由解析器委托给OS内部协议栈(也叫TCP/IP驱动)来执行。
  • 协议栈通过网卡将消息发送给DNS服务器
  • 其中,DNS服务器的IP地址是作为TCP/IP的一个设置项目提前设置好了的,无需进行查询操作

查询消息

  1. 域名:服务器或邮件服务器名称
  2. Class:目前只有互联网,所以是IN
  3. 记录类型:类型A代表IP地址;类型MX代表邮件服务器

[理解:链级查询]客户端会先访问最近的一台DNS服务器,如果没有想要查询的记录,就会将查询消息发送给根域DNS服务器,再向下查询最终找到目标DNS服务器。向目标DNS服务器发送查询消息,就会得到对应的IP地址

  • 实际的互联网中,上下级域可能采用共享方式,链级查询时可以跳级查询;DNS服务器还可以缓存最近查询信息。以上两种方法提高查询效率
  • 缓存的方式有可能造成不一致,所以缓存信息有一个有效期,超过有效期将删除缓存数据

委托协议栈发送消息

  • 此处的消息是数字信息——digital data
  • 向协议栈发送消息时,需按照指定的顺序调用socket库中的多个程序组件(即进行委托)

[补充内容]协议栈接受委托后收发数据操作的整体思路

  1. 收发数据的两台计算机之间连接了一条双向数据通道
  2. 建立管道的关键在于管道两端的数据出入口,这些出入口称为套接字
  3. 服务器程序在启动后就创建好套接字并等待客户端连接;客户端也会先创建一个套接字,从该套接字延伸出管道,连接到服务器端的套接字上,由此,通信准备工作完成
  4. 当数据发送完毕后,管道会被断开,断开可由两方的任意一方发起(一般Http版本有规定),断开后套接字也会被删除,通信结束
  5. 四个阶段分别为:创建套接字阶段、连接阶段、通信阶段、断开阶段

创建套接字

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!--DNS服务器,信息流-->
...
//获取IP地址
<内存地址> = gethostbyname("www.baidu.com");
...
//1.准备,创建套接字,创建完成后协议栈返回一个描述符,用于识别不同的套接字(本方,对网络另一端透明)
<描述符> = socket(<使用IPv4>,<流模式>,...);
...
//2.连接,协议栈执行连接操作,IP和端口号是识别对方套接字的机制
connect(<描述符>,<服务器的IP地址和端口号>,...);
...

<!--协议栈,数据流-->
//3.协议栈将数据发送出去
write(<描述符>,<发送数据>,<发送数据长度>);
...

<!--Web服务器,数据流-->
//3.接收,响应信息放入接收缓冲区中
<接收数据长度> = read(<描述符>,<接收缓冲区>,...);

<!--Web服务器,信息流-->
//4.断开
close(<描述符>);
  • 每次都要连删,造成效率低下,后来人们又设计出了能够在一次连接中收发多个请求和响应的方法。在 HTTP 版本 1.1 中就可以使用这种方法,在这种情况下,当所有数据都请求完成后,浏览器会主动触发断开连接的操作
  • 注:地址解析协议,Address Resolution Protocol,ARP,根据已知IP求出MAC地址
-------------The End-------------