Decorative image frame

一篇文章带你熟悉TCP-IP协议(网络协议篇一).md

本篇文章篇幅比较长,先来个思维导图预览一下。

一张图带你看完本篇文章

一、概述

1.计算机网络体系结构分层

计算机网络体系结构分层

2.TCP/IP 通信传输流

利用 TCP/IP 协议族进行网络通信时,会通过分层顺序与对方进行通信。发送端从应用层往下走,接收端则从链路层往上走。如下:

TCP/IP 通信传输流

  • 首先作为发送端的客户端在应用层(HTTP 协议)发出一个想看某个 Web 页面的 HTTP 请求。
  • 接着,为了传输方便,在传输层(TCP 协议)把从应用层处收到的数据(HTTP 请求报文)进行分割,并在各个报文上打上标记序号及端口号后转发给网络层。
  • 在网络层(IP 协议),增加作为通信目的地的 MAC 地址后转发给链路层。这样一来,发往网络的通信请求就准备齐全了。
  • 接收端的服务器在链路层接收到数据,按序往上层发送,一直到应用层。当传输到应用层,才能算真正接收到由客户端发送过来的 HTTP请求。
    如下图所示:

HTTP 请求
在网络体系结构中,包含了众多的网络协议,这篇文章主要围绕 HTTP 协议(HTTP/1.1版本)展开。

HTTP协议(HyperText Transfer Protocol,超文本传输协议)是用于从WWW服务器传输超文本到本地浏览器的传输协议。它可以使浏览器更加高效,使网络传输减少。它不仅保证计算机正确快速地传输超文本文档,还确定传输文档中的哪一部分,以及哪部分内容首先显示(如文本先于图形)等。
HTTP是客户端浏览器或其他程序与Web服务器之间的应用层通信协议。在Internet上的Web服务器上存放的都是超文本信息,客户机需要通过HTTP协议传输所要访问的超文本信息。HTTP包含命令和传输信息,不仅可用于Web访问,也可以用于其他因特网/内联网应用系统之间的通信,从而实现各类应用资源超媒体访问的集成。
我们在浏览器的地址栏里输入的网站地址叫做URL (Uniform Resource Locator,统一资源定位符)。就像每家每户都有一个门牌地址一样,每个网页也都有一个Internet地址。当你在浏览器的地址框中输入一个URL或是单击一个超级链接时,URL就确定了要浏览的地址。浏览器通过超文本传输协议(HTTP),将Web服务器上站点的网页代码提取出来,并翻译成漂亮的网页。

二、HTTP 工作过程

HTTP请求响应模型 HTTP通信机制是在一次完整的 HTTP 通信过程中,客户端与服务器之间将完成下列7个步骤:

1.建立 TCP 连接

在HTTP工作开始之前,客户端首先要通过网络与服务器建立连接,该连接是通过 TCP 来完成的,该协议与 IP 协议共同构建 Internet,即著名的 TCP/IP 协议族,因此 Internet 又被称作是 TCP/IP 网络。HTTP 是比 TCP 更高层次的应用层协议,根据规则,只有低层协议建立之后,才能进行高层协议的连接,因此,首先要建立 TCP 连接,一般 TCP 连接的端口号是80;

2.客户端向服务器发送请求命令

一旦建立了TCP连接,客户端就会向服务器发送请求命令;
例如:GET/sample/hello.jsp HTTP/1.1

3.客户端发送请求头信息

客户端发送其请求命令之后,还要以头信息的形式向服务器发送一些别的信息,之后客户端发送了一空白行来通知服务器,它已经结束了该头信息的发送;
服务器应答
客户端向服务器发出请求后,服务器会客户端返回响应;
例如: HTTP/1.1 200 OK
响应的第一部分是协议的版本号和响应状态码

5.服务器返回响应头信息

正如客户端会随同请求发送关于自身的信息一样,服务器也会随同响应向用户发送关于它自己的数据及被请求的文档;

6.服务器向客户端发送数据

服务器向客户端发送头信息后,它会发送一个空白行来表示头信息的发送到此为结束,接着,它就以 Content-Type 响应头信息所描述的格式发送用户所请求的实际数据;

7.服务器关闭 TCP 连接

一般情况下,一旦服务器向客户端返回了请求数据,它就要关闭 TCP 连接,然后如果客户端或者服务器在其头信息加入了这行代码 Connection:keep-alive ,TCP 连接在发送后将仍然保持打开状态,于是,客户端可以继续通过相同的连接发送请求。保持连接节省了为每个请求建立新连接所需的时间,还节约了网络带宽。

三、HTTP 协议基础

1.通过请求和响应的交换达成通信

应用 HTTP 协议时,必定是一端担任客户端角色,另一端担任服务器端角色。仅从一条通信线路来说,服务器端和客服端的角色是确定的。HTTP 协议规定,请求从客户端发出,最后服务器端响应该请求并返回。换句话说,肯定是先从客户端开始建立通信的,服务器端在没有接收到请求之前不会发送响应。

2.HTTP 是不保存状态的协议

HTTP 是一种无状态协议。协议自身不对请求和响应之间的通信状态进行保存。也就是说在 HTTP 这个级别,协议对于发送过的请求或响应都不做持久化处理。这是为了更快地处理大量事务,确保协议的可伸缩性,而特意把 HTTP 协议设计成如此简单的。
可是随着 Web 的不断发展,我们的很多业务都需要对通信状态进行保存。于是我们引入了 Cookie 技术。有了 Cookie 再用 HTTP 协议通信,就可以管理状态了。

Cookie 技术通过在请求和响应报文中写入 Cookie 信息来控制客户端的状态。Cookie 会根据从服务器端发送的响应报文内的一个叫做 Set-Cookie 的首部字段信息,通知客户端保存Cookie。当下次客户端再往该服务器发送请求时,客户端会自动在请求报文中加入 Cookie 值后发送出去。服务器端发现客户端发送过来的 Cookie 后,会去检查究竟是从哪一个客户端发来的连接请求,然后对比服务器上的记录,最后得到之前的状态信息。

Cookie 的流程

4.请求 URI 定位资源

HTTP 协议使用 URI 定位互联网上的资源。正是因为 URI 的特定功能,在互联网上任意位置的资源都能访问到。

5.告知服务器意图的 HTTP 方法(HTTP/1.1)

HTTP 方法

6.持久连接

HTTP 协议的初始版本中,每进行一个 HTTP 通信都要断开一次 TCP 连接。比如使用浏览器浏览一个包含多张图片的 HTML 页面时,在发送请求访问 HTML 页面资源的同时,也会请求该 HTML 页面里包含的其他资源。因此,每次的请求都会造成无畏的 TCP 连接建立和断开,增加通信量的开销。
为了解决上述 TCP 连接的问题,HTTP/1.1 和部分 HTTP/1.0 想出了持久连接的方法。其特点是,只要任意一端没有明确提出断开连接,则保持 TCP 连接状态。旨在建立一次 TCP 连接后进行多次请求和响应的交互。在 HTTP/1.1 中,所有的连接默认都是持久连接。

7.管线化

持久连接使得多数请求以管线化方式发送成为可能。以前发送请求后需等待并接收到响应,才能发送下一个请求。管线化技术出现后,不用等待亦可发送下一个请求。这样就能做到同时并行发送多个请求,而不需要一个接一个地等待响应了。
比如,当请求一个包含多张图片的 HTML 页面时,与挨个连接相比,用持久连接可以让请求更快结束。而管线化技术要比持久连接速度更快。请求数越多,时间差就越明显。

四、HTTP 协议报文结构

1.HTTP 报文

用于 HTTP 协议交互的信息被称为 HTTP 报文。请求端(客户端)的 HTTP 报文叫做请求报文;响应端(服务器端)的叫做响应报文。HTTP 报文本身是由多行(用 CR+LF 作换行符)数据构成的字符串文本。

2.HTTP 报文结构

HTTP 报文大致可分为报文首部和报文主体两部分。两者由最初出现的空行(CR+LF)来划分。通常,并不一定有报文主体。如下:

HTTP 报文结构

2.1请求报文结构

请求报文结构 请求报文的首部内容由以下数据组成:

请求行 —— 包含用于请求的方法、请求 URI 和 HTTP 版本。
首部字段 —— 包含表示请求的各种条件和属性的各类首部。(通用首部、请求首部、实体首部以及RFC里未定义的首部如 Cookie 等)
请求报文的示例,如下:

请求报文示例

2.2响应报文结构

响应报文结构 响应报文的首部内容由以下数据组成:

状态行 —— 包含表明响应结果的状态码、原因短语和 HTTP 版本。
首部字段 —— 包含表示请求的各种条件和属性的各类首部。(通用首部、响应首部、实体首部以及RFC里未定义的首部如 Cookie 等)
响应报文的示例,如下:

响应报文示例

五、HTTP 报文首部之请求行、状态行

1.请求行

举个栗子,下面是一个 HTTP 请求的报文:

GET /index.htm HTTP/1.1
Host: sample.com

其中,下面的这行就是请求行,

GET /index.htm HTTP/1.1

  • 开头的 GET 表示请求访问服务器的类型,称为方法;
  • 随后的字符串 /index.htm 指明了请求访问的资源对象,也叫做请求 URI;
  • 最后的 HTTP/1.1,即 HTTP 的版本号,用来提示客户端使用的 HTTP 协议功能。

综合来看,大意是请求访问某台 HTTP 服务器上的 /index.htm 页面资源。

2.状态行

同样举个栗子,下面是一个 HTTP 响应的报文:

HTTP/1.1 200 OK
Date: Mon, 10 Jul 2017 15:50:06 GMT
Content-Length: 256
Content-Type: text/html

...

其中,下面的这行就是状态行,

HTTP/1.1 200 OK

  • 开头的 HTTP/1.1 表示服务器对应的 HTTP 版本;
  • 紧挨着的 200 OK 表示请求的处理结果的状态码和原因短语。

    六、HTTP 报文首部之首部字段(重点分析)

    1.首部字段概述

    先来回顾一下首部字段在报文的位置,HTTP 报文包含报文首部和报文主体,报文首部包含请求行(或状态行)和首部字段。
    在报文众多的字段当中,HTTP 首部字段包含的信息最为丰富。首部字段同时存在于请求和响应报文内,并涵盖 HTTP 报文相关的内容信息。使用首部字段是为了给客服端和服务器端提供报文主体大小、所使用的语言、认证信息等内容。

2.首部字段结构

  • HTTP 首部字段是由首部字段名和字段值构成的,中间用冒号“:”分隔。
  • 另外,字段值对应单个 HTTP 首部字段可以有多个值。
  • 当 HTTP 报文首部中出现了两个或以上具有相同首部字段名的首部字段时,这种情况在规范内尚未明确,根据浏览器内部处理逻辑的不同,优先处理的顺序可能不同,结果可能并不一致。
首部字段名 冒号 字段值
Content-Type : text/html
Keep-Alive text/html

3.首部字段类型

首部字段根据实际用途被分为以下4种类型:

类型 描述
通用首部字段 请求报文和响应报文两方都会使用的首部
请求首部字段 从客户端向服务器端发送请求报文时使用的首部。补充了请求的附加内容、客户端信息、响应内容相关优先级等信息
响应首部字段 从服务器端向客户端返回响应报文时使用的首部。补充了响应的附加内容,也会要求客户端附加额外的内容信息。
实体首部字段 针对请求报文和响应报文的实体部分使用的首部。补充了资源内容更新时间等与实体有关的的信息。

4.通用首部字段(HTTP/1.1)

首部字段名 说明
Cache-Control 控制缓存的行为
Connection 逐挑首部、连接的管理
Date 创建报文的日期时间
Pragma 报文指令
Trailer 报文末端的首部一览
Transfer-Encoding 指定报文主体的传输编码方式
Upgrade 升级为其他协议
Via 代理服务器的相关信息
Warning 错误通知

4.1 Cache-Control

通过指定首部字段 Cache-Control 的指令,就能操作缓存的工作机制。

4.1.1 可用的指令一览

可用的指令按请求和响应分类如下:

缓存请求指令

指令 参数 说明
no-cache 强制向服务器再次验证
no-store 不缓存请求或响应的任何内容
max-age = [秒] 必需 响应的最大Age值
max-stale( =[秒]) 可省略 接收已过期的响应
min-fresh = [秒] 必需 期望在指定时间内的响应仍有效
no-transform 代理不可更改媒体类型
only-if-cached 从缓存获取资源
cache-extension - 新指令标记(token)

缓存响应指令

指令 参数 说明
public 可向任意方提供响应的缓存
private 可省略 仅向特定用户返回响应
no-cache 可省略 缓存前必须先确认其有效性
no-store 不缓存请求或响应的任何内容
no-transform 代理不可更改媒体类型
must-revalidate 可缓存但必须再向源服务器进行确认
proxy-revalidate 要求中间缓存服务器对缓存的响应有效性再进行确认
max-age = [秒] 必需 响应的最大Age值
s-maxage = [秒] 必需 公共缓存服务器响应的最大Age值
cache-extension - 新指令标记(token)

4.1.2 表示能否缓存的指令

public 指令

Cache-Control: public
当指定使用 public 指令时,则明确表明其他用户也可利用缓存。

private 指令

Cache-Control: private
当指定 private 指令后,响应只以特定的用户作为对象,这与 public 指令的行为相反。缓存服务器会对该特定用户提供资源缓存的服务,对于其他用户发送过来的请求,代理服务器则不会返回缓存。

no-cache 指令

Cache-Control: no-cache

  • 使用 no-cache 指令是为了防止从缓存中返回过期的资源。
  • 客户端发送的请求中如果包含 no-cache 指令,则表示客户端将不会接收缓存过的响应。于是,“中间”的缓存服务器必须把客户端请求转发给源服务器。
  • 如果服务器中返回的响应包含 no-cache 指令,那么缓存服务器不能对资源进行缓存。源服务器以后也将不再对缓存服务器请求中提出的资源有效性进行确认,且禁止其对响应资源进行缓存操作。
    Cache-Control: no-cache=Location
    由服务器返回的响应中,若报文首部字段 Cache-Control 中对 no-cache 字段名具体指定参数值,那么客户端在接收到这个被指定参数值的首部字段对应的响应报文后,就不能使用缓存。换言之,无参数值的首部字段可以使用缓存。只能在响应指令中指定该参数。

no-store 指令

Cache-Control: no-store
当使用 no-store 指令时,暗示请求(和对应的响应)或响应中包含机密信息。因此,该指令规定缓存不能在本地存储请求或响应的任一部分。
注意:no-cache 指令代表不缓存过期的指令,缓存会向源服务器进行有效期确认后处理资源;no-store 指令才是真正的不进行缓存。

4.1.3 指定缓存期限和认证的指令

s-maxage 指令

Cache-Control: s-maxage=604800(单位:秒)

  • s-maxage 指令的功能和 max-age 指令的相同,它们的不同点是 s-maxage 指令只适用于供多位用户使用的公共缓存服务器(一般指代理)。也就是说,对于向同一用户重复返回响应的服务器来说,这个指令没有任何作用。

  • 另外,当使用 s-maxage 指令后,则直接忽略对 Expires 首部字段及 max-age 指令的处理。

    max-age 指令

    Cache-Control: max-age=604800(单位:秒)

  • 当客户端发送的请求中包含 max-age 指令时,如果判定缓存资源的缓存时间数值比指定的时间更小,那么客户端就接收缓存的资源。另外,当指定 max-age 的值为0,那么缓存服务器通常需要将请求转发给源服务器。

  • 当服务器返回的响应中包含 max-age 指令时,缓存服务器将不对资源的有效性再作确认,而 max-age 数值代表资源保存为缓存的最长时间。

  • 应用 HTTP/1.1 版本的缓存服务器遇到同时存在 Expires 首部字段的情况时,会优先处理 max-age 指令,并忽略掉 Expires 首部字段;而 HTTP/1.0 版本的缓存服务器则相反。

    min-fresh 指令

    Cache-Control: min-fresh=60(单位:秒)
    min-fresh 指令要求缓存服务器返回至少还未过指定时间的缓存资源。

max-stale 指令

Cache-Control: max-stale=3600(单位:秒)

使用 max-stale 可指示缓存资源,即使过期也照常接收。
如果指令未指定参数值,那么无论经过多久,客户端都会接收响应;如果指定了具体参数值,那么即使过期,只要仍处于 max-stale 指定的时间内,仍旧会被客户端接收。

only-if-cached 指令

Cache-Control: only-if-cached
表示客户端仅在缓存服务器本地缓存目标资源的情况下才会要求其返回。换言之,该指令要求缓存服务器不重新加载响应,也不会再次确认资源的有效性。

must-revalidate 指令

Cache-Control: must-revalidate
使用 must-revalidate 指令,代理会向源服务器再次验证即将返回的响应缓存目前是否仍有效。另外,使用 must-revalidate 指令会忽略请求的 max-stale 指令。

proxy-revalidate 指令

1Cache-Control: proxy-revalidate1
proxy-revalidate 指令要求所有的缓存服务器在接收到客户端带有该指令的请求返回响应之前,必须再次验证缓存的有效性。

no-transform 指令

Cache-Control: no-transform
使用 no-transform 指令规定无论是在请求还是响应中,缓存都不能改变实体主体的媒体类型。这样做可防止缓存或代理压缩图片等类似操作。

4.1.4 Cache-Control 扩展

Cache-Control: private, community="UCI"
通过 cache-extension 标记(token),可以扩展 Cache-Control 首部字段内的指令。上述 community 指令即扩展的指令,如果缓存服务器不能理解这个新指令,就会直接忽略掉。

4.2 Connection

Connection 首部字段具备以下两个作用:

控制不再转发的首部字段

Connection: Upgrade
在客户端发送请求和服务器返回响应中,使用 Connection 首部字段,可控制不再转发给代理的首部字段,即删除后再转发(即Hop-by-hop首部)。

管理持久连接

Connection: close
HTTP/1.1 版本的默认连接都是持久连接。当服务器端想明确断开连接时,则指定 Connection 首部字段的值为 close。
Connection: Keep-Alive
HTTP/1.1 之前的 HTTP 版本的默认连接都是非持久连接。为此,如果想在旧版本的 HTTP 协议上维持持续连接,则需要指定 Connection 首部字段的值为 Keep-Alive。

4.3 Date

表明创建 HTTP 报文的日期和时间。
Date: Mon, 10 Jul 2017 15:50:06 GMT
HTTP/1.1 协议使用在 RFC1123 中规定的日期时间的格式。

4.4 Pragma

Pragma 首部字段是 HTTP/1.1 版本之前的历史遗留字段,仅作为与 HTTP/1.0 的向后兼容而定义。
Pragma: no-cache

  • 该首部字段属于通用首部字段,但只用在客户端发送的请求中,要求所有的中间服务器不返回缓存的资源。
  • 所有的中间服务器如果都能以 HTTP/1.1 为基准,那直接采用 Cache-Control: no-cache 指定缓存的处理方式最为理想。但是要整体掌握所有中间服务器使用的 HTTP 协议版本却是不现实的,所以,发送的请求会同时包含下面两个首部字段:

    Cache-Control: no-cache
    Pragma: no-cache
    4.5 Trailer
    Trailer: Expires
    首部字段 Trailer 会事先说明在报文主体后记录了哪些首部字段。可应用在 HTTP/1.1 版本分块传输编码时。

4.6 Transfer-Encoding

Transfer-Encoding: chunked

规定了传输报文主体时采用的编码方式。
HTTP/1.1 的传输编码方式仅对分块传输编码有效。

4.7 Upgrade

Upgrade: TSL/1.0
用于检测 HTTP 协议及其他协议是否可使用更高的版本进行通信,其参数值可以用来指定一个完全不同的通信协议。

4.8 Via

Via: 1.1 a1.sample.com(Squid/2.7)

为了追踪客户端和服务器端之间的请求和响应报文的传输路径。报文经过代理或网关时,会现在首部字段 Via 中附加该服务器的信息,然后再进行转发。
`首部字段 Via 不仅用于追踪报文的转发,还可避免请求回环的发生。

4.9 Warning

该首部字段通常会告知用户一些与缓存相关的问题的警告。
Warning 首部字段的格式如下:
Warning:[警告码][警告的主机:端口号] "[警告内容]"([日期时间])
最后的日期时间可省略。
HTTP/1.1 中定义了7种警告,警告码对应的警告内容仅推荐参考,另外,警告码具备扩展性,今后有可能追加新的警告码。

警告码 警告内容 说明
110 Response is stale(响应已过期) 代理返回已过期的资源
111 Revalidation failed(再验证失败) 代理再验证资源有效性时失败(服务器无法到达等原因)
112 Disconnection operation(断开连接操作) 代理与互联网连接被故意切断
113 Heuristic expiration(试探性过期) 响应的试用期超过24小时(有效缓存的设定时间大于24小时的情况下)
199 Miscellaneous warning(杂项警告) 任意的警告内容
214 Transformation applied(使用了转换) 代理对内容编码或媒体类型等执行了某些处理时
299 Miscellaneous persistent warning(持久杂项警告) 任意的警告内容

5. 请求首部字段(HTTP/1.1)

首部字段名 说明
Accept 用户代理可处理的媒体类型
Accept-Charset 优先的字符集
Accept-Encoding 优先的内容编码
Accept-Language 优先的语言(自然语言)
Authorization Web认证信息
Expect 期待服务器的特定行为
From 用户的电子邮箱地址
Host 请求资源所在服务器
If-Match 比较实体标记(ETag)
If-Modified-Since 比较资源的更新时间
If-None-Match 比较实体标记(与 If-Macth 相反)
If-Range 资源未更新时发送实体 Byte 的范围请求
If-Unmodified-Since 比较资源的更新时间(与 If-Modified-Since 相反)
Max-Forwards 最大传输逐跳数
Proxy-Authorization 代理服务器要求客户端的认证信息
Range 实体的字节范围请求
Referer 对请求中 URI 的原始获取方
TE 传输编码的优先级
User-Agent HTTP 客户端程序的信息

5.1 Accept

Accept: text/html, application/xhtml+xml, application/xml; q=0.5

  • Accept 首部字段可通知服务器,用户代理能够处理的媒体类型及媒体类型的相对优先级。可使用 type/subtype 这种形式,一次指定多种媒体类型。
  • 若想要给显示的媒体类型增加优先级,则使用 q=[数值] 来表示权重值,用分号(;)进行分隔。权重值的范围 0~1(可精确到小数点后三位),且 1 为最大值。不指定权重值时,默认为 1。

    5.2 Accept-Charset

    Accept-Charset: iso-8859-5, unicode-1-1; q=0.8
    Accept-Charset 首部字段可用来通知服务器用户代理支持的字符集及字符集的相对优先顺序。另外,可一次性指定多种字符集。同样使用 q=[数值] 来表示相对优先级。

5.3 Accept-Encoding

Accept-Encoding: gzip, deflate
Accept-Encoding 首部字段用来告知服务器用户代理支持的内容编码及内容编码的优先顺序,并可一次性指定多种内容编码。同样使用 q=[数值] 来表示相对优先级。也可使用星号(*)作为通配符,指定任意的编码格式。

5.4 Accept-Language

Accept-Lanuage: zh-cn,zh;q=0.7,en=us,en;q=0.3
告知服务器用户代理能够处理的自然语言集(指中文或英文等),以及自然语言集的相对优先级,可一次性指定多种自然语言集。同样使用 q=[数值] 来表示相对优先级。

5.5 Authorization

Authorization: Basic ldfKDHKfkDdasSAEdasd==
告知服务器用户代理的认证信息(证书值)。通常,想要通过服务器认证的用户代理会在接收到返回的 401 状态码响应后,把首部字段 Authorization 加入请求中。共用缓存在接收到含有 Authorization 首部字段的请求时的操作处理会略有差异。

5.6 Expect

Expect: 100-continue
告知服务器客户端期望出现的某种特定行为。

5.7 From

From: Deeson_Woo@163.com
告知服务器使用用户代理的电子邮件地址。

5.8 Host

Host: www.jianshu.com

告知服务器,请求的资源所处的互联网主机和端口号。
Host 首部字段是 HTTP/1.1 规范内唯一一个必须被包含在请求内的首部字段。
若服务器未设定主机名,那直接发送一个空值即可 Host: 。

5.9 If-Match

形如 If-xxx 这种样式的请求首部字段,都可称为条件请求。服务器接收到附带条件的请求后,只有判断指定条件为真时,才会执行请求。

If-Match: "123456"

  • 首部字段 If-Match,属附带条件之一,它会告知服务器匹配资源所用的实体标记(ETag)值。这时的服务器无法使用弱 ETag 值。

  • 服务器会比对 If-Match 的字段值和资源的 ETag 值,仅当两者一致时,才会执行请求。反之,则返回状态码 412 Precondition Failed 的响应。

  • 还可以使用星号(*)指定 If-Match 的字段值。针对这种情况,服务器将会忽略 ETag 的值,只要资源存在就处理请求。

    5.10 If-Modified-Since

    If-Modified-Since: Mon, 10 Jul 2017 15:50:06 GMT

  • 首部字段 If-Modified-Since,属附带条件之一,用于确认代理或客户端拥有的本地资源的有效性。

  • 它会告知服务器若 If-Modified-Since 字段值早于资源的更新时间,则希望能处理该请求。而在指定 If-Modified-Since 字段值的日期时间之后,如果请求的资源都没有过更新,则返回状态码 304 Not Modified 的响应。

    5.11 If-None-Match

    If-None-Match: "123456"
    首部字段 If-None-Match 属于附带条件之一。它和首部字段 If-Match 作用相反。用于指定 If-None-Match 字段值的实体标记(ETag)值与请求资源的 ETag 不一致时,它就告知服务器处理该请求。

5.12 If-Range

If-Range: "123456"

  • 首部字段 If-Range 属于附带条件之一。它告知服务器若指定的 If-Range 字段值(ETag 值或者时间)和请求资源的 ETag 值或时间相一致时,则作为范围请求处理。反之,则返回全体资源。
  • 下面我们思考一下不使用首部字段 If-Range 发送请求的情况。服务器端的资源如果更新,那客户端持有资源中的一部分也会随之无效,当然,范围请求作为前提是无效的。这时,服务器会暂且以状态码 412 Precondition Failed 作为响应返回,其目的是催促客户端再次发送请求。这样一来,与使用首部字段 If-Range 比起来,就需要花费两倍的功夫。

    5.13 If-Unmodified-Since

    If-Unmodified-Since: Mon, 10 Jul 2017 15:50:06 GMT
    首部字段 If-Unmodified-Since 和首部字段 If-Modified-Since 的作用相反。它的作用的是告知服务器,指定的请求资源只有在字段值内指定的日期时间之后,未发生更新的情况下,才能处理请求。如果在指定日期时间后发生了更新,则以状态码 412 Precondition Failed 作为响应返回。

5.14 Max-Forwards

Max-Forwards: 10
通过 TRACE 方法或 OPTIONS 方法,发送包含首部字段 Max-Forwards 的请求时,该字段以十进制整数形式指定可经过的服务器最大数目。服务器在往下一个服务器转发请求之前,Max-Forwards 的值减 1 后重新赋值。当服务器接收到 Max-Forwards 值为 0 的请求时,则不再进行转发,而是直接返回响应。

5.15 Proxy-Authorization

Proxy-Authorization: Basic dGlwOjkpNLAGfFY5

  • 接收到从代理服务器发来的认证质询时,客户端会发送包含首部字段 Proxy-Authorization 的请求,以告知服务器认证所需要的信息。

  • 这个行为是与客户端和服务器之间的 HTTP 访问认证相类似的,不同之处在于,认证行为发生在客户端与代理之间。

    5.16 Range

    Range: bytes=5001-10000

  • 对于只需获取部分资源的范围请求,包含首部字段 Range 即可告知服务器资源的指定范围。

  • 接收到附带 Range 首部字段请求的服务器,会在处理请求之后返回状态码为 206 Partial Content 的响应。无法处理该范围请求时,则会返回状态码 200 OK 的响应及全部资源。

    5.17 Referer

    Referer: http://www.sample.com/index.html
    首部字段 Referer 会告知服务器请求的原始资源的 URI。

5.18 TE

TE: gzip, deflate; q=0.5

  • 首部字段 TE 会告知服务器客户端能够处理响应的传输编码方式及相对优先级。它和首部字段 Accept-Encoding 的功能很相像,但是用于传输编码。

  • 首部字段 TE 除指定传输编码之外,还可以指定伴随 trailer 字段的分块传输编码的方式。应用后者时,只需把 trailers 赋值给该字段值。TE: trailers

    5.19 User-Agent

    User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:13.0) Gecko/20100101

  • 首部字段 User-Agent 会将创建请求的浏览器和用户代理名称等信息传达给服务器。

  • 由网络爬虫发起请求时,有可能会在字段内添加爬虫作者的电子邮件地址。此外,如果请求经过代理,那么中间也很可能被添加上代理服务器的名称。

    6. 响应首部字段(HTTP/1.1)

首部字段名 说明
Accept-Ranges 是否接受字节范围请求
Age 推算资源创建经过时间
ETag 资源的匹配信息
Location 令客户端重定向至指定 URI
Proxy-Authenticate 代理服务器对客户端的认证信息
Retry-After 对再次发起请求的时机要求
Server HTTP 服务器的安装信息
Vary 代理服务器缓存的管理信息
WWW-Authenticate 服务器对客户端的认证信息

6.1 Accept-Ranges

Accept-Ranges: bytes

  • 首部字段 Accept-Ranges 是用来告知客户端服务器是否能处理范围请求,以指定获取服务器端某个部分的资源。
  • 可指定的字段值有两种,可处理范围请求时指定其为 bytes,反之则指定其为 none。

    6.2 Age

    Age: 1200

首部字段 Age 能告知客户端,源服务器在多久前创建了响应。字段值的单位为秒。
若创建该响应的服务器是缓存服务器,Age 值是指缓存后的响应再次发起认证到认证完成的时间值。代理创建响应时必须加上首部字段 Age。

6.3 ETag

ETag: "usagi-1234"

  • 首部字段 ETag 能告知客户端实体标识。它是一种可将资源以字符串形式做唯一性标识的方式。服务器会为每份资源分配对应的 ETag 值。

  • 另外,当资源更新时,ETag 值也需要更新。生成 ETag 值时,并没有统一的算法规则,而仅仅是由服务器来分配。

  • ETag 中有强 ETag 值和弱 ETag 值之分。强 ETag 值,不论实体发生多么细微的变化都会改变其值;弱 ETag 值只用于提示资源是否相同。只有资源发生了根本改变,产生差异时才会改变 ETag 值。这时,会在字段值最开始处附加 W/: ETag: W/“usagi-1234”。

    6.4 Location

    Location: http://www.sample.com/sample.html

  • 使用首部字段 Location 可以将响应接收方引导至某个与请求 URI 位置不同的资源。

  • 基本上,该字段会配合 3xx :Redirection 的响应,提供重定向的 URI。

  • 几乎所有的浏览器在接收到包含首部字段 Location 的响应后,都会强制性地尝试对已提示的重定向资源的访问。

    6.5 Proxy-Authenticate

    Proxy-Authenticate: Basic realm="Usagidesign Auth"

  • 首部字段 Proxy-Authenticate 会把由代理服务器所要求的认证信息发送给客户端。

  • 它与客户端和服务器之间的 HTTP 访问认证的行为相似,不同之处在于其认证行为是在客户端与代理之间进行的。

    6.6 Retry-After

    Retry-After: 180

  • 首部字段 Retry-After 告知客户端应该在多久之后再次发送请求。主要配合状态码 503 Service Unavailable 响应,或 3xx Redirect 响应一起使用。

  • 字段值可以指定为具体的日期时间(Mon, 10 Jul 2017 15:50:06 GMT 等格式),也可以是创建响应后的秒数。

    6.7 Server

    Server: Apache/2.2.6 (Unix) PHP/5.2.5
    首部字段 Server 告知客户端当前服务器上安装的 HTTP 服务器应用程序的信息。不单单会标出服务器上的软件应用名称,还有可能包括版本号和安装时启用的可选项。

6.8 Vary

Vary: Accept-Language

  • 首部字段 Vary 可对缓存进行控制。源服务器会向代理服务器传达关于本地缓存使用方法的命令。
  • 从代理服务器接收到源服务器返回包含 Vary 指定项的响应之后,若再要进行缓存,仅对请求中含有相同 Vary 指定首部字段的请求返回缓存。即使对相同资源发起请求,但由于 Vary 指定的首部字段不相同,因此必须要从源服务器重新获取资源。

    6.9 WWW-Authenticate

    WWW-Authenticate: Basic realm="Usagidesign Auth"
    首部字段 WWW-Authenticate 用于 HTTP 访问认证。它会告知客户端适用于访问请求 URI 所指定资源的认证方案(Basic 或是 Digest)和带参数提示的质询(challenge)。

7. 实体首部字段(HTTP/1.1)

首部字段名 说明
Allow 资源可支持的 HTTP 方法
Content-Encoding 实体主体适用的编码方式
Content-Language 实体主体的自然语言
Content-Length 实体主体的大小(单位:字节)
Content-Location 替代对应资源的 URI
Content-MD5 实体主体的报文摘要
vContent-Range 实体主体的位置范围
Content-Type 实体主体的媒体类型
Expires 实体主体过期的日期时间
Last-Modified 资源的最后修改日期时间

7.1 Allow

Allow: GET, HEAD

  • 首部字段 Allow 用于通知客户端能够支持 Request-URI 指定资源的所有 HTTP 方法。

  • 当服务器接收到不支持的 HTTP 方法时,会以状态码 405 Method Not Allowed 作为响应返回。与此同时,还会把所有能支持的 HTTP 方法写入首部字段 Allow 后返回。

    7.2 Content-Encoding

    Content-Encoding: gzip

  • 首部字段 Content-Encoding 会告知客户端服务器对实体的主体部分选用的内容编码方式。内容编码是指在不丢失实体信息的前提下所进行的压缩。

  • 主要采用这 4 种内容编码的方式(gzip、compress、deflate、identity)。

    7.3 Content-Language

    Content-Language: zh-CN
    首部字段 Content-Language 会告知客户端,实体主体使用的自然语言(指中文或英文等语言)。

7.4 Content-Length

Content-Length: 15000
首部字段 Content-Length 表明了实体主体部分的大小(单位是字节)。对实体主体进行内容编码传输时,不能再使用 Content-Length首部字段。

7.5 Content-Location

Content-Location: http://www.sample.com/index.html
首部字段 Content-Location 给出与报文主体部分相对应的 URI。和首部字段 Location 不同,Content-Location 表示的是报文主体返回资源对应的 URI。

7.6 Content-MD5

Content-MD5: OGFkZDUwNGVhNGY3N2MxMDIwZmQ4NTBmY2IyTY==
首部字段 Content-MD5 是一串由 MD5 算法生成的值,其目的在于检查报文主体在传输过程中是否保持完整,以及确认传输到达。

7.7 Content-Range

Content-Range: bytes 5001-10000/10000
针对范围请求,返回响应时使用的首部字段 Content-Range,能告知客户端作为响应返回的实体的哪个部分符合范围请求。字段值以字节为单位,表示当前发送部分及整个实体大小。

7.8 Content-Type

Content-Type: text/html; charset=UTF-8
首部字段 Content-Type 说明了实体主体内对象的媒体类型。和首部字段 Accept 一样,字段值用 type/subtype 形式赋值。参数 charset 使用 iso-8859-1 或 euc-jp 等字符集进行赋值。

7.9 Expires

Expires: Mon, 10 Jul 2017 15:50:06 GMT

  • 首部字段 Expires 会将资源失效的日期告知客户端。
  • 缓存服务器在接收到含有首部字段 Expires 的响应后,会以缓存来应答请求,在 Expires 字段值指定的时间之前,响应的副本会一直被保存。当超过指定的时间后,缓存服务器在请求发送过来时,会转向源服务器请求资源。
  • 源服务器不希望缓存服务器对资源缓存时,最好在 Expires 字段内写入与首部字段 Date 相同的时间值。

    7.10 Last-Modified`

    Last-Modified: Mon, 10 Jul 2017 15:50:06 GMT
    首部字段 Last-Modified 指明资源最终修改的时间。一般来说,这个值就是 Request-URI 指定资源被修改的时间。但类似使用 CGI 脚本进行动态数据处理时,该值有可能会变成数据最终修改时的时间。
首部字段名 说明 首部类型
Set-Cookie 开始状态管理所使用的 Cookie 信息 响应首部字段
Cookie 服务器接收到的 Cookie 信息 请求首部字段
### 8.1 Set-Cookie
Set-Cookie: status=enable; expires=Mon, 10 Jul 2017 15:50:06 GMT; path=/;

下面的表格列举了 Set-Cookie 的字段值。

属性 说明
NAME=VALUE 赋予 Cookie 的名称和其值(必需项)
expires=DATE Cookie 的有效期(若不明确指定则默认为浏览器关闭前为止)
path=PATH 将服务器上的文件目录作为Cookie的适用对象(若不指定则默认为文档所在的文件目录)
domain=域名 作为 Cookie 适用对象的域名 (若不指定则默认为创建 Cookie的服务器的域名)
Secure 仅在 HTTPS 安全通信时才会发送 Cookie
HttpOnly 加以限制,使 Cookie 不能被 JavaScript 脚本访问

8.1.1 expires 属性

  • Cookie 的 expires 属性指定浏览器可发送 Cookie 的有效期。
  • 当省略 expires 属性时,其有效期仅限于维持浏览器会话(Session)时间段内。这通常限于浏览器应用程序被关闭之前。
  • 另外,一旦 Cookie 从服务器端发送至客户端,服务器端就不存在可以显式删除 Cookie 的方法。但可通过覆盖已过期的 Cookie,实现对客户端 Cookie 的实质性删除操作。

    8.1.2 path 属性

    Cookie 的 path 属性可用于限制指定 Cookie 的发送范围的文件目录。

8.1.3 domain 属性

  • 通过 Cookie 的 domain 属性指定的域名可做到与结尾匹配一致。比如,当指定 example.com 后,除example.com 以外,www.example.com 或 www2.example.com 等都可以发送 Cookie。
  • 因此,除了针对具体指定的多个域名发送 Cookie 之 外,不指定 domain 属性显得更安全。

    8.1.4 secure 属性

    Cookie 的 secure 属性用于限制 Web 页面仅在 HTTPS 安全连接时,才可以发送 Cookie。

8.1.5 HttpOnly 属性

  • Cookie 的 HttpOnly 属性是 Cookie 的扩展功能,它使 JavaScript 脚本无法获得 Cookie。其主要目的为防止跨站脚本攻击(Cross-site scripting,XSS)对 Cookie 的信息窃取。
  • 通过上述设置,通常从 Web 页面内还可以对 Cookie 进行读取操作。但使用 JavaScript 的 document.cookie 就无法读取附加 HttpOnly 属性后的 Cookie 的内容了。因此,也就无法在 XSS 中利用 JavaScript 劫持 Cookie 了。Cookie: status=enable
    首部字段 Cookie 会告知服务器,当客户端想获得 HTTP 状态管理支持时,就会在请求中包含从服务器接收到的 Cookie。接收到多个 Cookie 时,同样可以以多个 Cookie 形式发送。

9. 其他首部字段

HTTP 首部字段是可以自行扩展的。所以在 Web 服务器和浏览器的应用上,会出现各种非标准的首部字段。
以下是最为常用的首部字段。

9.1 X-Frame-Options

X-Frame-Options: DENY
首部字段 X-Frame-Options 属于 HTTP 响应首部,用于控制网站内容在其他 Web 网站的 Frame 标签内的显示问题。其主要目的是为了防止点击劫持(clickjacking)攻击。首部字段 X-Frame-Options 有以下两个可指定的字段值:

  • DENY:拒绝

  • SAMEORIGIN:仅同源域名下的页面(Top-level-browsing-context)匹配时许可。(比如,当指定 http://sample.com/sample.html 页面为 SAMEORIGIN 时,那么 sample.com 上所有页面的 frame 都被允许可加载该页面,而 example.com 等其他域名的页面就不行了)

    9.2 X-XSS-Protection

    X-XSS-Protection: 1
    首部字段 X-XSS-Protection 属于 HTTP 响应首部,它是针对跨站脚本攻击(XSS)的一种对策,用于控制浏览器 XSS 防护机制的开关。首部字段 X-XSS-Protection 可指定的字段值如下:

  • 0 :将 XSS 过滤设置成无效状态

  • 1 :将 XSS 过滤设置成有效状态

    9.3 DNT

    DNT: 1
    首部字段 DNT 属于 HTTP 请求首部,其中 DNT 是 Do Not Track 的简称,意为拒绝个人信息被收集,是表示拒绝被精准广告追踪的一种方法。首部字段 DNT 可指定的字段值如下:

  • 0 :同意被追踪

  • 1 :拒绝被追踪
    由于首部字段 DNT 的功能具备有效性,所以 Web 服务器需要对 DNT做对应的支持。

9.4 P3P

P3P: CP="CAO DSP LAW CURa ADMa DEVa TAIa PSAa PSDa IVAa IVDa OUR BUS IND
首部字段 P3P 属于 HTTP 响应首部,通过利用 P3P(The Platform for Privacy Preferences,在线隐私偏好平台)技术,可以让 Web 网站上的个人隐私变成一种仅供程序可理解的形式,以达到保护用户隐私的目的。
要进行 P3P 的设定,需按以下操作步骤进行:

  • 步骤 1:创建 P3P 隐私
  • 步骤 2:创建 P3P 隐私对照文件后,保存命名在 /w3c/p3p.xml
  • 步骤 3:从 P3P 隐私中新建 Compact policies 后,输出到 HTTP 响应中

    七、HTTP 响应状态码(重点分析)

    1. 状态码概述

  • HTTP 状态码负责表示客户端 HTTP 请求的返回结果、标记服务器端的处理是否正常、通知出现的错误等工作。
  • HTTP 状态码如 200 OK ,以 3 位数字和原因短语组成。数字中的第一位指定了响应类别,后两位无分类。
  • 不少返回的响应状态码都是错误的,但是用户可能察觉不到这点。比如 Web 应用程序内部发生错误,状态码依然返回 200 OK。

    2. 状态码类别

    类别 原因短语
    1xx Informational(信息性状态码) 接收的请求正在处理
    2xx Success(成功状态码) 请求正常处理完毕
    3xx Redirection(重定向状态码) 需要进行附加操作以完成请求
    4xx Client Error(客户端错误状态码) 服务器无法处理请求
    5xx Server Error(服务器错误状态码) 服务器处理请求出错

我们可以自行改变 RFC2616 中定义的状态码或者服务器端自行创建状态码,只要遵守状态码的类别定义就可以了。

3. 常用状态码解析

HTTP 状态码种类繁多,数量达几十种。其中最常用的有以下 14 种,一起来看看。

3.1 200 OK

表示从客户端发来的请求在服务器端被正常处理了。

3.2 204 No Content

代表服务器接收的请求已成功处理,但在返回的响应报文中不含实体的主体部分。另外,也不允许返回任何实体的主体。
一般在只需要从客户端向服务器端发送消息,而服务器端不需要向客户端发送新消息内容的情况下使用。

3.3 206 Partial Content

表示客户端进行了范围请求,而服务器成功执行了这部分的 GET 请求。响应报文中包含由 Content-Range 首部字段指定范围的实体内容。

3.4 301 Moved Permanently

永久性重定向。表示请求的资源已被分配了新的 URI。以后应使用资源现在所指的 URI。也就是说,如果已经把资源对应的 URI 保存为书签了,这时应该按 Location 首部字段提示的 URI 重新保存。

3.5 302 Found

  • 临时性重定向。表示请求的资源已被分配了新的 URI,希望用户(本次)能使用新的 URI 访问。
  • 301 Moved Permanently 状态码相似,但 302 Found 状态码代表资源不是被永久移动,只是临时性质的。换句话说,已移动的资源对应的 URI 将来还有可能发生改变。

    3.6 303 See Other

  • 表示由于请求的资源存在着另一个 URI,应使用 GET 方法定向获取请求的资源。
  • 303 See Other302 Found 状态码有着相同的功能,但 303 See Other 状态码明确表示客户端应采用 GET 方法获取资源,这点与 302 Found 状态码有区别。

    3.7 304 Not Modified

  • 表示客户端发送附带条件的请求时,服务器端允许请求访问的资源,但未满足条件的情况。
  • 304 Not Modified 状态码返回时,不包含任何响应的主体部分。
  • 304 Not Modified 虽然被划分到 3xx 类别中,但和重定向没有关系。

    3.8 307 Temporary Redirect

    临时重定向。该状态码与 302 Found 有着相同的含义。

3.9 400 Bad Request

  • 表示请求报文中存在语法错误。当错误发生时,需修改请求的内容后再次发送请求。
  • 另外,浏览器会像 200 OK 一样对待该状态码。

    3.10 401 Unauthorized

    表示发送的请求需要有通过 HTTP 认证(BASIC 认证、DIGEST 认证)的认证信息。
    另外,若之前已进行过 1 次请求,则表示用户认证失败。
    返回含有 401 Unauthorized 的响应必须包含一个适用于被请求资源的 WWW-Authenticate 首部用以质询(challenge)用户信息。

    3.11 403 Forbidden

    表明对请求资源的访问被服务器拒绝了。服务器端没有必要给出详细的拒绝理由,当然也可以在响应报文的实体主体部分对原因进行描述。

3.12 404 Not Found

表明服务器上无法找到请求的资源。除此之外,也可以在服务器端拒绝请求且不想说明理由的时候使用。

3.13 500 Internal Server Error

表明服务器端在执行请求时发生了错误。也可能是 Web 应用存在的 bug 或某些临时的故障。

3.14 503 Service Unavailable

表明服务器暂时处于超负载或正在进行停机维护,现在无法处理请求。如果事先得知解除以上状况需要的时间,最好写入 Retry-After 首部字段再返回给客户端。

八、HTTP 报文实体

1. HTTP 报文实体概述

HTTP 报文结构 大家请仔细看看上面示例中,各个组成部分对应的内容。 接着,我们来看看报文和实体的概念。如果把 HTTP 报文想象成因特网货运系统中的箱子,那么 HTTP 实体就是报文中实际的货物。
  • 报文:是网络中交换和传输的数据单元,即站点一次性要发送的数据块。报文包含了将要发送的完整的数据信息,其长短很不一致,长度不限且可变。
  • 实体:作为请求或响应的有效载荷数据(补充项)被传输,其内容由实体首部和实体主体组成。(实体首部相关内容在上面第六点中已有阐述。)
    我们可以看到,上面示例右图中深红色框的内容就是报文的实体部分,而蓝色框的两部分内容分别就是实体首部和实体主体。而左图中粉红框内容就是报文主体。
    通常,报文主体等于实体主体。只有当传输中进行编码操作时,实体主体的内容发生变化,才导致它和报文主体产生差异。

2. 内容编码

  • HTTP 应用程序有时在发送之前需要对内容进行编码。例如,在把很大的 HTML 文档发送给通过慢速连接上来的客户端之前,服务器可能会对其进行压缩,这样有助于减少传输实体的时间。服务器还可以把内容搅乱或加密,以此来防止未授权的第三方看到文档的内容。
  • 这种类型的编码是在发送方应用到内容之上的。当内容经过内容编码后,编好码的数据就放在实体主体中,像往常一样发送给接收方。
    内容编码类型:
编码方式 描述
gzip 表明实体采用 GNU zip 编码
compress 表明实体采用 Unix 的文件压缩程序
deflate 表明实体采用 zlib 的格式压缩的
identity 表明没有对实体进行编码,当没有
Content-Encoding 首部字段时,默认采用此编码方式
## 3. 传输编码
内容编码是对报文的主体进行的可逆变换,是和内容的具体格式细节紧密相关的。
传输编码也是作用在实体主体上的可逆变换,但使用它们是由于架构方面的原因,同内容的格式无关。使用传输编码是为了改变报文中的数据在网络上传输的方式。

内容编码和传输编码的对比

4. 分块编码

分块编码把报文分割成若干已知大小的块。块之间是紧挨着发送的,这样就不需要在发送之前知道整个报文的大小了。分块编码是一种传输编码,是报文的属性。

分块编码与持久连接
若客户端与服务器端之间不是持久连接,客户端就不需要知道它在读取的主体的长度,而只需要读取到服务器关闭主体连接为止。
当使用持久连接时,在服务器写主体之前,必须知道它的大小并在 Content-Length 首部中发送。如果服务器动态创建内容,就可能在发送之前无法知道主体的长度。
分块编码为这种困难提供了解决方案,只要允许服务器把主体分块发送,说明每块的大小就可以了。因为主体是动态创建的,服务器可以缓冲它的一部分,发送其大小和相应的块,然后在主体发送完之前重复这个过程。服务器可以用大小为 0 的块作为主体结束的信号,这样就可以继续保持连接,为下一个响应做准备。
来看看一个分块编码的报文示例:

分块编码的报文

5.多部分媒体类型

MIME 中的 multipart(多部分)电子邮件报文中包含多个报文,它们合在一起作为单一的复杂报文发送。每一部分都是独立的,有各自的描述其内容的集,不同部分之间用分界字符串连接在一起。
相应得,HTTP 协议中也采纳了多部分对象集合,发送的一份报文主体内可包含多种类型实体。
多部分对象集合包含的对象如下:

  • multipart/form-data:在 Web 表单文件上传时使用。
  • multipart/byteranges:状态码 206 Partial Content 响应报文包含了多个范围的内容时使用。

    6. 范围请求

    假设你正在下载一个很大的文件,已经下了四分之三,忽然网络中断了,那下载就必须重头再来一遍。为了解决这个问题,需要一种可恢复的机制,即能从之前下载中断处恢复下载。要实现该功能,这就要用到范围请求。
    有了范围请求, HTTP 客户端可以通过请求曾获取失败的实体的一个范围(或者说一部分),来恢复下载该实体。当然这有一个前提,那就是从客户端上一次请求该实体到这一次发出范围请求的时间段内,该对象没有改变过。例如:

GET /bigfile.html HTTP/1.1
Host: www.sample.com
Range: bytes=20224-
···

实体范围请求示例
上面示例中,客户端请求的是文档开头20224字节之后的部分。

九、与 HTTP 协作的 Web 服务器

HTTP 通信时,除客户端和服务器外,还有一些用于协助通信的应用程序。如下列出比较重要的几个:代理、缓存、网关、隧道、Agent 代理。

1.代理

代理

HTTP 代理服务器是 Web 安全、应用集成以及性能优化的重要组成模块。代理位于客户端和服务器端之间,接收客户端所有的 HTTP 请求,并将这些请求转发给服务器(可能会对请求进行修改之后再进行转发)。对用户来说,这些应用程序就是一个代理,代表用户访问服务器。
出于安全考虑,通常会将代理作为转发所有 Web 流量的可信任中间节点使用。代理还可以对请求和响应进行过滤,安全上网或绿色上网。

2. 缓存

浏览器第一次请求:

浏览器第一次请求
浏览器再次请求:

浏览器再次请求
Web 缓存或代理缓存是一种特殊的 HTTP 代理服务器,可以将经过代理传输的常用文档复制保存起来。下一个请求同一文档的客户端就可以享受缓存的私有副本所提供的服务了。客户端从附近的缓存下载文档会比从远程 Web 服务器下载快得多。

3. 网关

HTTP / FTP 网关

网关是一种特殊的服务器,作为其他服务器的中间实体使用。通常用于将 HTTP 流量转换成其他的协议。网关接收请求时就好像自己是资源的源服务器一样。客户端可能并不知道自己正在跟一个网关进行通信。

4. 隧道

HTTP/SSL 隧道

隧道是会在建立起来之后,就会在两条连接之间对原始数据进行盲转发的 HTTP 应用程序。HTTP 隧道通常用来在一条或多条 HTTP 连接上转发非 HTTP 数据,转发时不会窥探数据。
HTTP 隧道的一种常见用途就是通过 HTTP 连接承载加密的安全套接字层(SSL)流量,这样 SSL 流量就可以穿过只允许 Web 流量通过的防火墙了。

5. Agent 代理

自动搜索引擎“网络蜘蛛”

Agent 代理是代表用户发起 HTTP 请求的客户端应用程序。所有发布 Web 请求的应用程序都是 HTTP Agent 代理。

作者:涤生_Woo
链接:https://www.jianshu.com/p/6e9e4156ece3

一篇文章带你熟悉TCP/IP协议.md

同样的,本文篇幅也比较长,先来一张思维导图,带大家过一遍。

一图看完本文

一、 计算机网络体系结构分层

计算机网络体系结构分层

计算机网络体系结构分层

不难看出,TCP/IP 与 OSI 在分层模块上稍有区别。OSI 参考模型注重“通信协议必要的功能是什么”,而 TCP/IP 则更强调“在计算机上实现协议应该开发哪种程序”。

二、 TCP/IP 基础

1. TCP/IP 的具体含义

从字面意义上讲,有人可能会认为 TCP/IP 是指 TCP 和 IP 两种协议。实际生活当中有时也确实就是指这两种协议。然而在很多情况下,它只是利用 IP 进行通信时所必须用到的协议群的统称。具体来说,IP 或 ICMP、TCP 或 UDP、TELNET 或 FTP、以及 HTTP 等都属于 TCP/IP 协议。他们与 TCP 或 IP 的关系紧密,是互联网必不可少的组成部分。TCP/IP 一词泛指这些协议,因此,有时也称 TCP/IP 为网际协议群。
互联网进行通信时,需要相应的网络协议,TCP/IP 原本就是为使用互联网而开发制定的协议族。因此,互联网的协议就是 TCP/IP,TCP/IP 就是互联网的协议。

网际协议群

2. 数据包

包、帧、数据包、段、消息

以上五个术语都用来表述数据的单位,大致区分如下:

  • 包可以说是全能性术语;
  • 帧用于表示数据链路层中包的单位;
  • 数据包是 IP 和 UDP 等网络层以上的分层中包的单位;
  • 段则表示 TCP 数据流中的信息;
  • 消息是指应用协议中数据的单位。

每个分层中,都会对所发送的数据附加一个首部,在这个首部中包含了该层必要的信息,如发送的目标地址以及协议相关信息。通常,为协议提供的信息为包首部,所要发送的内容为数据。在下一层的角度看,从上一层收到的包全部都被认为是本层的数据。

数据包首部
网络中传输的数据包由两部分组成:一部分是协议所要用到的首部,另一部分是上一层传过来的数据。首部的结构由协议的具体规范详细定义。在数据包的首部,明确标明了协议应该如何读取数据。反过来说,看到首部,也就能够了解该协议必要的信息以及所要处理的数据。包首部就像协议的脸。

3. 数据处理流程

下图以用户 a 向用户 b 发送邮件为例子:

数据处理流程

  • ① 应用程序处理
    首先应用程序会进行编码处理,这些编码相当于 OSI 的表示层功能;
    编码转化后,邮件不一定马上被发送出去,这种何时建立通信连接何时发送数据的管理功能,相当于 OSI 的会话层功能。

  • ② TCP 模块的处理
    TCP 根据应用的指示,负责建立连接、发送数据以及断开连接。TCP 提供将应用层发来的数据顺利发送至对端的可靠传输。为了实现这一功能,需要在应用层数据的前端附加一个 TCP 首部。

  • ③ IP 模块的处理
    IP 将 TCP 传过来的 TCP 首部和 TCP 数据合起来当做自己的数据,并在 TCP 首部的前端加上自己的 IP 首部。IP 包生成后,参考路由控制表决定接受此 IP 包的路由或主机。

  • ④ 网络接口(以太网驱动)的处理
    从 IP 传过来的 IP 包对于以太网来说就是数据。给这些数据附加上以太网首部并进行发送处理,生成的以太网数据包将通过物理层传输给接收端。

  • ⑤ 网络接口(以太网驱动)的处理
    主机收到以太网包后,首先从以太网包首部找到 MAC 地址判断是否为发送给自己的包,若不是则丢弃数据。
    如果是发送给自己的包,则从以太网包首部中的类型确定数据类型,再传给相应的模块,如 IP、ARP 等。这里的例子则是 IP 。

  • ⑥ IP 模块的处理
    IP 模块接收到 数据后也做类似的处理。从包首部中判断此 IP 地址是否与自己的 IP 地址匹配,如果匹配则根据首部的协议类型将数据发送给对应的模块,如 TCP、UDP。这里的例子则是 TCP。
    另外吗,对于有路由器的情况,接收端地址往往不是自己的地址,此时,需要借助路由控制表,在调查应该送往的主机或路由器之后再进行转发数据。

  • ⑦ TCP 模块的处理
    在 TCP 模块中,首先会计算一下校验和,判断数据是否被破坏。然后检查是否在按照序号接收数据。最后检查端口号,确定具体的应用程序。数据被完整地接收以后,会传给由端口号识别的应用程序。

  • ⑧ 应用程序的处理
    接收端应用程序会直接接收发送端发送的数据。通过解析数据,展示相应的内容。

    三、传输层中的 TCP 和 UDP

    TCP/IP 中有两个具有代表性的传输层协议,分别是 TCP 和 UDP。

  • TCP 是面向连接的、可靠的流协议。流就是指不间断的数据结构,当应用程序采用 TCP 发送消息时,虽然可以保证发送的顺序,但还是犹如没有任何间隔的数据流发送给接收端。TCP 为提供可靠性传输,实行“顺序控制”或“重发控制”机制。此外还具备“流控制(流量控制)”、“拥塞控制”、提高网络利用率等众多功能。

  • UDP 是不具有可靠性的数据报协议。细微的处理它会交给上层的应用去完成。在 UDP 的情况下,虽然可以确保发送消息的大小,却不能保证消息一定会到达。因此,应用有时会根据自己的需要进行重发处理。

  • TCP 和 UDP 的优缺点无法简单地、绝对地去做比较:TCP 用于在传输层有必要实现可靠传输的情况;而在一方面,UDP 主要用于那些对高速传输和实时性有较高要求的通信或广播通信。TCP 和 UDP 应该根据应用的目的按需使用。

    1. 端口号

    数据链路和 IP 中的地址,分别指的是 MAC 地址和 IP 地址。前者用来识别同一链路中不同的计算机,后者用来识别 TCP/IP 网络中互连的主机和路由器。在传输层也有这种类似于地址的概念,那就是端口号。端口号用来识别同一台计算机中进行通信的不同应用程序。因此,它也被称为程序地址。

1.1 根据端口号识别应用

一台计算机上同时可以运行多个程序。传输层协议正是利用这些端口号识别本机中正在进行通信的应用程序,并准确地将数据传输。

通过端口号识别应用

1.2 通过 IP 地址、端口号、协议号进行通信识别

仅凭目标端口号识别某一个通信是远远不够的。

通过端口号、IP地址、协议号进行通信识别
① 和② 的通信是在两台计算机上进行的。它们的目标端口号相同,都是80。这里可以根据源端口号加以区分。
③ 和 ① 的目标端口号和源端口号完全相同,但它们各自的源 IP 地址不同。
此外,当 IP 地址和端口号全都一样时,我们还可以通过协议号来区分(TCP 和 UDP)。

1.3 端口号的确定

标准既定的端口号:这种方法也叫静态方法。它是指每个应用程序都有其指定的端口号。但并不是说可以随意使用任何一个端口号。例如 HTTP、FTP、TELNET 等广为使用的应用协议中所使用的端口号就是固定的。这些端口号被称为知名端口号,分布在 01023 之间;除知名端口号之外,还有一些端口号被正式注册,它们分布在 102449151 之间,不过这些端口号可用于任何通信用途。
时序分配法:服务器有必要确定监听端口号,但是接受服务的客户端没必要确定端口号。在这种方法下,客户端应用程序完全可以不用自己设置端口号,而全权交给操作系统进行分配。动态分配的端口号范围在 49152~65535 之间。

1.4 端口号与协议

端口号由其使用的传输层协议决定。因此,不同的传输层协议可以使用相同的端口号。
此外,那些知名端口号与传输层协议并无关系。只要端口一致都将分配同一种应用程序进行处理。

2. UDP

  • UDP 不提供复杂的控制机制,利用 IP 提供面向无连接的通信服务。
  • 并且它是将应用程序发来的数据在收到的那一刻,立即按照原样发送到网络上的一种机制。即使是出现网络拥堵的情况,UDP 也无法进行流量控制等避免网络拥塞行为。
  • 此外,传输途中出现丢包,UDP 也不负责重发。
  • 甚至当包的到达顺序出现乱序时也没有纠正的功能。
  • 如果需要以上的细节控制,不得不交由采用 UDP 的应用程序去处理。
  • UDP 常用于一下几个方面:1.包总量较少的通信(DNS、SNMP等);2.视频、音频等多媒体通信(即时通信);3.限定于 LAN 等特定网络中的应用通信;4.广播通信(广播、多播)。

    3. TCP

    TCP 与 UDP 的区别相当大。它充分地实现了数据传输时各种控制功能,可以进行丢包时的重发控制,还可以对次序乱掉的分包进行顺序控制。而这些在 UDP 中都没有。
    此外,TCP 作为一种面向有连接的协议,只有在确认通信对端存在时才会发送数据,从而可以控制通信流量的浪费。
    根据 TCP 的这些机制,在 IP 这种无连接的网络上也能够实现高可靠性的通信( 主要通过检验和、序列号、确认应答、重发控制、连接管理以及窗口控制等机制实现)。
    3.1 三次握手(重点)
  • TCP 提供面向有连接的通信传输。面向有连接是指在数据通信开始之前先做好两端之间的准备工作。
  • 所谓三次握手是指建立一个 TCP 连接时需要客户端和服务器端总共发送三个包以确认连接的建立。在socket编程中,这一过程由客户端执行connect来触发。
    下面来看看三次握手的流程图:

三次握手

  • 第一次握手:客户端将标志位SYN置为1,随机产生一个值seq=J,并将该数据包发送给服务器端,客户端进入SYN_SENT状态,等待服务器端确认。
  • 第二次握手:服务器端收到数据包后由标志位SYN=1知道客户端请求建立连接,服务器端将标志位SYN和ACK都置为1,ack=J+1,随机产生一个值seq=K,并将该数据包发送给客户端以确认连接请求,服务器端进入SYN_RCVD状态。
  • 第三次握手:客户端收到确认后,检查ack是否为J+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=K+1,并将该数据包发送给服务器端,服务器端检查ack是否为K+1,ACK是否为1,如果正确则连接建立成功,客户端和服务器端进入ESTABLISHED状态,完成三次握手,随后客户端与服务器端之间可以开始传输数据了。
    3.2 四次挥手(重点)
  • 四次挥手即终止TCP连接,就是指断开一个TCP连接时,需要客户端和服务端总共发送4个包以确认连接的断开。在socket编程中,这一过程由客户端或服务端任一方执行close来触发。
  • 由于TCP连接是全双工的,因此,每个方向都必须要单独进行关闭,这一原则是当一方完成数据发送任务后,发送一个FIN来终止这一方向的连接,收到一个FIN只是意味着这一方向上没有数据流动了,即不会再收到数据了,但是在这个TCP连接上仍然能够发送数据,直到这一方向也发送了FIN。首先进行关闭的一方将执行主动关闭,而另一方则执行被动关闭。

下面来看看四次挥手的流程图:

四次挥手

  • 中断连接端可以是客户端,也可以是服务器端。
  • 第一次挥手:客户端发送一个FIN=M,用来关闭客户端到服务器端的数据传送,客户端进入FIN_WAIT_1状态。意思是说”我客户端没有数据要发给你了”,但是如果你服务器端还有数据没有发送完成,则不必急着关闭连接,可以继续发送数据。
  • 第二次挥手:服务器端收到FIN后,先发送ack=M+1,告诉客户端,你的请求我收到了,但是我还没准备好,请继续你等我的消息。这个时候客户端就进入FIN_WAIT_2 状态,继续等待服务器端的FIN报文。
  • 第三次挥手:当服务器端确定数据已发送完成,则向客户端发送FIN=N报文,告诉客户端,好了,我这边数据发完了,准备好关闭连接了。服务器端进入LAST_ACK状态。
  • 第四次挥手:客户端收到FIN=N报文后,就知道可以关闭连接了,但是他还是不相信网络,怕服务器端不知道要关闭,所以发送ack=N+1后进入TIME_WAIT状态,如果Server端没有收到ACK则可以重传。服务器端收到ACK后,就知道可以断开连接了。客户端等待了2MSL后依然没有收到回复,则证明服务器端已正常关闭,那好,我客户端也可以关闭连接了。最终完成了四次握手。
    上面是一方主动关闭,另一方被动关闭的情况,实际中还会出现同时发起主动关闭的情况,
    具体流程如下图:
    同时挥手

    3.3 通过序列号与确认应答提高可靠性

  • 在 TCP 中,当发送端的数据到达接收主机时,接收端主机会返回一个已收到消息的通知。这个消息叫做确认应答(ACK)。当发送端将数据发出之后会等待对端的确认应答。如果有确认应答,说明数据已经成功到达对端。反之,则数据丢失的可能性很大。
  • 在一定时间内没有等待到确认应答,发送端就可以认为数据已经丢失,并进行重发。由此,即使产生了丢包,仍然能够保证数据能够到达对端,实现可靠传输。
  • 未收到确认应答并不意味着数据一定丢失。也有可能是数据对方已经收到,只是返回的确认应答在途中丢失。这种情况也会导致发送端误以为数据没有到达目的地而重发数据。
  • 此外,也有可能因为一些其他原因导致确认应答延迟到达,在源主机重发数据以后才到达的情况也屡见不鲜。此时,源主机只要按照机制重发数据即可。
  • 对于目标主机来说,反复收到相同的数据是不可取的。为了对上层应用提供可靠的传输,目标主机必须放弃重复的数据包。为此我们引入了序列号。
  • 序列号是按照顺序给发送数据的每一个字节(8位字节)都标上号码的编号。接收端查询接收数据 TCP 首部中的序列号和数据的长度,将自己下一步应该接收的序列号作为确认应答返送回去。通过序列号和确认应答号,TCP 能够识别是否已经接收数据,又能够判断是否需要接收,从而实现可靠传输。
    序列号和确认应答

    3.4 重发超时的确定

  • 重发超时是指在重发数据之前,等待确认应答到来的那个特定时间间隔。如果超过这个时间仍未收到确认应答,发送端将进行数据重发。最理想的是,找到一个最小时间,它能保证“确认应答一定能在这个时间内返回”。
  • TCP 要求不论处在何种网络环境下都要提供高性能通信,并且无论网络拥堵情况发生何种变化,都必须保持这一特性。为此,它在每次发包时都会计算往返时间及其偏差。将这个往返时间和偏差时间相加,重发超时的时间就是比这个总和要稍大一点的值。
  • 在 BSD 的 Unix 以及 Windows 系统中,超时都以0.5秒为单位进行控制,因此重发超时都是0.5秒的整数倍。不过,最初其重发超时的默认值一般设置为6秒左右。
  • 数据被重发之后若还是收不到确认应答,则进行再次发送。此时,等待确认应答的时间将会以2倍、4倍的指数函数延长。
  • 此外,数据也不会被无限、反复地重发。达到一定重发次数之后,如果仍没有任何确认应答返回,就会判断为网络或对端主机发生了异常,强制关闭连接。并且通知应用通信异常强行终止。

    3.5 以段为单位发送数据

    在建立 TCP 连接的同时,也可以确定发送数据包的单位,我们也可以称其为“最大消息长度”(MSS)。最理想的情况是,最大消息长度正好是 IP 中不会被分片处理的最大数据长度。
    TCP 在传送大量数据时,是以 MSS 的大小将数据进行分割发送。进行重发时也是以 MSS 为单位。
    MSS 在三次握手的时候,在两端主机之间被计算得出。两端的主机在发出建立连接的请求时,会在 TCP 首部中写入 MSS 选项,告诉对方自己的接口能够适应的 MSS 的大小。然后会在两者之间选择一个较小的值投入使用。

3.6 利用窗口控制提高速度

  • TCP 以1个段为单位,每发送一个段进行一次确认应答的处理。这样的传输方式有一个缺点,就是包的往返时间越长通信性能就越低。

  • 为解决这个问题,TCP 引入了窗口这个概念。确认应答不再是以每个分段,而是以更大的单位进行确认,转发时间将会被大幅地缩短。也就是说,发送端主机,在发送了一个段以后不必要一直等待确认应答,而是继续发送。如下图所示:

窗口控制

  • 窗口大小就是指无需等待确认应答而可以继续发送数据的最大值。上图中窗口大小为4个段。这个机制实现了使用大量的缓冲区,通过对多个段同时进行确认应答的功能。

3.7 滑动窗口控制

滑动窗口

  • 上图中的窗口内的数据即便没有收到确认应答也可以被发送出去。不过,在整个窗口的确认应答没有到达之前,如果其中部分数据出现丢包,那么发送端仍然要负责重传。为此,发送端主机需要设置缓存保留这些待被重传的数据,直到收到他们的确认应答。

  • 在滑动窗口以外的部分包括未发送的数据以及已经确认对端已收到的数据。当数据发出后若如期收到确认应答就可以不用再进行重发,此时数据就可以从缓存区清除。

  • 收到确认应答的情况下,将窗口滑动到确认应答中的序列号的位置。这样可以顺序地将多个段同时发送提高通信性能。这种机制也别称为滑动窗口控制。

    3.8 窗口控制中的重发控制

    在使用窗口控制中, 出现丢包一般分为两种情况:

  • ① 确认应答未能返回的情况。在这种情况下,数据已经到达对端,是不需要再进行重发的,如下图:
    部分确认应答丢失

  • ② 某个报文段丢失的情况。接收主机如果收到一个自己应该接收的序列号以外的数据时,会针对当前为止收到数据返回确认应答。如下图所示,当某一报文段丢失后,发送端会一直收到序号为1001的确认应答,因此,在窗口比较大,又出现报文段丢失的情况下,同一个序列号的确认应答将会被重复不断地返回。而发送端主机如果连续3次收到同一个确认应答,就会将其对应的数据进行重发。这种机制比之前提到的超时管理更加高效,因此也被称为高速重发控制。
    高速重发控制

    四、网络层中的 IP 协议

  • IP(IPv4、IPv6)相当于 OSI 参考模型中的第3层——网络层。网络层的主要作用是“实现终端节点之间的通信”。这种终端节点之间的通信也叫“点对点通信”。

  • 网络的下一层——数据链路层的主要作用是在互连同一种数据链路的节点之间进行包传递。而一旦跨越多种数据链路,就需要借助网络层。网络层可以跨越不同的数据链路,即使是在不同的数据链路上也能实现两端节点之间的数据包传输。

  • IP 大致分为三大作用模块,它们是 IP 寻址、路由(最终节点为止的转发)以及 IP 分包与组包。

    1. IP 地址

    1.1 IP 地址概述
  • 在计算机通信中,为了识别通信对端,必须要有一个类似于地址的识别码进行标识。在数据链路中的 MAC 地址正是用来标识同一个链路中不同计算机的一种识别码。

  • 作为网络层的 IP ,也有这种地址信息,一般叫做 IP 地址。IP 地址用于在“连接到网络中的所有主机中识别出进行通信的目标地址”。因此,在 TCP/IP 通信中所有主机或路由器必须设定自己的 IP 地址。

  • 不论一台主机与哪种数据链路连接,其 IP 地址的形式都保持不变。

  • IP 地址(IPv4 地址)由32位正整数来表示。IP 地址在计算机内部以二进制方式被处理。然而,由于我们并不习惯于采用二进制方式,我们将32位的 IP 地址以每8位为一组,分成4组,每组以 “.” 隔开,再将每组数转换成十进制数。如下:
    28 28 28 28
    10101100 00010100 00000001 00000001 (2进制)

      1. 00000001 (2进制)
      1. 1 (10进制)
        1.2 IP 地址由网络和主机两部分标识组成
  • 如下图,网络标识在数据链路的每个段配置不同的值。网络标识必须保证相互连接的每个段的地址不相重复。而相同段内相连的主机必须有相同的网络地址。IP 地址的“主机标识”则不允许在同一个网段内重复出现。由此,可以通过设置网络地址和主机地址,在相互连接的整个网络中保证每台主机的 IP 地址都不会相互重叠。即 IP 地址具有了唯一性。
    IP地址的主机标识
  • 如下图,IP 包被转发到途中某个路由器时,正是利用目标 IP 地址的网络标识进行路由。因为即使不看主机标识,只要一见到网络标识就能判断出是否为该网段内的主机。
    IP地址的网络标识
    1.3 IP 地址的分类
  • IP 地址分为四个级别,分别为A类、B类、C类、D类。它根据 IP 地址中从第 1 位到第 4 位的比特列对其网络标识和主机标识进行区分。
  • A 类 IP 地址是首位以 “0” 开头的地址。从第 1 位到第 8 位是它的网络标识。用十进制表示的话,0.0.0.0~127.0.0.0 是 A 类的网络地址。A 类地址的后 24 位相当于主机标识。因此,一个网段内可容纳的主机地址上限为16,777,214个。
  • B 类 IP 地址是前两位 “10” 的地址。从第 1 位到第 16 位是它的网络标识。用十进制表示的话,128.0.0.0~191.255.0.0 是 B 类的网络地址。B 类地址的后 16 位相当于主机标识。因此,一个网段内可容纳的主机地址上限为65,534个。
  • C 类 IP 地址是前三位为 “110” 的地址。从第 1 位到第 24 位是它的网络标识。用十进制表示的话,192.0.0.0~223.255.255.0 是 C 类的网络地址。C 类地址的后 8 位相当于主机标识。因此,一个网段内可容纳的主机地址上限为254个。
  • D 类 IP 地址是前四位为 “1110” 的地址。从第 1 位到第 32 位是它的网络标识。用十进制表示的话,224.0.0.0~239.255.255.255 是 D 类的网络地址。D 类地址没有主机标识,常用于多播。
  • 在分配 IP 地址时关于主机标识有一点需要注意。即要用比特位表示主机地址时,不可以全部为 0 或全部为 1。因为全部为 0 只有在表示对应的网络地址或 IP 地址不可以获知的情况下才使用。而全部为 1 的主机通常作为广播地址。因此,在分配过程中,应该去掉这两种情况。这也是为什么 C 类地址每个网段最多只能有 254( 28 - 2 = 254)个主机地址的原因。
    1.4 广播地址
  • 广播地址用于在同一个链路中相互连接的主机之间发送数据包。将 IP 地址中的主机地址部分全部设置为 1,就成了广播地址。
  • 广播分为本地广播和直接广播两种。在本网络内的广播叫做本地广播;在不同网络之间的广播叫做直接广播。
    1.5 IP 多播
  • 多播用于将包发送给特定组内的所有主机。由于其直接使用 IP 地址,因此也不存在可靠传输。
  • 相比于广播,多播既可以穿透路由器,又可以实现只给那些必要的组发送数据包。请看下图:

IP 多播

  • 多播使用 D 类地址。因此,如果从首位开始到第 4 位是 “1110”,就可以认为是多播地址。而剩下的 28 位可以成为多播的组编号。
  • 此外, 对于多播,所有的主机(路由器以外的主机和终端主机)必须属于 224.0.0.1 的组,所有的路由器必须属于 224.0.0.2 的组。
    1.6 子网掩码
  • 现在一个 IP 地址的网络标识和主机标识已不再受限于该地址的类别,而是由一个叫做“子网掩码”的识别码通过子网网络地址细分出比 A 类、B 类、C 类更小粒度的网络。这种方式实际上就是将原来 A 类、B 类、C 类等分类中的主机地址部分用作子网地址,可以将原网络分为多个物理网络的一种机制。
  • 子网掩码用二进制方式表示的话,也是一个 32 位的数字。它对应 IP 地址网络标识部分的位全部为 “1”,对应 IP 地址主机标识的部分则全部为 “0”。由此,一个 IP 地址可以不再受限于自己的类别,而是可以用这样的子网掩码自由地定位自己的网络标识长度。当然,子网掩码必须是 IP 地址的首位开始连续的 “1”。
  • 对于子网掩码,目前有两种表示方式。第一种是,将 IP 地址与子网掩码的地址分别用两行来表示。以 172.20.100.52 的前 26 位是网络地址的情况为例,如下:
    IP 地址 172. 20. 100. 52
    子网掩码 255. 255. 255. 192
    网络地址 172. 20. 100. 0
    子网掩码 255. 255. 255. 192
    广播地址 172. 20. 100. 63
    子网掩码 255. 255. 255. 192
  • 第二种表示方式是,在每个 IP 地址后面追加网络地址的位数用 “/ ” 隔开,如下:
    IP 地址 172. 20. 100. 52 / 26
    网络地址 172. 20. 100. 0 / 26
    广播地址 172. 20. 100. 63 / 26
  • 另外,在第二种方式下记述网络地址时可以省略后面的 “0” 。例如:172.20.0.0/26 跟 172.20/26 其实是一个意思。

    2. 路由

  • 发送数据包时所使用的地址是网络层的地址,即 IP 地址。然而仅仅有 IP 地址还不足以实现将数据包发送到对端目标地址,在数据发送过程中还需要类似于“指明路由器或主机”的信息,以便真正发往目标地址。保存这种信息的就是路由控制表。
  • 该路由控制表的形成方式有两种:一种是管理员手动设置,另一种是路由器与其他路由器相互交换信息时自动刷新。前者也叫做静态路由控制,而后者叫做动态路由控制。
  • IP 协议始终认为路由表是正确的。然后,IP 本身并没有定义制作路由控制表的协议。即 IP 没有制作路由控制表的机制。该表示由一个叫做“路由协议”的协议制作而成。
    2.1 IP 地址与路由控制
  • IP 地址的网络地址部分用于进行路由控制。
  • 路由控制表中记录着网络地址与下一步应该发送至路由器的地址。
  • 在发送 IP 包时,首先要确定 IP 包首部中的目标地址,再从路由控制表中找到与该地址具有相同网络地址的记录,根据该记录将 IP 包转发给相应的下一个路由器。如果路由控制表中存在多条相同网络地址的记录,就选择一个最为吻合的网络地址。
    路由控制表与 IP 包发送

    3. IP 分包与组包

  • 每种数据链路的最大传输单元(MTU)都不尽相同,因为每个不同类型的数据链路的使用目的不同。使用目的不同,可承载的 MTU 也就不同。
  • 任何一台主机都有必要对 IP 分片进行相应的处理。分片往往在网络上遇到比较大的报文无法一下子发送出去时才会进行处理。
  • 经过分片之后的 IP 数据报在被重组的时候,只能由目标主机进行。路由器虽然做分片但不会进行重组。
    3.1 路径 MTU 发现
  • 分片机制也有它的不足。如路由器的处理负荷加重之类。因此,只要允许,是不希望由路由器进行 IP 数据包的分片处理的。
  • 为了应对分片机制的不足,“路径 MTU 发现” 技术应运而生。路径 MTU 指的是,从发送端主机到接收端主机之间不需要分片是最大 MTU 的大小。即路径中存在的所有数据链路中最小的 MTU 。
  • 进行路径 MTU 发现,就可以避免在中途的路由器上进行分片处理,也可以在 TCP 中发送更大的包。

    4. IPv6

  • IPv6(IP version 6)是为了根本解决 IPv4 地址耗尽的问题而被标准化的网际协议。IPv4 的地址长度为 4 个 8 位字节,即 32 比特。而 IPv6 的地址长度则是原来的 4 倍,即 128 比特,一般写成 8 个 16 位字节。
    4.1 IPv6 的特点
  • IP 得知的扩大与路由控制表的聚合。
  • 性能提升。包首部长度采用固定的值(40字节),不再采用首部检验码。简化首部结构,减轻路由器负担。路由器不再做分片处理。
  • 支持即插即用功能。即使没有DHCP服务器也可以实现自动分配 IP 地址。
  • 采用认证与加密功能。应对伪造 IP 地址的网络安全功能以及防止线路窃听的功能。
  • 多播、Mobile IP 成为扩展功能。
    4.2 IPv6 中 IP 地址的标记方法
  • 一般人们将 128 比特 IP 地址以每 16 比特为一组,每组用冒号(“:”)隔开进行标记。
  • 而且如果出现连续的 0 时还可以将这些 0 省略,并用两个冒号(“::”)隔开。但是,一个 IP 地址中只允许出现一次两个连续的冒号。
    4.3 IPv6 地址的结构
  • IPv6 类似 IPv4,也是通过 IP 地址的前几位标识 IP 地址的种类。
  • 在互联网通信中,使用一种全局的单播地址。它是互联网中唯一的一个地址,不需要正式分配 IP 地址。
    未定义 0000 … 0000(128比特) ::/ 128
    环回地址 0000 … 0001(128比特) ::1 / 128
    唯一本地地址 1111 110 FC00:/ 7
    链路本地单播地址 1111 1110 10 FE80::/ 10
    多播地址 1111 1111 FF00::/ 8
    全局单播地址 (其他)
    4.4 全局单播地址
  • 全局单播地址是指世界上唯一的一个地址。它是互联网通信以及各个域内部通信中最为常用的一个 IPv6 地址。
  • 格式如下图所示,现在 IPv6 的网络中所使用的格式为,n = 48,m = 16 以及 128 - n - m = 64。即前 64 比特为网络标识,后 64 比特为主机标识。
    全局单播地址
    4.5 链路本地单播地址
  • 链路本地单播地址是指在同一个数据链路内唯一的地址。它用于不经过路由器,在同一个链路中的通信。通常接口 ID 保存 64 比特版的 MAC 地址。
    链路本地单播地址
    4.6 唯一本地地址
  • 唯一本地地址是不进行互联网通信时所用的地址。
  • 唯一本地地址虽然不会与互联网连接,但是也会尽可能地随机生成一个唯一的全局 ID。
  • L 通常被置为 1
  • 全局 ID 的值随机决定
  • 子网 ID 是指该域子网地址
  • 接口 ID 即为接口的 ID
    唯一本地地址
    4.7 IPv6 分段处理
  • IPv6 的分片处理只在作为起点的发送端主机上进行,路由器不参与分片。
  • IPv6 中最小 MTU 为 1280 字节,因此,在嵌入式系统中对于那些有一定系统资源限制的设备来说,不需要进行“路径 MTU 发现”,而是在发送 IP 包时直接以 1280 字节为单位分片送出。
    4.8 IP 首部(暂略)

    5. IP 协议相关技术

  • IP 旨在让最终目标主机收到数据包,但是在这一过程中仅仅有 IP 是无法实现通信的。必须还有能够解析主机名称和 MAC 地址的功能,以及数据包在发送过程中异常情况处理的功能。
    5.1 DNS
  • 我们平常在访问某个网站时不适用 IP 地址,而是用一串由罗马字和点号组成的字符串。而一般用户在使用 TCP/IP 进行通信时也不使用 IP 地址。能够这样做是因为有了 DNS (Domain Name System)功能的支持。DNS 可以将那串字符串自动转换为具体的 IP 地址。
  • 这种 DNS 不仅适用于 IPv4,还适用于 IPv6。
    5.2 ARP
  • 只要确定了 IP 地址,就可以向这个目标地址发送 IP 数据报。然而,在底层数据链路层,进行实际通信时却有必要了解每个 IP 地址所对应的 MAC 地址。
  • ARP 是一种解决地址问题的协议。以目标 IP 地址为线索,用来定位下一个应该接收数据分包的网络设备对应的 MAC 地址。不过 ARP 只适用于 IPv4,不能用于 IPv6。IPv6 中可以用 ICMPv6 替代 ARP 发送邻居探索消息。
  • RARP 是将 ARP 反过来,从 MAC 地址定位 IP 地址的一种协议。
    5.3 ICMP
  • ICMP 的主要功能包括,确认 IP 包是否成功送达目标地址,通知在发送过程当中 IP 包被废弃的具体原因,改善网络设置等。
  • IPv4 中 ICMP 仅作为一个辅助作用支持 IPv4。也就是说,在 IPv4 时期,即使没有 ICMP,仍然可以实现 IP 通信。然而,在 IPv6 中,ICMP 的作用被扩大,如果没有 ICMPv6,IPv6 就无法进行正常通信。
    5.4 DHCP
  • 如果逐一为每一台主机设置 IP 地址会是非常繁琐的事情。特别是在移动使用笔记本电脑、只能终端以及平板电脑等设备时,每移动到一个新的地方,都要重新设置 IP 地址。
  • 于是,为了实现自动设置 IP 地址、统一管理 IP 地址分配,就产生了 DHCP(Dynamic Host Configuration Protocol)协议。有了 DHCP,计算机只要连接到网络,就可以进行 TCP/IP 通信。也就是说,DHCP 让即插即用变得可能。
  • DHCP 不仅在 IPv4 中,在 IPv6 中也可以使用。
    5.5 NAT
  • NAT(Network Address Translator)是用于在本地网络中使用私有地址,在连接互联网时转而使用全局 IP 地址的技术。
  • 除转换 IP 地址外,还出现了可以转换 TCP、UDP 端口号的 NAPT(Network Address Ports Translator)技术,由此可以实现用一个全局 IP 地址与多个主机的通信。
  • NAT(NAPT)实际上是为正在面临地址枯竭的 IPv4 而开发的技术。不过,在 IPv6 中为了提高网络安全也在使用 NAT,在 IPv4 和 IPv6 之间的相互通信当中常常使用 NAT-PT。
    5.6 IP 隧道
    夹着 IPv4 网络的两个 IPv6 网络
  • 如上图的网络环境中,网络 A 与网络 B 之间无法直接进行通信,为了让它们之间正常通信,这时必须得采用 IP 隧道的功能。
  • IP 隧道可以将那些从网络 A 发过来的 IPv6 的包统合为一个数据,再为之追加一个 IPv4 的首部以后转发给网络 C。
  • 一般情况下,紧接着 IP 首部的是 TCP 或 UDP 的首部。然而,现在的应用当中“ IP 首部的后面还是 IP 首部”或者“ IP 首部的后面是 IPv6 的首部”等情况与日俱增。这种在网络层的首部后面追加网络层首部的通信方法就叫做“ IP 隧道”。

作者:涤生_Woo
链接:https://www.jianshu.com/p/9f3e879a4c9c

bpi-m3折腾记

0x00 前言

手里有一个bpi-m3一直在吃灰,原因是不会捣鼓,后来有点基础这。拿出来做个服务器系统用一下。我的bpi-m3是在咸鱼上淘的,花费450RMB。这个板子新的也就是这个价格为什么不买新的呢。

当时这样考虑的:

1.我买新的不会用,买破的可以咨询有经验的师傅,最起码他是玩过的。

2.这个板子是他扩容的,这是最打动我的地方,原板子只有8g内存。他给扩容成64g了。而且还有保护壳。如果总体算下来新的话少不了五六百了。

3.说句后话曾经我也想卖掉的,但没有收的。只能压在自己手里。


以上纯属闲扯淡可略过

本来是想装ubuntu的可以是香蕉派社区一直没更新。没有最新的ubuntu镜像源。里面能用的最新的是,ubuntu16.04。而16.04的更新源我一直没有找到可以用的。
最后只能折腾debian。debian比较稳定。里面最新的是debian9.4.

开始吧

1.bpi-m3烧录方法

2.bpi-m3镜像下载

配置

1.烧录成功之后需要解决最大的问题就是联网,
插上网线直接能链接网络了。这个不用担心。

2.更新源,ubuntu16.04之所以放弃就是因为找不到合适的更新源。

  • 首先查看debian版本lsb_release -a
  • 然后根据debian版本找对应的更新源(我的版是9.4的)
  • 首先用http协议的源。https的源暂时不能用。
    http更新源
    deb http://ftp.cn.debian.org/debian/ stretch main
    deb http://ftp.cn.debian.org/debian/ stretch-updates main
    deb http://ftp.cn.debian.org/debian-security stretch/updates main

sudo apt update

sudo apt upgrade

安装https协议

sudo apt install apt-transport-https

默认注释了源码镜像以提高 apt update 速度,如有需要可自行取消注释
1
2
3
4
5
6
7
8
deb https://mirrors.tuna.tsinghua.edu.cn/debian/ buster main contrib non-free
# deb-src https://mirrors.tuna.tsinghua.edu.cn/debian/ buster main contrib non-free
deb https://mirrors.tuna.tsinghua.edu.cn/debian/ buster-updates main contrib non-free
# deb-src https://mirrors.tuna.tsinghua.edu.cn/debian/ buster-updates main contrib non-free
deb https://mirrors.tuna.tsinghua.edu.cn/debian/ buster-backports main contrib non-free
# deb-src https://mirrors.tuna.tsinghua.edu.cn/debian/ buster-backports main contrib non-free
deb https://mirrors.tuna.tsinghua.edu.cn/debian-security buster/updates main contrib non-free
# deb-src https://mirrors.tuna.tsinghua.edu.cn/debian-security buster/updates main contrib non-free

换成个清华源

然后再更新,先写到这吧。有了源其他的好操作了。

come on

centos安装LANMP

一,LANMP是什么?

LANMP是linux下Apache,Nginx,MySQL和PHP的应用环境。具体自行了解。

二,下载安装包

wget http://dl.wdlinux.cn/files/lanmp_v3.tar.gz

三,解压下载的文件

tar zxvf lanmp_v3.tar.gz

四,运行LANMP

sh lanmp.sh

五,在kali和Ubuntu等系统会报错,系统dash兼容性不好。解决方案:

sudo dpkg-reconfigure dash

会弹出Configuring dash界面,然后选择”NO”选项。

*本来是在centos7安装的,但中间出现再多坑,没解决就只能用官方推荐的版本安装了。
反正的我的centos7没折腾好。
*CentOS 5.x系列,CentOS 6.X系列,包括32位,64位
*RedHat 5.x系列,RedHat 6.x系列,包括32位,64位
*Ubuntu 12.04,包括32位,64位

docekr环境搭建centos:7笔记

一,docker搭建略过

docekr version

查看版本号,测试是否安装成功。

二,下载镜像centos:7容器

docker pull centos:7

如果出现pull失败,大部分原因是docker源的原因

三,启动镜像centos7,如果不指定 /bin/bash,容器运行后会自动停止

docker run -d -i -t “IMAGE ID” /bin/bash

四,进入容器

docker exec -it bash

五,设置密码,并且安装ssh远程链接

yum install -y openssh-server openssh-clients net-tools vim initscripts

六,首先设置密码

输入命令 passwd -d root 清除root账号的密码;输入命令 passwd root进行修改root密码,然后重复两次输入新密码,如:123456

七,配置ssh远程配置文件

vim /etc/ssh/sshd_config

箭头的都取消 # 号

开启远程登陆
开启使用用户名密码来作为连接验证

八,备份容器

docker commit 《容器ID》 《备注》

九,查看docker备份的镜像

docker images

十,在运行的docker容器中 执行命令启动sshd

会报错:Failed to get D-Bus connection: Operation not permitted

十一,要是用systemctl 管理服务就要加上参数 –privileged 来增加权,并且不能使用默认的bash,换成 init,命令如下

docker run -d -it -p 22:22 –privileged (IMAGE ID) /usr/sbin/init

十二,以后台模式运行我再进入到容器里操作

docker exec -it (容器ID) /bin/bash

十三,开启sshd服务 systemctl restart sshd ; systemctl status sshd 检查服务状态;或者输入netstat -an | grep 22 检查 22 号端口是否开启监听。

十四, ssh root@宿主机ip -p 22

十五,安装wget

yum -y install wget

随记

最近不知道为什么对挖洞很抵触,不知道在哪里下手。捣鼓一些没用的工具。

win10 折腾Docker

前言

Docker产品指南

常用命令

1.运行docker --version以确保您具有受支持的Docker版本:

docker –version

2.在Docker Hub中拉去hello-world镜像并运行的容器:

docker run hello-world

3.列出从Docker Hub下载的hello-world映像:

docker image ls

4.删除镜像

有些镜像过时了,我们需要删除。使用如下的命令:docker rmi -f image_id ##-f:表示强制删除镜像;image_id:镜像id

5.列出hello-world 容器(显示“从Docker向您好!”后退出的容器)

docker container ls –all

6.通过运行一些帮助命令来浏览Docker帮助页面

1
2
3
4
> docker --help
> docker container --help
> docker container ls --help
> docker run --help

7.列出所有在运行的容器信息

docker ps

8.列出列出最近创建的5个容器信息。

docker ps -n 5

9.列出所有创建的容器ID。

docker ps -a -q

10.删除容器

docker rm 容器ID

Docker配置settings

1.国内镜像加速可去阿里云申请个免费的:https://cr.console.aliyun.com/cn-shenzhen/instances/repositories

注:镜像加速网上很多,但只能一条条加,不可同时加好几条。

2.更改Docker Hub下载的images的目录。

vscode使用Markdown文档编写

首先安装vscode工具,具体的使用可以参考之前的博文:《Visual Studio Code教程:基础使用和自定义设置》

VScode已经默认集成markdown文档编辑插件。
可以新建一个.md文件
Visual Studio Code 原生就支持高亮Markdown的语法,想要一边编辑一遍预览,有两种方法:
1.Ctrl + Shift + P 调出主命令框,输入 Markdown,应该会匹配到几项 Markdown相关命令

2.先按Ctrl + K,然后放掉,紧接着再按 v,也能调出实时预览框。【要在英文输入状态下】

附录:markdown语法:

1.标题
代码

注:# 后面保持空格

h1

h2

h3

h4

h5
h6

####### h7 // 错误代码

######## h8 // 错误代码

######### h9 // 错误代码

########## h10 // 错误代码
演示

h1
h2
h3
h4
h5
h6

####### h7

######## h8

######### h9

########## h10

2.分级标题
代码
注:= - 最少可以只写一个,兼容性一般

一级标题

二级标题

演示

3.TOC
注:根据标题生成目录,兼容性一般

代码

[TOC]
演示

4.引用
代码1(单行式)

hello world!
演示

hello world!

代码2(多行式)

hello world!
hello world!
hello world!
或者

hello world!
hello world!
hello world!
演示

相同的结果

hello world!
hello world!
hello world!

代码3(多层嵌套)

aaaaaaaaa

bbbbbbbbb

cccccccccc
演示

aaaaaaaaa

bbbbbbbbb

cccccccccc

5.行内标记
注:用 ` 标记代码块将变成一行

代码

标记之外hello world标记之外
演示

标记之外hello world标记之外

错误代码
注:不同平台错误略有差异

标记之外 < div> < div></div> < div></div> < div></div> < /div>标记之外
演示

6.代码块
注:与上行距离一空行

代码1(

1
2

注:用```生成块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
演示

<div>
<div></div>
<div></div>
<div></div>
</div>
代码2(Tab)

注: Tab缩进

我是文字……

<div>
<div></div>
<div></div>
<div></div>
</div>
演示

<div>
<div></div>
<div></div>
<div></div>
</div>
代码3(自定义语法)
注:根据不同的语言配置不同的代码着色

```javascript
var num = 0;
for (var i = 0; i < 5; i++) {
num+=i;
}
console.log(num);

演示

var num = 0;
for (var i = 0; i < 5; i++) {
num+=i;
}
console.log(num);
7.插入链接
代码1(内链式)
注:{:target=”_blank”}跳转方式兼容性一般 ,多数第三方平台不支持跳转

[百度1](http://www.baidu.com/" 百度一下”){:target=”_blank”}
演示

百度1

代码2(引用式)

[百度2][2]{:target=”_blank”}
[2]: http://www.baidu.com/ “百度二下”
演示

百度2

8.插入图片
代码1(内链式)

代码2(引用式)
![name][01]
[01]: ./01.png ‘描述’
9.插入图片带有链接
代码

{:target=”_blank”} // 内链式

[][5]{:target=”_blank”} // 引用式
[5]: http://www.baidu.com
10.视频插入
注:Markdown 语法是不支持直接插入视频的
普遍的做法是 插入HTML的 iframe 框架,通过网站自带的分享功能获取,如果没有可以尝试第二种方法
第二是伪造播放界面,实质是插入视频图片,然后通过点击跳转到相关页面

代码1
注:多数第三方平台不支持插入

\\ 代码2

{:target=”_blank”}

11.序表
代码1(有序)

注:序列.后 保持空格

  1. one
  2. two
  3. three
    演示

one
two
three
代码2(无序)

  • one
  • two
  • three
    演示

one
two
three
代码3(序表嵌套)

  1. one
    1. one-1
    2. two-2
  2. two
    • two-1
    • two-2
      演示

one
one-1
two-2
two
two-1
two-2
代码4(序表嵌套代码块)
注:换行+两个Tab

  • one

    var a = 10; // 与上行保持空行并 递进缩进
    演示:

one

var a = 10;
12.任务列表
注:兼容性一般 要隔开一行

代码

这是文字……

  • 选项一
  • 选项二
  • [选项3]
    演示

13.表情
注:兼容一般

表情代码地址

14.表格
注: : 代表对齐方式 ,** : 与 | 之间不要有空格**,否则对齐会有些不兼容

代码1

a b c
居中 左对齐 右对齐
========= =============== ============
演示

a b c
居中 左对齐 右对齐
========= =============== ============
代码2(简约写法)

a b c
居中 左对齐 右对齐
============ ================= =============
演示

a b c
居中 左对齐 右对齐
============ ================= =============
代码3(特殊表格)

注:一般对合并单元格,以及其他特殊格式表格,markdown 是无能为力的
所以常规的做法是使用HTML标签,但是这样的编写效率极低。
但是有了这款工具的话,所有问题都迎刃而解。

在线生成HTML代码 Tables Generator (国外的站)

Tables Generator
演示

15.支持内嵌CSS样式
代码

内联样式

演示

16.语义标记
描述 效果 代码
斜体 斜体 斜体
斜体 斜体 斜体
加粗 加粗 加粗
加粗+斜体 加粗+斜体 加粗+斜体
加粗+斜体 加粗+斜体 加粗+斜体
删除线 删除线 删除线
17.语义标签
描述 效果 代码
斜体 斜体 斜体
加粗 加粗 加粗
强调 强调 强调
上标 Za Za
下标 Za Za
键盘文本

Ctrl
换行
18.格式化文本
保持输入排版格式不变
注:对内含标签需要破坏结构才能显示

代码

hello world 
         hi
  hello world 

演示

hello world
hi
hello world

错误解决方法
注:标签内部添加空格 或者 直接使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
代码1(插入空格)

<pre>
< div>
< div>< /div>
< div>< /div>
< div>< /div>
< /div>
</pre>
演示

<pre>
< div>
< div>< /div>
< div>< /div>
< div>< /div>
< /div>
</pre>

代码2( ``` 代码块标记)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
演示

<div>
<div></div>
<div></div>
<div></div>
</div>
19.公式 {#1}
注:1个$左对齐,2个居中

代码

$$ x \href{why-equal.html}{=} y^2 + 1 $$
$ x = {-b \pm \sqrt{b^2-4ac} \over 2a}. $
演示



20.分隔符
注:最少三个 --- 或 ***或 * * *

代码

***
---
* * *
演示

21.脚注
代码

Markdown[^1]
[^1]: Markdown是一种纯文本标记语言 // 在文章最后面显示脚注
演示

Markdown[1]

22.锚点
代码
注:只有标题支持锚点, 跳转目录方括号后 保持空格

[公式标题锚点](#1)

### [需要跳转的目录] {#1} // 方括号后保持空格
演示

公式标题锚点

23.定义型列表
注:解释型定义
代码

Markdown
: 轻量级文本标记语言,可以转换成html,pdf等格式 // 开头一个`:` + `Tab` 或 四个空格

代码块定义
: 代码块定义……

var a = 10; // 保持空一行与 递进缩进
演示



24.自动邮箱链接
代码

<xxx@outlook.com>
演示

xxx@outlook.com

25.流程图
代码1

```flow // 流程
st=>start: 开始|past:> http://www.baidu.com // 开始
e=>end: 结束 // 结束
c1=>condition: 条件1:>http://www.baidu.com[_parent] // 判断条件
c2=>condition: 条件2 // 判断条件
c3=>condition: 条件3 // 判断条件
io=>inputoutput: 输出 // 输出
//----------------以上为定义参数-------------------------

//----------------以下为连接参数-------------------------
// 开始->判断条件1为no->判断条件2为no->判断条件3为no->输出->结束
st->c1(yes,right)->c2(yes,right)->c3(yes,right)->io->e
c1(no)->e // 条件1不满足->结束
c2(no)->e // 条件2不满足->结束
c3(no)->e // 条件3不满足->结束

演示

代码详解
流程图分为两个部分: 定义参数 然后 连接参数

定义示例:

tag=>type: content:>url // 形参格式
st=>start: 开始:>http://www.baidu.com[blank] //实参格式
注:** st=>start: 开始 的:后面保持空格**

形参 实参 含义
tag st 标签 (可以自定义)
=> => 赋值
type start 类型 (6种类型)
content 开始 描述内容 (可以自定义)
:>url http://www.baidu.com[blank] 链接与跳转方式 兼容性很差
6种类型 含义
start 启动
end 结束
operation 程序
subroutine 子程序
condition 条件
inputoutput 输出
连接示例:

st->c1(yes,right)->c2(yes,right)->c3(yes,right)->io->e
开始->判断条件1为no->判断条件2为no->判断条件3为no->输出->结束
形参 实参 含义
-> -> 连接
condition c1 条件
(布尔值,方向) (yes,right) 如果满足向右连接,4种方向:right ,left,up ,down 默认为:down
注:operation (程序); subroutine (子程序) ;condition (条件),都可以在括号里加入连接方向。

operation(right)
subroutine(left)
condition(yes,right) // 只有条件 才能加布尔值
代码2

注:添加样式和url跳转 需要添加第三方的脚本
实际效果很差,使用起来麻烦,意义不大

流程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
st=>start: 启动|past:>http://www.baidu.com[blank] // 开始
e=>end: 结束 // 结束
op1=>operation: 方案一 // 运算1
sub2=>subroutine: 方案二|approved:>http://www.baidu.com[_parent] // 运算2
sub3=>subroutine: 重新制定方案 // 运算2
cond1=>condition: 行不行?|request // 判断条件1
cond2=>condition: 行不行? // 判断条件2
io=>inputoutput: 结果满意 // 输出

// 开始->方案1->判断条件->
st->op1->cond1
// 判断条件1为no->方案2->判断条件2为no->重新制定方案->方案1
cond1(no,right)->sub2->cond2(no,right)->sub3(right)->op1
cond1(yes)->io->e // 判断条件满足->输出->结束
cond2(yes)->io->e // 判断条件满足->输出->结束

演示

一般普遍支持的效果

26.时序图
代码1

1
2
3
4
A->>B: 你好
Note left of A: 我在左边 // 注释方向,只有左右,没有上下
Note right of B: 我在右边
B-->A: 很高兴认识你

演示

代码详解

注:A->>B: 你好 后面可以不写文字,但是一定要在最后加上:
Note left of A 代表注释在A的左边

符号 含义

  • 实线

    实心箭头

    • 虚线

      空心箭头
      代码2

      1
      2
      3
      4
      5
      6
      7
      8
      9
      起床->吃饭: 稀饭油条
      吃饭->上班: 不要迟到了
      上班->午餐: 吃撑了
      上班->下班:
      Note right of 下班: 下班了
      下班->回家:
      Note right of 回家: 到家了
      回家-->>起床:
      Note left of 起床: 新的一天

作者:shawWey
出处: https://www.cnblogs.com/shawWey/

ubuntu安装pycharm教程

1.去官网下载pycharm安装包,选择Linux版本下载https://www.jetbrains.com/pycharm/download/#section=linux
2.安装了VMware Tools可以直接把下载的压缩包 “pycharm-professional-2018.2.3.tar” 复制到Ubuntu的Downloads文件夹中,右键点 “Extract Here” 解压
3.解压后进入bin目录下,在这个目录右键Open in Terminal,在Terminal中执行命令: sh ./pycharm.sh
4.第一次装选第二个,若重新安装的需要导入之前安装版本的配置选第一个,然后点 “OK” 确认
5.点击OK之后弹出 PyCharm Privary Policy Agreement框,隐私政策协议,直接点击Accept 同意即可
6.弹出PyCharm License Activation框,选择Activation code激活,然后复制下面的激活码点击激活MTW881U3Z5-eyJsaWNlbnNlSWQiOiJNVFc4ODFVM1o1IiwibGljZW5zZWVOYW1lIjoiTnNzIEltIiwiYXNzaWduZWVOYW1lIjoiIiwiYXNzaWduZWVFbWFpbCI6IiIsImxpY2Vuc2VSZXN0cmljdGlvbiI6IkZvciBlZHVjYXRpb25hbCB1c2Ugb25seSIsImNoZWNrQ29uY3VycmVudFVzZSI6ZmFsc2UsInByb2R1Y3RzIjpbeyJjb2RlIjoiSUkiLCJwYWlkVXBUbyI6IjIwMTktMTEtMDYifSx7ImNvZGUiOiJBQyIsInBhaWRVcFRvIjoiMjAxOS0xMS0wNiJ9LHsiY29kZSI6IkRQTiIsInBhaWRVcFRvIjoiMjAxOS0xMS0wNiJ9LHsiY29kZSI6IlBTIiwicGFpZFVwVG8iOiIyMDE5LTExLTA2In0seyJjb2RlIjoiR08iLCJwYWlkVXBUbyI6IjIwMTktMTEtMDYifSx7ImNvZGUiOiJETSIsInBhaWRVcFRvIjoiMjAxOS0xMS0wNiJ9LHsiY29kZSI6IkNMIiwicGFpZFVwVG8iOiIyMDE5LTExLTA2In0seyJjb2RlIjoiUlMwIiwicGFpZFVwVG8iOiIyMDE5LTExLTA2In0seyJjb2RlIjoiUkMiLCJwYWlkVXBUbyI6IjIwMTktMTEtMDYifSx7ImNvZGUiOiJSRCIsInBhaWRVcFRvIjoiMjAxOS0xMS0wNiJ9LHsiY29kZSI6IlBDIiwicGFpZFVwVG8iOiIyMDE5LTExLTA2In0seyJjb2RlIjoiUk0iLCJwYWlkVXBUbyI6IjIwMTktMTEtMDYifSx7ImNvZGUiOiJXUyIsInBhaWRVcFRvIjoiMjAxOS0xMS0wNiJ9LHsiY29kZSI6IkRCIiwicGFpZFVwVG8iOiIyMDE5LTExLTA2In0seyJjb2RlIjoiREMiLCJwYWlkVXBUbyI6IjIwMTktMTEtMDYifSx7ImNvZGUiOiJSU1UiLCJwYWlkVXBUbyI6IjIwMTktMTEtMDYifV0sImhhc2giOiIxMDgyODE0Ni8wIiwiZ3JhY2VQZXJpb2REYXlzIjowLCJhdXRvUHJvbG9uZ2F0ZWQiOmZhbHNlLCJpc0F1dG9Qcm9sb25nYXRlZCI6ZmFsc2V9-aKyalfjUfiV5UXfhaMGgOqrMzTYy2rnsmobL47k8tTpR/jvG6HeL3FxxleetI+W+Anw3ZSe8QAMsSxqVS4podwlQgIe7f+3w7zyAT1j8HMVlfl2h96KzygdGpDSbwTbwOkJ6/5TQOPgAP86mkaSiM97KgvkZV/2nXQHRz1yhm+MT+OsioTwxDhd/22sSGq6KuIztZ03UvSciEmyrPdl2ueJw1WuT9YmFjdtTm9G7LuXvCM6eav+BgCRm+wwtUeDfoQqigbp0t6FQgkdQrcjoWvLSB0IUgp/f4qGf254fA7lXskT2VCFdDvi0jgxLyMVct1cKnPdM6fkHnbdSXKYDWw==-MIIElTCCAn2gAwIBAgIBCTANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1KZXRQcm9maWxlIENBMB4XDTE4MTEwMTEyMjk0NloXDTIwMTEwMjEyMjk0NlowaDELMAkGA1UEBhMCQ1oxDjAMBgNVBAgMBU51c2xlMQ8wDQYDVQQHDAZQcmFndWUxGTAXBgNVBAoMEEpldEJyYWlucyBzLnIuby4xHTAbBgNVBAMMFHByb2QzeS1mcm9tLTIwMTgxMTAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxcQkq+zdxlR2mmRYBPzGbUNdMN6OaXiXzxIWtMEkrJMO/5oUfQJbLLuMSMK0QHFmaI37WShyxZcfRCidwXjot4zmNBKnlyHodDij/78TmVqFl8nOeD5+07B8VEaIu7c3E1N+e1doC6wht4I4+IEmtsPAdoaj5WCQVQbrI8KeT8M9VcBIWX7fD0fhexfg3ZRt0xqwMcXGNp3DdJHiO0rCdU+Itv7EmtnSVq9jBG1usMSFvMowR25mju2JcPFp1+I4ZI+FqgR8gyG8oiNDyNEoAbsR3lOpI7grUYSvkB/xVy/VoklPCK2h0f0GJxFjnye8NT1PAywoyl7RmiAVRE/EKwIDAQABo4GZMIGWMAkGA1UdEwQCMAAwHQYDVR0OBBYEFGEpG9oZGcfLMGNBkY7SgHiMGgTcMEgGA1UdIwRBMD+AFKOetkhnQhI2Qb1t4Lm0oFKLl/GzoRykGjAYMRYwFAYDVQQDDA1KZXRQcm9maWxlIENBggkA0myxg7KDeeEwEwYDVR0lBAwwCgYIKwYBBQUHAwEwCwYDVR0PBAQDAgWgMA0GCSqGSIb3DQEBCwUAA4ICAQAF8uc+YJOHHwOFcPzmbjcxNDuGoOUIP+2h1R75Lecswb7ru2LWWSUMtXVKQzChLNPn/72W0k+oI056tgiwuG7M49LXp4zQVlQnFmWU1wwGvVhq5R63Rpjx1zjGUhcXgayu7+9zMUW596Lbomsg8qVve6euqsrFicYkIIuUu4zYPndJwfe0YkS5nY72SHnNdbPhEnN8wcB2Kz+OIG0lih3yz5EqFhld03bGp222ZQCIghCTVL6QBNadGsiN/lWLl4JdR3lJkZzlpFdiHijoVRdWeSWqM4y0t23c92HXKrgppoSV18XMxrWVdoSM3nuMHwxGhFyde05OdDtLpCv+jlWf5REAHHA201pAU6bJSZINyHDUTB+Beo28rRXSwSh3OUIvYwKNVeoBY+KwOJ7WnuTCUq1meE6GkKc4D/cXmgpOyW/1SmBz3XjVIi/zprZ0zf3qH5mkphtg6ksjKgKjmx1cXfZAAX6wcDBNaCL+Ortep1Dh8xDUbqbBVNBL4jbiL3i3xsfNiyJgaZ5sX7i8tmStEpLbPwvHcByuf59qJhV/bZOl8KqJBETCDJcY6O2aqhTUy+9x93ThKs1GKrRPePrWPluud7ttlgtRveit/pcBrnQcXOl1rHq7ByB8CFAxNotRUYL9IF5n3wJOgkPojMy6jetQA5Ogc8Sm7RG6vg1yow==
7.安装成功
8.新建工程格式,例:工程名01_python基础,文件名:lc_01_hello.py
9.pycharm恢复初始设置:pycharm的配置信息保存在家目录下的.pycharmXXX目录下的,若要恢复初始设置,关闭当前运行的pycharm,终端中输入:rm -r .pycharmXXX。
10.卸载pycharm:第一步找到pycharm安装的目录,输入:ls -l,看到 pycharm-201XXX,再输入sudo rm -r pycharm-201XXX。第二步再删除配置目录,它是隐藏目录,在家目录输入:ls -la,看到以.开头的.pycharm201XXX,再输入: rm -r .pycharm201XXX

原文链接:https://blog.csdn.net/ML_amateur/article/details/88391521