总体结构
或者简单的网络拓扑模型
一、浏览器生成HTTP请求消息
1、HTTP
浏览器做的第一步工作就是解析URL, 确定了Web服务器和文件名,接下来根据这些信息来生成 HTTP请求消息
1.1 HTTP协议
超文本传输协议HyperText Transfer Protocol,它是基于TCP协议的应用层传输协议,简单来说就是客户端和服务端进行数据传输的一种规则。
HTTP是一种 无状态协议,HTTP协议本身不会对发送过的请求和相应的通信状态进行持久化处理。这样做的目的是为了保持HTTP协议的简单性,从而能够快速处理大量的事务,提高效率
然而,在很多场景中,我们需要保持用户登录的状态或者记录用户购物车中的商品。由于HTTP是无状态协议,所以必须引入一些技术来记录管理状态,例如Cookie
1.2 HTTP消息
-
请求消息
格式:
请求行 + 消息头 + 空行 + 消息体
GET / HTTP/1.1 --> 请求行 Accept: */* --> 消息头
POST /login HTTP/1.1 --> 请求行 Accept: */* --> 消息头 --> 空行 { --> 消息体 "name":"whc", "password":"123" }
-
响应消息
格式:
状态行 + 消息头 + 空行 + 消息体
HTTP/1.1 200 OK --> 状态行 Content-Length: 1024 --> 消息头 Content-Type: text/html --> 空行 <html> --> 消息体 .... </html>
2、DNS
生成HTTP消息之后, 接下来委托操作系统将消息发送给Web服务器。(浏览器不具备将消息发送到网络中的功能),在进行这个操作之前,需要完成查询网址中服务器域名对应的IP地址,在委托操作系统发送消息时,必须要提供通信对象的IP地址。
2.1 TCP/IP中IP地址
TCP/IP的基本思路,如下图所示,由一些小的子网,通过路由器连接形成起来组成一个大的网络。
-
子网
可以理解为用集线器连接起来的几台计算机,我们将它看作一个单位,称为子网。
-
网络
子网通过路由器连接起来,就形成了一个网络。
-
在网络中,所有设备都会被分配一个地址,这个地址的整体称为IP地址
-
真实的IP地址: 一串32比特的数字(4个字节组成)
- IP地址: 网络地址(网络号) + 主机地址(主机号)
- 网络地址: 是IP地址的一部分,表示整个子网 (IP地址主机号全0)
- 广播地址: 向子网上所有设备发送包的一个地址 (IP地址主机号全1)
网络地址 + 主机地址 这两部分还需要附加信息即子网掩码 来决定内部结构。 其中,子网掩码为1部分表示网络号,为0部分表示主机号。 比如 IP地址: 192.168.10.40 子网掩码: 255.255.255.224 网络地址 = IP地址 & 子网掩码 = 192.168.10.32 广播地址 = 192.168.10.63 第一个主机地址: 网络地址+1 = 102.169.10.33 最后一个主机地址: 广播地址-1 = 102.169.10.62
2.2 Socket库
对于DNS服务器,我们的计算机上一定有相应的DNS客户端,这部分称为DNS解析器,简称
解析器
。根据域名查询IP地址时,浏览器会调用Socket库中的
解析器
负责执行解析操作。
-
解析器
实际上是一段程序,包含在操作系统的Socket库
-
Socket库
其中包含的程序组件可以让其它的应用程序调用操作系统的网络功能,其中解析器就是这个库其中的一种程序组件
解析器内部原理
2.3 DNS服务器
基本工作原理: 根据需要查询的域名和记录类型查找相应的记录,并向客户端返回响应消息。(DNS服务器上事先保存着对应的记录数据)
2.3.1 域名的层级关系
DNS中的域名是通过句点来分隔的,比如www.baidu.com
,句点代表了不同层次的 界限
层级关系类似一个树状结构:
- 根DNS服务器
- 顶级域名DNS服务器(.com、.org、.cn)
- 二级域名(baidu.com)
- 三级域名(www.baidu.com)
根域的DNS服务器信息保存在互联网中所有的DNS服务器中,所以,任何DNS服务器都可以找到并访问根域DNS服务器
2.3.2 域名解析工作流程
- 客户端首先访问最近的一台DNS服务器(即客户端的TCP/IP设置中填写的DNS服务器地址), 询问www.baidu.com的IP地址
本地域名服务器
收到客户端的请求后,如果缓存中存在该记录就直接返回;如果没有,本地DNS会去询问根域名服务器(.)
,根域名服务器不直接用于域名解析,返回所管理的com顶级域名服务器
的ip地址- 本地DNS服务器收到地址后,向顶级域名服务器(
.com
)发出请求 - 顶级服务器返回所管理的二级域名服务器(
baidu.com
)的ip地址 - 本地DNS服务器收到地址后,向二级域名服务器(
baidu.com
)发出请求 - 二级域名服务器查询到缓存中有该域名和ip的对应关系,然后将ip地址返回给本地DNS服务器
- 本地DNS服务器将获取的ip地址返回给客户端,并且将域名与ip对应关系保存在缓存中,以备下次别的用户查询时使用
二、协议栈处理数据以及IP、以太网的包收发操作
通过DNS获取IP地址后,就可以委托操作系统内部的协议栈向要访问的Web服务器发送消息了。
1、协议栈基本结构
应用程序(浏览器)通过调用Socket库中的程序组件委托协议栈工作。
协议栈上半部分的两块分别负责收发数据的TCP和UDP协议,它们两会接收应用层的委托执行收发数据的操作;下半部分用IP协议控制网络包收发操作,在互联网上传送数据时,数据会被切分成一块块的网络包,而将网络包发送给对方的操作就是由IP负责的。
浏览器、邮件等一般应用程序收发数据时用 TCP
DNS查询等收发较短的控制数据时用 UDP
IP中包括了ICMP
协议和ARP
协议
- ICMP: 用于告知网络包传送过程中产生的错误以及各种控制信息
- ARP: 用于提供IP地址查询相应的以太网MAC地址
网卡驱动程序: 负责控制网卡硬件
网卡: 负责完成实际的收发操作,对网线中的信号执行发送和接收操作
2、数据收发操作
数据收发操作: 在两台计算机之间连接一条数据通道(管道),数据沿着这条通道流动
-
套接字
建立管道两端的数据出入口,这些出入口称为套接字
(
协议栈是根据套接字中记录的控制信息来工作的
)协议栈内部有一块用于存放控制信息的内存空间,这里记录了用于控制通信操作的控制信息,例如通信对象的IP地址、端口号、通信操作的进行状态等,套接字只是一个概念,并不存在实体,如果要赋予它一个实体,这些控制信息就是套接字的实体,或者说存放控制信息的内存空间就是套接字的实体。
基本数据收发操作过程:
-
创建套接字
-
将管道连接到服务器端的套接字上
-
收发数据
-
断开管道并删除套接字
-
描述符
识别不同的套接字,应用程序通过描述符来识别不同连接所对应的套接字
-
IP地址和端口号
客户端和服务器之间用来识别对方套接字的机制
2.1 创建套接字
如上图①,应用程序调用socket(小写表示Socket库中的程序组件)申请创建套接字,协议栈根据应用程序的申请执行创建套接字的操作。
- 协议栈首先分配用于存放一个套接字所需的内存空间
- 往刚才创建的内存空间存入控制信息,进行初始化操作
- 将表示这个套接字的描述符告知应用程序
- 应用程序收到描述符号,向协议栈进行收发数据委托时就需要提供这个描述符了(描述符确定了套接字,协议栈能够获取所有相关信息,所以应用程序不需要每次都告诉协议栈应该和谁进行通信)
2.2 连接服务器(TCP三次握手)
如上图②,创建套接字之后,应用程序调用connect
,随后协议栈会将本地的套接字与服务器的套接字进行连接。
连接实际上是通信双方交换控制信息,在套接字中记录这些必要信息并准备数据收发的一连串操作。
-
控制信息
-
第一类是头部中记录的信息
比如TCP头部、以太网头部(MAC头部)、IP头部
-
第二类是套接字(协议栈中的内存空间)中记录的信息
应用程序传递来的信息以及从通信对象接收到的信息都会保存,以及收发数据操作的执行状态等信息
-
连接操作的实际过程(三次握手)
在HTTP传输数据之前,首先需要TCP建立连接,TCP连接的建立,通常称为
三次握手
- 一开始,客户端和服务器都处于
CLOSE
状态。先是服务端主动监听某个端口,处理LISTEN
状态 - 然后客户端主动发起连接
SYN
,之后处于SYN-SENT
状态 - 服务端收到发起的连接,返回
SYN
,并且ACK
客户端的SYN
,之后处于SYNC-RCVD
状态 - 客户端收到服务端发送的
SYN
和ACK
之后,发送ACK
的ACK
,之后处于ESTABLISHED
状态,因为它一发一收成功了 - 服务端收到
ACK
的ACK
之后,处于ESTABLISHED
状态,因为它也一发一收成功了
所以三次握手目的是保证双方都有发送和接收的能力
2.3 收发数据
数据收发操作是从应用程序调用write将要发送的数据交给协议栈开始的,如上图③,协议栈收到数据后执行发送操作。
2.3.1 客户端发送消息
- 协议栈首先会将数据存放在内部的发送缓冲区中,并等待应用程序的下一段数据
- 缓冲区填满之后,开始发送出去,数据会被以MSS长度为单位进行拆分,拆分出来的每块数据,在每块数据前面加上TCP头信息,再交给IP模块发送出去
TCP分割数据
如果HTTP请求消息比较长,超过了MSS的长度,这时TCP就需要把HTTP的数据拆解成一块块的数据发送,而不是一次性发送所有数据
- MTU(最大传输单元): 一个网络包的最大长度,以太网一般为1500字节
- MSS(最大报文长度): 除去IP和TCP头部之后,一个网络包所能容纳的TCP数据的最大长度
TCP报文生成
TCP报文 = TCP头部 + HTTP报文(HTTP头部 + 数据)
如图是TCP头部信息
2.3.2 服务端响应消息
和客户端发送数据一样,客户端接收数据也需要将数据暂存到接收缓冲区中。
-
浏览器委托协议栈发送请求之后,会调用read程序来获取
响应消息
-
read会转移到协议栈,协议栈接下来会尝从内部的接收缓冲区取出数据并传递给应用程序,这个时候可能请求消息刚发送,响应消息可能还没返回,所以接收数据的操作需要等待,等服务器返回响应消息到达后再继续执行接收操作
-
响应数据到达之后,协议栈会检查收到的数据块和TCP头部内容,判断是否有数据丢失,没有问题则返回ACK号
-
然后协议栈将数据块暂存到接收缓冲区中,并将数据块按顺序连接起来还原出原始的数据,将数据交给应用程序
-
最后协议栈会找到合适的时机向发送方发送窗口更新(如果能与ACK号等合并的话,这里会发送合并后的包)
2.4 断开管道并删除套接字
服务端的响应消息发送完毕之后,数据收发操作就结束了,这时开始就会开始执行断开操作。(HTTP1.0)
(HTTP1.1,服务器返回响应消息后,客户端还可以继续发送下一个请求消息,如果接下来没有请求要发送了,客户端一方会发起断开连接)
以Web为例,服务器会先断开过程。
- 服务器先发送一个FIN为1的TCP包,然后客户端返回一个表示确认的ACK号
- 接下来,客户端协议栈也会和服务器一样,发送一个FIN为1的TCP包,然后服务端返回一个表示确认的ACK号
- 等待一段时间后,套接字会被删除
3、生成接收方IP地址的IP头部
TCP模块在执行连接、收发、断开等各阶段操作时,都需要委托IP模块将数据封装成网络包发送给通信对象
IP模块接收TCP模块的委托负责包的收发工作,它会生成IP头部并附加在TCP头部前面。
如图为IP报文头部的格式:
- IP头部的"接收方IP地址"填写通信对象的IP地址
- 发送方IP地址需要判断发送所使用的网卡,并填写该网卡的地址
存在多个网卡时,选择哪个网卡来发送包?
答: 根据路由表
规则,来判断哪一个网卡作为源地址IP
如图所示:
假设Web服务器的目标地址是192.168.1.21
- 首先先和第一条(默认网关)目的子网掩码进行与运算,得到的结果为
0.0.0.0
,和第一条目的目标地址匹配 - 再与第二条目的子网掩码进行与运算,得到的结果为
192.0.0.0
,与127.0.0.0
不匹配 - 以此类推,直到与第六条目的子网掩码进行与运算,得到的结果为
192.168.1
,与第六条目标地址192.168.1.0
匹配
从上面可以看到,有两条符合规则,但是会选择第六条,因为路由器首先会寻找网络号比特数最长的一条记录。网络号比特数越长,说明主机号比特数越短,意味着该子网内可分配的主机数量越少,这一规则的目的是尽量缩小范围,所以根据这条记录判断的转发目标就会更加准确。
而默认网关则是在所有条目匹配不上时,就会自动匹配这一行, 并且后序就把包发给路由器,Gateway
即是路由器的IP地址
4、生成以太网用的MAC头部
生成了IP头部之后,接下来IP模块还需要在IP头部前面加上MAC头部
MAC头部
-
以太类型
- 0800:IP协议
- 0806:ARP协议
-
发送方MAC地址
网卡本身的MAC地址,MAC地址是在网卡生产时写入ROM里的,只要将这个值读取出来写入MAC头部就可以了
-
接收方MAC地址
填写对方的MAC地址,因为IP模块根据路由表Gateway栏中的IP地址就知道把包发送给谁了,但是不知道对方的MAC地址,所以需要
ARP
协议帮我们找到路由器的MAC地址
ARP协议
ARP协议在以太网中以 广播的形式,对以太网所有的设备提问“这个IP地址是谁的?请把你的MAC地址告诉我”。然后就会有人回答:“这个IP地址是我的,我的MAC地址是XXXX”。
如果对方和主机处于同一个子网中,那么通过上面的操作就可以得到对方的MAC地址。然后,我们将这个MAC地址写入MAC头部,MAC头部就完成了。
ARP缓存
每次发送包都要查询一次,网络中就会增加很多ARP包,因此我们会把查询结果放到一块ARP缓存的内存空间,ARP缓存一般只有几分钟。
5、网卡
网络包只是存放在内存中的一串二进制数字信息,没有办法直接发送给对方。因此,我们需要将
数字信息转化为电信号
,才能在网线上传输,也就是说,这才是真正的数据发送过程。负责执行这一操作的是网卡,网卡无法单独工作,需要网卡驱动程序控制网卡。
网卡结构图
-
ROM
保存着全世界唯一的MAC地址,生产时写入的;网卡中保存的MAC地址会由网卡驱动程序读取并分配给MAC模块
网卡驱动从IP模块获取包之后,会将其复制到网卡内的缓冲区中,然后向MAC模块发送发送包的命令,接着MAC模块会将包从缓冲区取出,并在开头加上报文和起始帧分界符,在末尾加上用于检测错误的FCS(帧校验序列)
-
报头和起始帧分界符
- 报头: 用来测定时机
- 起始帧分界符: 用来确定包的起始位置
-
FCS
用来检查包传输过程中是否有损坏
最后网卡会将包转化为电信号,通过网线发送出去。
转载:https://blog.csdn.net/whc__/article/details/116771672