# 浏览器访问资源

# URL

统一资源定位符(Uniform Resource Locator)

# 格式

# HTTP 协议

http://user:password@www.example.com:80/dir/file1.htm

  1. 协议
  2. 用户名、密码,可省略
  3. web 服务器域名
  4. 端口,可省略
  5. 文件路径名

# FTP 协议

ftp://user:password@ftp.example.com:21/dir/file1.htm

  1. 协议
  2. 用户名、密码,可省略
  3. FTP 服务器域名
  4. 端口,可省略
  5. 文件路径名

# 本地文件

file://localhost/c:/path/file1.zip

  1. 协议
  2. 计算机名,可省略
  3. 文件的路径名

# 电子邮件

mailto:toUser@example.com

# 新闻

news:comp.protocols.tcp-ip

# 生成 HTTP 请求消息

请求信息

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

# HTTP 响应信息

响应信息

<HTTP版本><空格><状态码><空格><响应描述>
<字段名>:<字段值>
...
...
<空行>
<消息体>

# DNS 查询服务器 IP 地址

# IP

# 表示方式

# 点分十进制

每 8 bit 用。分隔。

10.11.12.13

# 子网掩码

10.11.12.13/255.255.255.0

# 比特数的子网掩码

10.11.12.13/24

前 24 位全为 1,剩余为 0,表示主机数。

  1. IP 可以得出网络号
  2. 除了网络号,剩余的位数,继续用子网掩码划分
  3. 子网掩码 + 网络号,得出子网号,剩余的才是这个子网的主机号。

# 代表整个子网

10.11.12.0/24

# 子网内广播

10.11.12.255/24

# DNS 解析

DNS(Domain Name System)查询 IP 地址的操作,称为域名解析,负责执行此操作的为解析器。

# 查询条件

  1. 域名
  2. Class:目前只固定 IN
  3. 记录类型:A - 地址;MX - Mail eXchange
域名                   Class 记录类型 响应数据
www.lab.glasscom.com  IN     A      192.0.2.226
glasscom.com          IN     MX     10 mail.glasscom.com
mail.glasscom.com     IN     A      192.0.2.227

邮箱还有一个优先级

# 域名分层

使用英文句点来划分,靠右层级越高。

例如: www.lab.glasscom.com

  • 一级域名:com
  • 二级域名:glasscom
  • 三级、四级:lab、www

# 根域服务器

它没有名字,如果要表示,就在域名最右边添加句点,例如:

www.lab.glasscom.com.

全球目前只有 13 台 根域服务器,这些都配置在主机中的。

当然还有成千上万台镜像 DNS 服务器,会定时更新根域服务器的数据。

# 查找过程

www.lab.glasscom.com. 域名的查找过程

  1. 从主机配置的 DNS 服务器查找;配置是系统 TCP/IP 自动配置好的,或者手动配置。
  2. 查找不到了,再从最高级别查起,即根域或其镜像 DNS 服务器查找
  3. 没有再从 com 的 DNS 服务器查找
  4. 然后一级一级的查询,直到查询或到达最低级域名 DNS 为止。

当然,DNS 服务器可能包含多级的域名注册信息,因此不用查询多次。以及 DNS 服务器有缓存

低级的域名都会注册到高级的域名服务器中。

例如:一级域名 com、cn 等的域名都注册到根域服务器中。

# DNS 使用 TCP 还是 UDP?

两者都使用:

  1. 在局域网中使用 UDP
  2. 在跨越较远的根服务器、一级等,用 TCP

# 委托协议栈发送信息

得到对方的 IP 后,就可以委托系统的 Socket 库来收发数据。

Socket 建立两者之间的通道,数据在通道中流动。

流程:

  1. 双方创建套接字(创建阶段)
  2. 客户端连接服务器的套接字上(连接阶段)
  3. 收发数据(通信阶段)
  4. 断开管道并删除套接字(断开阶段)

应用程序

// DNS
<内存地址> = gethostbyname("www.lab.glasscom.com");
// 创建阶段
<描述符> = socket(<IPv4>, <流模式>, ...);
// 连接阶段
connect(<描述符>, <服务器的 IP 地址和端口>, ...);
// 通信阶段
write(<描述符>, <发送数据>, <数据长度>);
<接收数据长度> = read(<描述符>, <接收缓冲区>, ...);
// 断开阶段
close(<描述符>);

# Socket、socket、套接字区别:

  • Socket 代表库,包含多种组件
  • socket 指的是创建套接字的 socket 程序组件
  • 套接字:指的是双方创建的通道

# 创建阶段

使用 socket 组件,创建套接字,协议栈会返回描述符号。

描述符储存在内存中,就类似一个 ID,用于区分是哪个套接字。

# 连接阶段

使用 connect 组件;需要指定描述符、服务器 IP 地址、端口号。

IP 能识别到某台主机,但不知道对方的哪个套接字,因此需要端口号。

端口号能识别到对方的某个套接字

因此连接阶段,通过 IP 和端口号,能连接到对方主机的套接字,完成套接字的连接,形成通道。

# 为什么不使用套接字的描述符代表端口呢?

因为描述符代表的是本机的套接字,是本机识别本机的套接字的;而对方的套接字无法知道。

因此,使用双方约定好的端口号,作为对方的套接字的识别。

# 通信阶段:传递消息

通过 write 和 read 来读写消息,实现传递消息。

例如,HTTP,生成 HTTP 请求报文,然后调用 write 写入通道中,服务器通过 read 读取通道的数据。

# 断开阶段

使用 close 组件,断开和删除套接字,通道关闭。

HTTP 协议规定,web 服务器发送完响应消息后,先断开;然后浏览器知道断开后,也会调用 close 断开。

不同协议,客户端和服务器端哪一方先执行 close 都有可能。