Net
Net简介
2.1 TCP/IP网络模型
前言:为什么要有TCP/IP网络模型?
答:为了提供一套 通用的 网络协议
因为在一台设备上的进程间通信有很多方式,比如管道、消息队列、共享内存、信号等方式,而对于不同的设备上的进程间通信,就需要网络通信,而设备是多样性的,需要兼容多种多样的设备,就需要一套 通用的网络协议
这个网络协议是分层的,每一层都有各自的作用和责任
TCP/IP网络模型分为4层:应用层-->传输层-->网络层-->网络接口层(由上到下)
接下来根据 [TCP/IP 网络模型 ]分别对每一层进行介绍:
应用层(最上层)
最上层的,也是我们能直接接触到的就是应用层(Application Layer),我们使用的应用软件都是在应用层实现的,当两台不同的设备的应用需要通信的时候,应用就把应用数据传给下一层,也就是传输层。
应用层接收数据后把数据传入传输层
所以,应用层只需要专注于为用户提供应用功能,比如HTTP、FTP、Telnet、DNS、SMTP等
应用层不用关心数据是如何传输
应用层是工作在操作系统的用户态,传输层****及其一下则工作在内核态
传输层
应用层的数据包会传输到传输层,传输层(Transport Layer) 是为应用层提供网络支持
在传输层会有两个传输协议,分别为TCP
和UDP
TCP的全称是“传输控制协议”(Transmission Control Protocol),大部分应用使用的正是TCP传输层协议,比如HTTP应用层协议。
TCP有很多特征:流量控制、超时重传、拥塞控制等,这些保证了数据包能可靠地传输给对方
UDP相对来说比较协议,简单到只负责发送数据包,不保证数据包是否能抵达对方,但是实时性相对更好,传输效率也高。
UDP也可以实现可靠传输,把TCP的特性在应用层上实现就行,(不过要实现一个商用的可靠UDP传输协议也不简单)
应用需要传输的数据可能会非常大,如果直接传输就不好控制,因此当传输层的数据包大小超过MSS(TCP最大报文段长度),就要将数据包分块,这样即使在传输过程中一个分块缺失或者损坏了,只需要重新发送这一分开,而不用重新发送整个数据包。
在TCP协议中,每一个分块称为一个TCP段(TCP Segment)
当设备作为接收方时,传输层则要负责把数据包传给应用层,但是一台设备上可能会有很多应用在接收或者传输数据,因此需要一个编号将应用区分开来,这个编号就是端口
比如 80 端口通常是 Web 服务器用的,22 端口通常是远程登录服务器用的。而对于浏览器(客户端)中的每个标签栏都是一个独立的进程,操作系统会为这些进程分配临时的端口号。
由于传输层的报文中会携带端口号,因此接收方可以识别出该报文是发送给哪个应用。
传输层并不负责将数据从一个设备传输到另一个设备
网络层
在实际场景中,一个设备的数据要传输给另一个设备,就需要在各种各样的路径和节点进行选择,其中的网络环节是错综复杂的。而传输层的设计理念是简单、高效、专注,如果传输层还负责这一块功能就有点违背设计原则
我们不希望传输层协议处理太多的事情,只需要服务好应用即可,让其作为应用间数据传输的媒介,帮助实现应用到应用的通信,而实际的传输功能就交给下一层,也就是网络层(Internet Layer)
个人理解:应用层把大量的数据发送给传输层,传输层将这些大量的数据进行打包,分段,确定好目的应用,然后由网络层进行传输。
网络层最常用的是IP协议(Internet Protocol),IP协议会将传输层的报文作为数据部分,再加上IP包头组装成IP报文,如果IP报文大小超过了MTU(以太网中一般为1500字节)就会再次进行分片,得到一个继续发送网络的IP报文
网络层负责将数据从一个设备传输到另一个设备,但是世界上那么多设备,如何找到对方呢,因此,网络层需要有区分设备的编号
一般用IP地址给设备进行编号,对于IPv4协议,IP地址共32位,分成了四段(比如127.0.0.1,分成四段,每段8位)。但是寻址起来特别麻烦,不能一个一个去匹配。
因此,需要将IP地址分成两种意义:
一个是网络号,负责标识该IP地址是属于那个[ 子网 ]的
一个是主机号,负责标识同一[ 子网 ]下的不同主机
怎么区分网络号和主机号呢?这需要配合子网掩码才能算出IP地址的网络号和主机号
举个例子,比如 10.100.122.0/24,后面的/24
表示就是 255.255.255.0
子网掩码,255.255.255.0 二进制是「11111111-11111111-11111111-00000000」,大家数数一共多少个1?不用数了,是 24 个1,为了简化子网掩码的表示,用/24代替255.255.255.0。
知道了子网掩码,该怎么计算出网络地址和主机地址呢?
将 10.100.122.2 和 255.255.255.0 进行按位与运算,就可以得到网络号,如下图:
将 255.255.255.0 取反后与IP地址进行进行按位与运算,就可以得到主机号
~255.255.255.0 = 0.0.0.255
除了寻找能力,IP协议还有另一个重要的能力是路由。实际场景中,两台设备并不是用一条网线连接,而是通过很多网关、路由器、交换机等众多网络设备连接起来的。那么就会形成很多条网络的路径,因此当数据包到达一个网络节点,就需要通过路由算法决定下一步哪条路径
路由器寻找工作中,就需要目标地址的子网,找到后进而把数据包发送到对应的网络内
所以,IP 协议的寻址作用是告诉我们去往下一个目的地该朝哪个方向走,路由则是根据「下一个目的地」选择路径。寻址更像在导航,路由更像在操作方向盘
网络接口层
生成IP头部后,接下来就是网络接口层(Link Layer)在IP头部的前面加上MAC头部,并封装成数据帧(Data frame)发送到网络上
IP 头部中的接收方 IP 地址表示网络包的目的地,通过这个地址我们就可以判断要将包发到哪里,但在以太网的世界中,这个思路是行不通的。
什么是以太网呢?电脑上的以太网接口,Wi-Fi接口,以太网交换机、路由器上的千兆,万兆以太网口,还有网线,它们都是以太网的组成部分。以太网就是一种在「局域网」内,把附近的设备连接起来,使它们之间可以进行通讯的技术。
以太网在判断网络包目的地时和 IP 的方式不同,因此必须采用相匹配的方式才能在以太网中将包发往目的地,而 MAC 头部就是干这个用的,所以,在以太网进行通讯要用到 MAC 地址。
MAC 头部是以太网使用的头部,它包含了接收方和发送方的 MAC 地址等信息,我们可以通过 ARP 协议获取对方的 MAC 地址。
所以说,网络接口层主要为网络层提供「链路级别」传输的服务,负责在以太网、WiFi 这样的底层网络上发送原始数据包,工作在网卡这个层次,使用 MAC 地址来标识网络上的设备。
总结
综上所述,TCP/IP 网络通常是由上到下分成 4 层,分别是应用层,传输层,网络层和网络接口层。
网络接口层的传输单位是帧(frame),IP 层的传输单位是包(packet),TCP 层的传输单位是段(segment),HTTP 的传输单位则是消息或报文(message)。但这些名词并没有什么本质的区分,可以统称为数据包。
当键入网址后,到网页显示,期间发生了什么?
HTTP
浏览器做的第一步工作是解析****URL
首先浏览器做的第一步工作就是要对URL
进行解析,从而生成发生给Web
服务器的请求信息
在一条长长的URL里的各个元素的代表是什么
这里的URL实际上是请求服务器里的文件资源
当上图的蓝色部分URL元素都省略了,那么请求的是哪个文件呢?
当没有路径名时,就代表访问根目录下事先设置的默认文件,也就是/index.html
或者/default.html
这些文件,这样就不好发生混乱
生产HTTP请求信息
对URL
进行解析之后,浏览器确定了Web服务器和文件名,接下来就是根据这些信息来生产HTTP请求信息
真实地址查询——DNS
通过浏览器解析URL并生成HTTP消息后,需要委托操作系统将消息发送给Web
服务器
但是在发送之前,还需要查询服务器域名对应的IP地址,因为委托操作系统发送消息时,必须提供通信对象的IP地址
这里,有一种服务器就专门保存了Web
服务器域名与IP
的对应关系——DNS服务器
域名的层级关系
DNS中的域名都是用句点来分隔的,比如www.server.com
,这里的句点带不了不同层次之间的界限
在域名中,越靠右的位置表示其层级越高
实际上域名最后还有一个点,比如www``.server.com.
,这个最后一个点代表根域名
也就是说,.
根域是最顶层,它的下一层是.com
顶级域,再下面是server.com
所以,域名的层级关系类似一个树状结构
根DNS服务器
.
顶级域DNS服务器
.com
权威DNS服务器
server.com
根域的DNS服务器信息保存在互联网中所有的DNS服务器中,这样一来任何DNS服务器都可以找到并访问根域DNS服务器
因此,客户端只要能够找到任意一台 DNS 服务器,就可以通过它找到根域 DNS 服务器,然后再一路顺藤摸瓜找到位于下层的某台目标 DNS 服务器。
域名解析的工作流程
客户端首先会发出一个DNS请求,问www.server.com的IP是啥,并发给本地DNS服务器(也就是客户端的TCP/IP设置中填写的DNS服务器地址)
本地域名服务器收到客户端的请求后,如果缓存里的表格能找到www.server.com,则直接返回IP地址,如果没有,本地DNS会去问它的根域名服务器, 根域名服务器是最高层次的,它不直接用于域名解析,但能指明一条道路。
根DNS收到本地DNS的请求后,根据www.server.com的后置是
.com
,这个域名归于.com
区域管理,返回.com
顶级域名服务器地址给本地本地DNS收到顶级域名服务器地址后,向顶级域名服务器请求负责www.server.com的权威DNS服务器的地址,
本地DNS最后向权威DNS服务器请求www.server.com的IP地址,该server.com的权威服务器就是域名解析结果的出处。
权威DNS服务器查询结后将对应的IP地址X.X.X.X返回到本地DNS
本地DNS再将IP地址返回客户端,客户端和目标建立连接
至此,DNS的解析过程完成了,其过程可见下图
域名解析并不是每次都需要经过这么多步骤
还有缓存的存在。
浏览器会先看自身有没有对这个域名的缓存,如果有,就直接返回,如果没有,就去问操作系统,操作系统也会去看自己的缓存,如果有,就直接返回,如果没有,再去 hosts 文件看,也没有,才会去问「本地 DNS 服务器」。
协议栈
通过DNS获取IP后,就可以把HTTP的传输工具交给操作系统中的协议栈
协议栈的内部分为几个部分,分别承担不同的工作。上下关系是有一定的规则的,上面的部分会向下面的部分委托工作,下面的部分收到委托的工作并执行。
应用程序(浏览器)通过调用 Socket 库,来委托协议栈工作。协议栈的上半部分有两块,分别是负责收发数据的 TCP 和 UDP 协议,这两个传输协议会接受应用层的委托执行收发数据的操作。
协议栈的下面一半是用 IP 协议控制网络包收发操作,在互联网上传数据时,数据会被切分成一块块的网络包,而将网络包发送给对方的操作就是由 IP 负责的。
此外 IP 中还包括 ICMP
协议和 ARP
协议。
ICMP
用于告知网络包传送过程中产生的错误以及各种控制信息。ARP
用于根据 IP 地址查询相应的以太网 MAC 地址。
IP 下面的网卡驱动程序负责控制网卡硬件,而最下面的网卡则负责完成实际的收发操作,也就是对网线中的信号执行发送和接收操作。
可靠传输——TCP
HTTP是基于TCP协议传输的,
TCP包头格式
TCP 报文头部的格式:
首先,源端口号和目标端口号是必不可少的,如果没有这两个端口号,数据不知道发送给哪些应用
接下来有包的序号,这个是为了解决包乱序的问题
还有确认号,目的是确认发出去对方是否有收到。如果没有收到就重新发送直到送达,这是是为了解决丢包问题
还有一些状态位。例如 SYN
是发起一个连接,ACK
是回复,RST
是重新连接,FIN
是结束连接等。TCP 是面向连接的,因而双方要维护连接的状态,这些带状态位的包的发送,会引起双方的状态变更。
还有一个重要的就是窗口大小。TCP要做流量控制,通信双方各声明一个窗口(缓存大小),标识自己当前能够提供的处理能力,以控制流量发送的快慢
除了流量控制以外,TCP还做了拥塞控制,能够控制数据发送的速度
TCP传输数据之前,要先三次握手建立连接
在HTTP传输数据之前,首先需要TCP建立连接,TCP连接的建立,通常称为三次握手
这个所谓的「连接」,只是双方计算机里维护一个状态机,在连接建立的过程中,双方的状态变化时序图就像这样。
一开始,客户端和服务端都处于
CLOSED
状态。先是服务端主动监听某个端口,处于LISTEN
状态。然后客户端主动发起连接
SYN
,之后处于SYN-SENT
状态。服务端收到发起的连接,返回
SYN
,并且ACK
客户端的SYN
,之后处于SYN-RCVD
状态。客户端收到服务端发送的
SYN
和ACK
之后,发送对SYN
确认的ACK
,之后处于ESTABLISHED
状态,因为它一发一收成功了。服务端收到
ACK
的ACK
之后,处于ESTABLISHED
状态,因为它也一发一收了。
所以三次握手目的是保证双方都有发送和接收的能力。
如何查看TCP的连接状态
TCP 的连接状态查看,在 Linux 可以通过 netstat -napt
命令查看。
TCP分割数据
如果 HTTP 请求消息比较长,超过了 MSS
的长度,这时 TCP 就需要把 HTTP 的数据拆解成一块块的数据发送,而不是一次性发送所有数据。
MTU
:一个网络包的最大长度,以太网中一般为1500
字节。MSS
:除去 IP 和 TCP 头部之后,一个网络包所能容纳的 TCP 数据的最大长度。
数据会被以 MSS
的长度为单位进行拆分,拆分出来的每一块数据都会被放进单独的网络包中。也就是在每个被拆分的数据加上 TCP 头信息,然后交给 IP 模块来发送数据。
TCP报文生成
TCP协议里面会有两个端口,一个是浏览器监听的端口(通常为随机生成),一个是Web服务器监听的端口(HTTP默认是80
,HTTPS默认是443
)
双方建立连接后,TCP报文中的数据部分就是存放了HTTP头部+数据,组装好TCP报文之后,就需要交给下面的网络层处理
至此,网络包的报文如下图。
远程定位——IP
TCP模块在执行连接、收发、断开等阶段操作时,都需要委托IP模块将数据封装成网络包发送给通信对象
IP包头格式
在IP协议中,需要有源地址IP和目标地址IP:
源地址IP:客户端输出的IP地址
目标地址:通过DNS域名解析得到的Web服务器IP
因为HTTP是经过TCP传输的,所有在IP包头的协议号,要填写06
(十六进制),表示协议为TCP协议
假设客户端有多个网卡,就会有多个IP地址,那么IP头部的源地址应该选择哪个地址?
这个判断相当于在多块网卡中,判断应该使用哪个网卡来发送包
这时候就需要根据路由表规则,来判断哪一个网卡作为源地址IP
在 Linux 操作系统,我们可以使用 route -n
命令查看当前系统的路由表。
举个例子,根据上面的路由表,我们假设 Web 服务器的目标地址是 192.168.10.200
。
首先先和第一条目的子网掩码(
Genmask
)进行 与运算,得到结果为192.168.10.0
,但是第一个条目的Destination
是192.168.3.0
,两者不一致所以匹配失败。再与第二条目的子网掩码进行 与运算,得到的结果为
192.168.10.0
,与第二条目的Destination 192.168.10.0
匹配成功,所以将使用eth1
网卡的 IP 地址作为 IP 包头的源地址。
那么假设 Web 服务器的目标地址是 10.100.20.100
,那么依然依照上面的路由表规则判断,判断后的结果是和第三条目匹配。
第三条目比较特殊,它目标地址和子网掩码都是 0.0.0.0
,这表示默认网关,如果其他所有条目都无法匹配,就会自动匹配这一行。并且后续就把包发给路由器,Gateway
即是路由器的 IP 地址。
IP报文生成
两点传输——MAC
生成了IP头部之后,接下来网络包还需要在IP头部的前面加上MAC头部
MAC包头格式
在MAC包头里需要发送方的MAC地址和接收方目标MAC地址,用于两点之间的传输
一般在TCP/IP通信里,MAC包头的协议类型只使用:
0800
:IP协议0806
:ARP协议
MAC发送方和接收方如何确认?
发送方的MAC地址获取简单,MAC地址在网卡生产时写入到ROM里面,只要将这个值读取出来写入到MAC头部就行
接收方的MAC地址就有点复杂,只要告诉以太网对方的MAC地址,以太网就会把包发送过去,那么对方的MAC地址哪里来呢?
这是得先清楚应该把包发给谁,需要查询一下路由表,在路由表中找到匹配的条目,然后把包发送给Gateway
列中的IP地址
如何获取对方的MAC地址?
这里需要ARP
协议帮我们找到路由器的MAC地址
ARP协议会在以太网中以广播的形式,对以太网所有的设备进行广播,如果对方和自己处在同一张子网中,那么上面操作就可可以得到对方的MAC地址,那么将这个MAC地址写入MAC头部后,MAC头部就完成了
ARP缓存
在得到对方的MAC地址后,操作系统会将本次的查询结果放到一块ARP缓存的内存空间,不过缓存保存的时间就几分钟
也就是说,在发包时:
先查询 ARP 缓存,如果其中已经保存了对方的 MAC 地址,就不需要发送 ARP 查询,直接使用 ARP 缓存中的地址。
而当 ARP 缓存中不存在对方 MAC 地址时,则发送 ARP 广播查询。
查看 ARP 缓存内容
在 Linux 系统中,我们可以使用 arp -a
命令来查看 ARP 缓存的内容。
MAC 报文生成
至此,网络包的报文如下图。
出口——网卡
网络包只是存放在内存中的一串二进制数字信息,没有办法直接发送给对方。因此,我们需要将数字信息转换为电信号,才能在网线上传输,也就是说,这才是真正的数据发送过程。
负责执行这一操作的是网卡,要控制网卡还需要靠网卡驱动程序。
网卡驱动获取网络包之后,会将其复制到网卡内的缓存区中,接着会在其开头加上报头和起始帧分界符,在末尾加上用于检测错误的帧校验序列。
起始帧分界符是一个用来表示包起始位置的标记
末尾的
FCS
(帧校验序列)用来检查包传输过程是否有损坏
最后网卡会将包转为电信号,通过网线发送出去。
交换机
下面来看一下包是如何通过交换机的。交换机的设计是将网络包原样转发到目的地。交换机工作在 MAC 层,也称为二层网络设备。
交换机的包接收操作
……
服务器 与 客户端
数据包抵达服务器后,服务器会先扒开数据包的 MAC 头部,查看是否和服务器自己的 MAC 地址符合,符合就将包收起来。
接着继续扒开数据包的 IP 头,发现 IP 地址符合,根据 IP 头中协议项,知道自己上层是 TCP 协议。
于是,扒开 TCP 的头,里面有序列号,需要看一看这个序列包是不是我想要的,如果是就放入缓存中然后返回一个 ACK,如果不是就丢弃。TCP头部里面还有端口号, HTTP 的服务器正在监听这个端口号。
于是,服务器自然就知道是 HTTP 进程想要这个包,于是就将包发给 HTTP 进程。
服务器的 HTTP 进程看到,原来这个请求是要访问一个页面,于是就把这个网页封装在 HTTP 响应报文里。
HTTP 响应报文也需要穿上 TCP、IP、MAC 头部,不过这次是源地址是服务器 IP 地址,目的地址是客户端 IP 地址。
接下来将从以下6个方面,逐渐学习和了解HTTP
- HTTP基本概念
- Get与Post
- HTTP特征
- HTTP缓存
- HTTPS与HTTP
- HTTP/1.1、HTTP/2、HTTP/3演变
HTTP基本概念
1.HTTP是什么?
HTTP是超文本传输协议,也就是HyperText Transfer Protocol
HTTP的名字【超文本传输协议】,可以拆成三个部分:
超文本
传输
协议
针对 HTTP 协议,我们可以这么理解。
- 「协议」
HTTP 是一个用在计算机世界里的协议。它使用计算机能够理解的语言确立了一种计算机之间交流通信的规范(两个以上的参与者),以及相关的各种控制和错误处理方式(行为约定和规范)。
- 「传输」
HTTP 协议是一个双向协议。
针对传输,我们可以进一步理解了 HTTP。
HTTP 是一个在计算机世界里专门用来在两点之间传输数据的约定和规范。
- 「超文本」
HTTP 传输的内容是「超文本」。
理解「超文本」,它就是超越了普通文本的文本,它是文字、图片、视频等的混合体,最关键有超链接,能从一个超文本跳转到另外一个超文本。
HTTP 是一个在计算机世界里专门在「两点」之间「传输」文字、图片、音频、视频等「超文本」数据的「约定和规范」。
HTTP是用于从互联网服务器传输超文本到本地浏览器的协议,这个说法是错误的,因为HTTP也可以服务于【服务器<--->服务器】,所有采用两点之间的描述比较准确
2.HTTP常见的状态码
1xx
类状态码属于提示信息,是协议处理中的一种中间状态,实际用到的比较少。
2xx
类状态码表示服务器成功处理了客户端的请求,也是我们最愿意看到的状态。
「200 OK」是最常见的成功状态码,表示一切正常。如果是非
HEAD
请求,服务器返回的响应头都会有 body 数据。「204 No Content」也是常见的成功状态码,与 200 OK 基本相同,但响应头没有 body 数据。
「206 Partial Content」是应用于 HTTP 分块下载或断点续传,表示响应返回的 body 数据并不是资源的全部,而是其中的一部分,也是服务器处理成功的状态。
3xx
类状态码表示客户端请求的资源发生了变动,需要客户端用新的 URL 重新发送请求获取资源,也就是重定向。
「301 Moved Permanently」表示永久重定向,说明请求的资源已经不存在了,需改用新的 URL 再次访问。
「302 Found」表示临时重定向,说明请求的资源还在,但暂时需要用另一个 URL 来访问。
301 和 302 都会在响应头里使用字段 Location
,指明后续要跳转的 URL,浏览器会自动重定向新的 URL。
- 「304 Not Modified」不具有跳转的含义,表示资源未修改,重定向已存在的缓冲文件,也称缓存重定向,也就是告诉客户端可以继续使用缓存资源,用于缓存控制。
4xx
类状态码表示客户端发送的报文有误,服务器无法处理,也就是错误码的含义。
「400 Bad Request」表示客户端请求的报文有错误,但只是个笼统的错误。
「403 Forbidden」表示服务器禁止访问资源,并不是客户端的请求出错。
「404 Not Found」表示请求的资源在服务器上不存在或未找到,所以无法提供给客户端。
5xx
类状态码表示客户端请求报文正确,但是服务器处理时内部发生了错误,属于服务器端的错误码。
「500 Internal Server Error」与 400 类型,是个笼统通用的错误码,服务器发生了什么错误,我们并不知道。
「501 Not Implemented」表示客户端请求的功能还不支持,类似“即将开业,敬请期待”的意思。
「502 Bad Gateway」通常是服务器作为网关或代理时返回的错误码,表示服务器自身工作正常,访问后端服务器发生了错误。
「503 Service Unavailable」表示服务器当前很忙,暂时无法响应客户端,类似“网络服务正忙,请稍后重试”的意思。