GithubHelp home page GithubHelp logo

http's People

Contributors

sunweiguo avatar

Stargazers

 avatar

Watchers

 avatar  avatar

http's Issues

3.http的前世今生

HTTP 是基于 TCP/IP 协议的应用层协议。它不涉及数据包(packet)传输,主要规定了客户端和服务器之间的通信格式,默认使用80端口。

一、HTTP/0.9

1.1 简介

这是第一个定稿的HTTP协议。

  • 内容非常简单,只有一个命令GET
  • 没有HEADER等描述数据的信息
  • 服务器发送完毕,就关闭TCP连接(一个HTTP请求在一个TCP连接中完成)

1.2 请求格式

比如发起一个GET请求:

GET /index.html

上面命令表示,TCP 连接(connection)建立后,客户端向服务器请求(request)网页index.html。

1.3 响应格式

协议规定,服务器只能回应HTML格式的字符串,不能回应别的格式。

<html>
  <body>Hello World</body>
</html>

服务器发送完毕,就关闭TCP连接。

二、HTTP/1.0

2.1 简介

跟现在比较普遍适用的1.1版本已经相差不多。

  • 增加很多命令,比如POST、HEAD等命令
  • 增加status code 和 header
  • 多字符集支持、多部分发送、权限、缓存等

首先,任何格式的内容都可以发送。这使得互联网不仅可以传输文字,还能传输图像、视频、二进制文件。这为互联网的大发展奠定了基础。

其次,除了GET命令,还引入了POST命令和HEAD命令,丰富了浏览器与服务器的互动手段。

再次,HTTP请求和回应的格式也变了。除了数据部分,每次通信都必须包括头信息(HTTP header),用来描述一些元数据。

其他的新增功能还包括状态码(status code)、多字符集支持、多部分发送(multi-part type)、权限(authorization)、缓存(cache)、内容编码(content encoding)等。

2.2 请求格式

下面是一个1.0版的HTTP请求的例子。

GET / HTTP/1.0
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5)
Accept: */*

可以看到,这个格式与0.9版有很大变化。
第一行是请求命令,必须在尾部添加协议版本(HTTP/1.0)。后面就是多行头信息,描述客户端的情况。

客户端请求的时候,可以使用Accept字段声明自己可以接受哪些数据格式。上面代码中,客户端声明自己可以接受任何格式的数据。

2.3 响应格式

服务器的回应如下:

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

<html>
  <body>Hello World</body>
</html>

回应的格式是"头信息 + 一个空行(\r\n) + 数据"。其中,第一行是"协议版本 + 状态码(status code) + 状态描述"。

2.4 Content-Type 字段

关于字符的编码,1.0版规定,头信息必须是 ASCII 码,后面的数据可以是任何格式。因此,服务器回应的时候,必须告诉客户端,数据是什么格式,这就是Content-Type字段的作用。

2.5 缺点

每个TCP连接只能发送一个请求。发送数据完毕,连接就关闭,如果还要请求其他资源,就必须再新建一个连接。

为了解决这个问题,有些浏览器在请求时,用了一个非标准的Connection字段。

Connection: keep-alive

这个字段要求服务器不要关闭TCP连接,以便其他请求复用。服务器同样回应这个字段。

Connection: keep-alive

一个可以复用的TCP连接就建立了,直到客户端或服务器主动关闭连接。但是,这不是标准字段,不同实现的行为可能不一致,因此不是根本的解决办法。

三、HTTP/1.1

3.1 持久连接和管道机制

  • 持久连接(以前的版本中,一个HTTP请求就创建一个TCP连接,请求返回之后就关闭TCP连接,然而建立一次TCP连接的过程是比较耗时的,效率会比较低,现在建立一个TCP连接后,后面的HTTP请求都可以复用这个TCP连接,即允许了在同一个连接里面发送多个请求,会提高效率)
  • pipeline(解决了同一个TCP连接中客户端可以发送多个HTTP请求,但是对于服务端来说,对于进来的请求要按照顺序进行内容的返回,如果前一个请求处理时间长,而后一个请求处理时间端,即便后面一个请求已经处理完毕了,也要等待前一个请求处理完毕返回他才可以返回结果,这种串行的方式比较慢)

在1.1版本以前,每次HTTP请求,都会重新建立一次TCP连接,服务器响应后,就立刻关闭。众所周知,建立TCP连接的新建成本很高,因为需要三次握手,并且有着慢启动的特性导致发送速度较慢。而1.1版本添加的持久连接功能可以让一次TCP连接中发送多条HTTP请求,值得一提的是默认是,控制持久连接的Connection字段默认值是keep-alive,也就是说是默认打开持久连接,如果想要关闭,只需将该字段的值改为close。

Connection: close

而管道化则赋予了客户端在一个TCP连接中连续发送多个请求的能力,而不需要等到前一个请求响应,这大大提高了效率。值得一提的是,虽然客户端可以连续发送多个请求,但是服务器返回依然是按照发送的顺序返回。(强调的是request不需要等待上一个request的response,其实发送的request还是有顺序的,服务端按照这个顺序接收,依次返回响应)

HTTP/1.1允许多个http请求通过一个套接字同时被输出 ,而不用等待相应的响应。然后请求者就会等待各自的响应,这些响应是按照之前请求的顺序依次到达。(me:所有请求保持一个FIFO的队列,一个请求发送完之后,不必等待这个请求的响应被接受到,下一个请求就可以被再次发出;同时,服务器端返回这些请求的响应时也是按照FIFO的顺序)。管道化的表现可以大大提高页面加载的速度,尤其是在高延迟连接中。

3.2 Content-Length 字段

一个TCP连接现在可以传送多个回应,势必就要有一种机制,区分数据包是属于哪一个回应的。这就是Content-length字段的作用,声明本次回应的数据长度。

Content-Length: 3495

上面代码告诉浏览器,本次回应的长度是3495个字节,后面的字节就属于下一个回应了。

在1.0版中,Content-Length字段不是必需的,因为浏览器发现服务器关闭了TCP连接,就表明收到的数据包已经全了。

3.3 分块传输编码

对于一些很耗时的动态操作来说,这意味着,服务器要等到所有操作完成,才能发送数据,显然这样的效率不高。更好的处理方法是,产生一块数据,就发送一块,采用"流模式"(stream)取代"缓存模式"(buffer)。

因此,1.1版规定可以不使用Content-Length字段,而使用"分块传输编码"(chunked transfer encoding)。只要请求或回应的头信息有Transfer-Encoding字段,就表明回应将由数量未定的数据块组成。

Transfer-Encoding: chunked

每个非空的数据块之前,会有一个16进制的数值,表示这个块的长度。最后是一个大小为0的块,就表示本次回应的数据发送完了。下面是一个例子。

HTTP/1.1 200 OK
Content-Type: text/plain
Transfer-Encoding: chunked

25
This is the data in the first chunk

1C
and this is the second one

3
con

8
sequence

0

3.3 其他功能

1.1版还新增了许多动词方法:PUT、PATCH、HEAD、 OPTIONS、DELETE。

另外,客户端请求的头信息新增了Host字段,用来指定服务器的域名。

Host: www.example.com

有了Host字段,就可以将请求发往同一台服务器上的不同网站,为虚拟主机的兴起打下了基础。

3.4 缺点

虽然1.1版允许复用TCP连接,但是同一个TCP连接里面,所有的数据通信是按次序进行的。服务器只有处理完一个回应,才会进行下一个回应。要是前面的回应特别慢,后面就会有许多请求排队等着。这称为"队头堵塞"(Head-of-line blocking)。

四、SPDY 协议

2009年,谷歌公开了自行研发的 SPDY 协议,主要解决 HTTP/1.1 效率不高的问题。

这个协议在Chrome浏览器上证明可行以后,就被当作 HTTP/2 的基础,主要特性都在 HTTP/2 之中得到继承。

五、HTTP/2

5.1 二进制协议

HTTP/1.1 版的头信息肯定是文本(ASCII编码),数据体可以是文本,也可以是二进制。

HTTP/2 则是一个彻底的二进制协议,头信息和数据体都是二进制,并且统称为"帧"(frame):头信息帧和数据帧。

二进制协议的一个好处是,可以定义额外的帧。HTTP/2 定义了近十种帧,为将来的高级应用打好了基础。如果使用文本实现这种功能,解析数据将会变得非常麻烦,二进制解析则方便得多。

5.2 多工

HTTP/2 复用TCP连接,在一个连接里,客户端和浏览器都可以同时发送多个请求或回应,而且不用按照顺序一一对应,这样就避免了"队头堵塞"。

举例来说,在一个TCP连接里面,服务器同时收到了A请求和B请求,于是先回应A请求,结果发现处理过程非常耗时,于是就发送A请求已经处理好的部分, 接着回应B请求,完成后,再发送A请求剩下的部分。

这样双向的、实时的通信,就叫做多工(Multiplexing)。

5.3 数据流

因为 HTTP/2 的数据包是不按顺序发送的,同一个连接里面连续的数据包,可能属于不同的回应。因此,必须要对数据包做标记,指出它属于哪个回应。

HTTP/2 将每个请求或回应的所有数据包,称为一个数据流(stream)。每个数据流都有一个独一无二的编号。数据包发送的时候,都必须标记数据流ID,用来区分它属于哪个数据流。另外还规定,客户端发出的数据流,ID一律为奇数,服务器发出的,ID为偶数。

数据流发送到一半的时候,客户端和服务器都可以发送信号(RST_STREAM帧),取消这个数据流。1.1版取消数据流的唯一方法,就是关闭TCP连接。这就是说,HTTP/2 可以取消某一次请求,同时保证TCP连接还打开着,可以被其他请求使用。

客户端还可以指定数据流的优先级。优先级越高,服务器就会越早回应。

5.4 头信息压缩

HTTP 协议不带有状态,每次请求都必须附上所有信息。所以,请求的很多字段都是重复的,比如Cookie和User Agent,一模一样的内容,每次请求都必须附带,这会浪费很多带宽,也影响速度。

HTTP/2 对这一点做了优化,引入了头信息压缩机制(header compression)。一方面,头信息使用gzip或compress压缩后再发送;另一方面,客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,以后就不发送同样字段了,只发送索引号,这样就提高速度了。

5.5 服务器推送

HTTP/2 允许服务器未经请求,主动向客户端发送资源,这叫做服务器推送(server push)。

常见场景是客户端请求一个网页,这个网页里面包含很多静态资源。正常情况下,客户端必须收到网页后,解析HTML源码,发现有静态资源,再发出静态资源请求。其实,服务器可以预期到客户端请求网页后,很可能会再请求静态资源,所以就主动把这些静态资源随着网页一起发给客户端了。

整理自:http://www.ruanyifeng.com/blog/2016/08/http.html

1.从下到上看五层模型

#经典五层模型

image

下面我们先来了解一下各层做的事情!

#1.物理层

电脑要组网,第一件事要干什么?当然是先把电脑连起来,可以用光缆、电缆、双绞线、无线电波等方式。

这就叫做"物理层",它就是把电脑连接起来的物理手段。它主要规定了网络的一些电气特性,作用是负责传送0和1的电信号。

#2.数据链路层

单纯的0和1没有任何意义,必须规定解读方式:多少个电信号算一组?每个信号位有何意义?

这就是"链接层"的功能,它在"实体层"的上方,确定了0和1的分组方式。

#2.1 以太网协议

早期的时候,每家公司都有自己的电信号分组方式。逐渐地,一种叫做"以太网"(Ethernet)的协议,占据了主导地位。

以太网规定,一组电信号构成一个数据包,叫做"帧"(Frame)。每一帧分成两个部分:标头(Head)和数据(Data)。

image

"标头"包含数据包的一些说明项,比如发送者、接受者、数据类型等等;"数据"则是数据包的具体内容。

"标头"的长度,固定为18字节。"数据"的长度,最短为46字节,最长为1500字节。因此,整个"帧"最短为64字节,最长为1518字节。如果数据很长,就必须分割成多个帧进行发送。

#2.2 MAC地址

上面提到,以太网数据包的"标头",包含了发送者和接受者的信息。那么,发送者和接受者是如何标识呢?

以太网规定,连入网络的所有设备,都必须具有"网卡"接口。数据包必须是从一块网卡,传送到另一块网卡。网卡的地址,就是数据包的发送地址和接收地址,这叫做MAC地址。

每块网卡出厂的时候,都有一个全世界独一无二的MAC地址,长度是48个二进制位,通常用12个十六进制数表示。

前6个十六进制数是厂商编号,后6个是该厂商的网卡流水号。有了MAC地址,就可以定位网卡和数据包的路径了。

#2.3 广播

定义地址只是第一步,后面还有更多的步骤。

首先,一块网卡怎么会知道另一块网卡的MAC地址?

回答是有一种ARP协议,可以解决这个问题。下面介绍ARP。

其次,就算有了MAC地址,系统怎样才能把数据包准确送到接收方?

回答是以太网采用了一种很"原始"的方式,它不是把数据包准确送到接收方,而是向本网络内所有计算机发送,让每台计算机自己判断,是否为接收方。

image

上图中,1号计算机向2号计算机发送一个数据包,同一个子网络的3号、4号、5号计算机都会收到这个包。它们读取这个包的"标头",找到接收方的MAC地址,然后与自身的MAC地址相比较,如果两者相同,就接受这个包,做进一步处理,否则就丢弃这个包。这种发送方式就叫做"广播"(broadcasting)。

有了数据包的定义、网卡的MAC地址、广播的发送方式,"链接层"就可以在多台计算机之间传送数据了。

#3.网络层

以太网协议,依靠MAC地址发送数据。理论上,单单依靠MAC地址,上海的网卡就可以找到洛杉矶的网卡了,技术上是可以实现的。

但是,这样做有一个重大的缺点。以太网采用广播方式发送数据包,所有成员人手一"包",不仅效率低,而且局限在发送者所在的子网络。也就是说,如果两台计算机不在同一个子网络,广播是传不过去的。这种设计是合理的,否则互联网上每一台计算机都会收到所有包,那会引起灾难。

互联网是无数子网络共同组成的一个巨型网络,很像想象上海和洛杉矶的电脑会在同一个子网络,这几乎是不可能的。

因此,必须找到一种方法,能够区分哪些MAC地址属于同一个子网络,哪些不是。如果是同一个子网络,就采用广播方式发送,否则就采用"路由"方式发送。("路由"的意思,就是指如何向不同的子网络分发数据包,这是一个很大的主题,本文不涉及。)遗憾的是,MAC地址本身无法做到这一点。它只与厂商有关,与所处网络无关。

这就导致了"网络层"的诞生。它的作用是引进一套新的地址,使得我们能够区分不同的计算机是否属于同一个子网络。这套地址就叫做"网络地址",简称"网址"。

于是,"网络层"出现以后,每台计算机有了两种地址,一种是MAC地址,另一种是网络地址。两种地址之间没有任何联系,MAC地址是绑定在网卡上的,网络地址则是管理员分配的,它们只是随机组合在一起。

网络地址帮助我们确定计算机所在的子网络,MAC地址则将数据包送到该子网络中的目标网卡。因此,从逻辑上可以推断,必定是先处理网络地址,然后再处理MAC地址。

#3.1 IP协议

规定网络地址的协议,叫做IP协议。它所定义的地址,就被称为IP地址。

目前,广泛采用的是IP协议第四版,简称IPv4。这个版本规定,网络地址由32个二进制位组成。

习惯上,我们用分成四段的十进制数表示IP地址,从0.0.0.0一直到255.255.255.255。

互联网上的每一台计算机,都会分配到一个IP地址。这个地址分成两个部分,前一部分代表网络,后一部分代表主机。比如,IP地址172.16.254.1,这是一个32位的地址,假定它的网络部分是前24位(172.16.254),那么主机部分就是后8位(最后的那个1)。处于同一个子网络的电脑,它们IP地址的网络部分必定是相同的,也就是说172.16.254.2应该与172.16.254.1处在同一个子网络。

但是,问题在于单单从IP地址,我们无法判断网络部分。还是以172.16.254.1为例,它的网络部分,到底是前24位,还是前16位,甚至前28位,从IP地址上是看不出来的。

那么,怎样才能从IP地址,判断两台计算机是否属于同一个子网络呢?这就要用到另一个参数"子网掩码"(subnet mask)。

所谓"子网掩码",就是表示子网络特征的一个参数。它在形式上等同于IP地址,也是一个32位二进制数字,它的网络部分全部为1,主机部分全部为0。比如,IP地址172.16.254.1,如果已知网络部分是前24位,主机部分是后8位,那么子网络掩码就是11111111.11111111.11111111.00000000,写成十进制就是255.255.255.0。

知道"子网掩码",我们就能判断,任意两个IP地址是否处在同一个子网络。方法是将两个IP地址与子网掩码分别进行AND运算(两个数位都为1,运算结果为1,否则为0),然后比较结果是否相同,如果是的话,就表明它们在同一个子网络中,否则就不是。

比如,已知IP地址172.16.254.1和172.16.254.233的子网掩码都是255.255.255.0,请问它们是否在同一个子网络?两者与子网掩码分别进行AND运算,结果都是172.16.254.0,因此它们在同一个子网络。

总结一下,IP协议的作用主要有两个,一个是为每一台计算机分配IP地址,另一个是确定哪些地址在同一个子网络。

#3.2 IP数据包

根据IP协议发送的数据,就叫做IP数据包。不难想象,其中必定包括IP地址信息。

但是前面说过,以太网数据包只包含MAC地址,并没有IP地址的栏位。那么是否需要修改数据定义,再添加一个栏位呢?

回答是不需要,我们可以把IP数据包直接放进以太网数据包的"数据"部分,因此完全不用修改以太网的规格。这就是互联网分层结构的好处:上层的变动完全不涉及下层的结构。

具体来说,IP数据包也分为"标头"和"数据"两个部分。"标头"部分主要包括版本、长度、IP地址等信息,"数据"部分则是IP数据包的具体内容。它放进以太网数据包后,以太网数据包就变成了下面这样。

image

IP数据包的"标头"部分的长度为20个字节,整个数据包的总长度最大为65,535字节。因此,理论上,一个IP数据包的"数据"部分,最长为65,515字节。前面说过,以太网数据包的"数据"部分,最长只有1500字节。因此,如果IP数据包超过了1500字节,它就需要分割成几个以太网数据包,分开发送了。

#3.3 ARP协议

关于"网络层",还有最后一点需要说明。

因为IP数据包是放在以太网数据包里发送的,所以我们必须同时知道两个地址,一个是对方的MAC地址,另一个是对方的IP地址。通常情况下,对方的IP地址是已知的,但是我们不知道它的MAC地址。

所以,我们需要一种机制,能够从IP地址得到MAC地址。

这里又可以分成两种情况。第一种情况,如果两台主机不在同一个子网络,那么事实上没有办法得到对方的MAC地址,只能把数据包传送到两个子网络连接处的"网关"(gateway),让网关去处理。

第二种情况,如果两台主机在同一个子网络,那么我们可以用ARP协议,得到对方的MAC地址。ARP协议也是发出一个数据包(包含在以太网数据包中),其中包含它所要查询主机的IP地址,在对方的MAC地址这一栏,填的是FF:FF:FF:FF:FF:FF,表示这是一个"广播"地址。它所在子网络的每一台主机,都会收到这个数据包,从中取出IP地址,与自身的IP地址进行比较。如果两者相同,都做出回复,向对方报告自己的MAC地址,否则就丢弃这个包。

总之,有了ARP协议之后,我们就可以得到同一个子网络内的主机MAC地址,可以把数据包发送到任意一台主机之上了。

#4. 传输层

有了MAC地址和IP地址,我们已经可以在互联网上任意两台主机上建立通信。

接下来的问题是,同一台主机上有许多程序都需要用到网络,比如,你一边浏览网页,一边与朋友在线聊天。当一个数据包从互联网上发来的时候,你怎么知道,它是表示网页的内容,还是表示在线聊天的内容?

也就是说,我们还需要一个参数,表示这个数据包到底供哪个程序(进程)使用。这个参数就叫做"端口"(port),它其实是每一个使用网卡的程序的编号。每个数据包都发到主机的特定端口,所以不同的程序就能取到自己所需要的数据。

"端口"是0到65535之间的一个整数,正好16个二进制位。0到1023的端口被系统占用,用户只能选用大于1023的端口。不管是浏览网页还是在线聊天,应用程序会随机选用一个端口,然后与服务器的相应端口联系。

"传输层"的功能,就是建立"端口到端口"的通信。相比之下,"网络层"的功能是建立"主机到主机"的通信。只要确定主机和端口,我们就能实现程序之间的交流。因此,Unix系统就把主机+端口,叫做"套接字"(socket)。有了它,就可以进行网络应用程序开发了。

#4.1 UDP协议

现在,我们必须在数据包中加入端口信息,这就需要新的协议。最简单的实现叫做UDP协议,它的格式几乎就是在数据前面,加上端口号。

UDP数据包,也是由"标头"和"数据"两部分组成。

image

"标头"部分主要定义了发出端口和接收端口,"数据"部分就是具体的内容。然后,把整个UDP数据包放入IP数据包的"数据"部分,而前面说过,IP数据包又是放在以太网数据包之中的,所以整个以太网数据包现在变成了下面这样:

image

UDP数据包非常简单,"标头"部分一共只有8个字节,总长度不超过65,535字节,正好放进一个IP数据包。

#4.2 TCP协议

UDP协议的优点是比较简单,容易实现,但是缺点是可靠性较差,一旦数据包发出,无法知道对方是否收到。

为了解决这个问题,提高网络可靠性,TCP协议就诞生了。这个协议非常复杂,但可以近似认为,它就是有确认机制的UDP协议,每发出一个数据包都要求确认。如果有一个数据包遗失,就收不到确认,发出方就知道有必要重发这个数据包了。

因此,TCP协议能够确保数据不会遗失。它的缺点是过程复杂、实现困难、消耗较多的资源。

TCP数据包和UDP数据包一样,都是内嵌在IP数据包的"数据"部分。TCP数据包没有长度限制,理论上可以无限长,但是为了保证网络的效率,通常TCP数据包的长度不会超过IP数据包的长度,以确保单个TCP数据包不必再分割。

关于TCP细节以后再探讨。

#5. 应用层

应用程序收到"传输层"的数据,接下来就要进行解读。由于互联网是开放架构,数据来源五花八门,必须事先规定好格式,否则根本无法解读。

"应用层"的作用,就是规定应用程序的数据格式。

举例来说,TCP协议可以为各种各样的程序传递数据,比如Email、WWW、FTP等等。那么,必须有不同协议规定电子邮件、网页、FTP数据的格式,这些应用程序协议就构成了"应用层"。

这是最高的一层,直接面对用户。它的数据就放在TCP数据包的"数据"部分。因此,现在的以太网的数据包就变成下面这样。

image

*注:UDP头为8个字节,TCP头为20个字节

整理于:http://www.ruanyifeng.com/blog/2012/05/internet_protocol_suite_part_i.html

2.从上到下看五层模型

这个过程看的就是用户从浏览器输入一条url之后,是如何发送过去的。

#1.上一篇文章的小结

我们已经知道,网络通信就是交换数据包。电脑A向电脑B发送一个数据包,后者收到了,回复一个数据包,从而实现两台电脑之间的通信。数据包的结构,基本上是下面这样:

image

发送这个包,需要知道两个地址:
  

  • 对方的MAC地址
  • 对方的IP地址

有了这两个地址,数据包才能准确送到接收者手中。但是,前面说过,MAC地址有局限性,如果两台电脑不在同一个子网络,就无法知道对方的MAC地址,必须通过网关(gateway)转发。

image

上图中,1号电脑要向4号电脑发送一个数据包。它先判断4号电脑是否在同一个子网络,结果发现不是(后文介绍判断方法),于是就把这个数据包发到网关A。网关A通过路由协议,发现4号电脑位于子网络B,又把数据包发给网关B,网关B再转发到4号电脑。

1号电脑把数据包发到网关A,必须知道网关A的MAC地址。

发送数据包之前,电脑必须判断对方是否在同一个子网络,然后选择相应的MAC地址。

有了一台新电脑之后,要想上网,一种方式是自己配置静态IP:

image

很多人都没有进行过这个配置,因为一般情况下我们根本不需要这样。但是有的时候也会用到,比如我在电信实习的时候,他们每一个网口旁边都贴着这四个参数,你联网必须要适用他提供的一系列地址才行。其实经过上面的学习,我们已经知道,通信的时候,需要知道对方的IP(ARP知道对方的MAC地址)、子网掩码(确定所在的子网)、默认网关(不在一个子网,要通过网关取转发、路由)、DNS服务器(解析域名为IP地址)。

但是,这样的设置很专业,普通用户望而生畏,而且如果一台电脑的IP地址保持不变,其他电脑就不能使用这个地址,不够灵活。出于这两个原因,大多数用户使用"动态IP地址上网"。

#2.DHCP协议

所谓"动态IP地址",指计算机开机后,会自动分配到一个IP地址,不用人为设定。它使用的协议叫做DHCP协议。

这个协议规定,每一个子网络中,有一台计算机负责管理本网络的所有IP地址,它叫做"DHCP服务器"。新的计算机加入网络,必须向"DHCP服务器"发送一个"DHCP请求"数据包,申请IP地址和相关的网络参数。

前面说过,如果两台计算机在同一个子网络,必须知道对方的MAC地址和IP地址,才能发送数据包。但是,新加入的计算机不知道DHCP服务器的两个地址,怎么发送数据包呢

DHCP协议做了一些巧妙的规定。

首先,它是一种应用层协议,建立在UDP协议之上,所以整个数据包是这样的:

image

(1)最前面的"以太网标头",设置发出方(本机)的MAC地址和接收方(DHCP服务器)的MAC地址。前者就是本机网卡的MAC地址,后者这时不知道,就填入一个广播地址:FF-FF-FF-FF-FF-FF。

(2)后面的"IP标头",设置发出方的IP地址和接收方的IP地址。这时,对于这两者,本机都不知道。于是,发出方的IP地址就设为0.0.0.0,接收方的IP地址设为255.255.255.255。

(3)最后的"UDP标头",设置发出方的端口和接收方的端口。这一部分是DHCP协议规定好的,发出方是68端口,接收方是67端口。

这个数据包构造完成后,就可以发出了。以太网是广播发送,同一个子网络的每台计算机都收到了这个包。

因为接收方的MAC地址是FF-FF-FF-FF-FF-FF,看不出是发给谁的,所以每台收到这个包的计算机,还必须分析这个包的IP地址,才能确定是不是发给自己的。

当看到发出方IP地址是0.0.0.0,接收方是255.255.255.255,于是DHCP服务器知道"这个包是发给我的",而其他计算机就可以丢弃这个包。

接下来,DHCP服务器读出这个包的数据内容,分配好IP地址,发送回去一个"DHCP响应"数据包。

这个响应包的结构也是类似的,以太网标头的MAC地址是双方的网卡地址,IP标头的IP地址是DHCP服务器的IP地址(发出方)和255.255.255.255(接收方),UDP标头的端口是67(发出方)和68(接收方),分配给请求端的IP地址和本网络的具体参数则包含在Data部分。

新加入的计算机收到这个响应包,于是就知道了自己的IP地址、子网掩码、网关地址、DNS服务器等等参数。

动态拿到最核心的四个参数:自己的IP地址、子网掩码、网关地址、DNS服务器,就可以联网了。

#3.访问google的过程

我们假定,经过上一节的步骤,用户设置好了自己的网络参数:

  • 本机的IP地址:192.168.1.100
  • 子网掩码:255.255.255.0
  • 网关的IP地址:192.168.1.1
  • DNS的IP地址:8.8.8.8

然后他打开浏览器,想要访问Google,在地址栏输入了网址:www.google.com。

这意味着,浏览器要向Google发送一个网页请求的数据包。

#3.1 DNS协议

我们知道,发送数据包,必须要知道对方的IP地址。但是,现在,我们只知道网址www.google.com,不知道它的IP地址。

DNS协议可以帮助我们,将这个网址转换成IP地址。已知DNS服务器为8.8.8.8,于是我们向这个地址发送一个DNS数据包(53端口)。

image

然后,DNS服务器做出响应,告诉我们Google的IP地址是172.194.72.105。于是,我们知道了对方的IP地址。

#3.2 子网掩码

接下来,我们要判断,这个IP地址是不是在同一个子网络,这就要用到子网掩码。

已知子网掩码是255.255.255.0,本机用它对自己的IP地址192.168.1.100,做一个二进制的AND运算(两个数位都为1,结果为1,否则为0),计算结果为192.168.1.0;然后对Google的IP地址172.194.72.105也做一个AND运算,计算结果为172.194.72.0。这两个结果不相等,所以结论是,Google与本机不在同一个子网络。

因此,我们要向Google发送数据包,必须通过网关192.168.1.1转发,也就是说,接收方的MAC地址将是网关的MAC地址。

#3.3 应用层协议

浏览网页用的是HTTP协议,它的整个数据包构造是这样的:

image

HTTP部分的内容,类似于下面这样:

  GET / HTTP/1.1
  Host: www.google.com
  Connection: keep-alive
  User-Agent: Mozilla/5.0 (Windows NT 6.1) ......
  Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
  Accept-Encoding: gzip,deflate,sdch
  Accept-Language: zh-CN,zh;q=0.8
  Accept-Charset: GBK,utf-8;q=0.7,*;q=0.3
  Cookie: ... ...

我们假定这个部分的长度为4960字节,它会被嵌在TCP数据包之中。

#3.4 TCP协议

TCP数据包需要设置端口,接收方(Google)的HTTP端口默认是80,发送方(本机)的端口是一个随机生成的1024-65535之间的整数,假定为51775。

TCP数据包的标头长度为20字节,加上嵌入HTTP的数据包,总长度变为4980字节。

#3.5 IP协议

然后,TCP数据包再嵌入IP数据包。IP数据包需要设置双方的IP地址,这是已知的,发送方是192.168.1.100(本机),接收方是172.194.72.105(Google)。

IP数据包的标头长度为20字节,加上嵌入的TCP数据包,总长度变为5000字节。

#3.6 以太网协议

最后,IP数据包嵌入以太网数据包。以太网数据包需要设置双方的MAC地址,发送方为本机的网卡MAC地址,接收方为网关192.168.1.1的MAC地址(通过ARP协议得到)。

以太网数据包的数据部分,最大长度为1500字节,而现在的IP数据包长度为5000字节。因此,IP数据包必须分割成四个包。因为每个包都有自己的IP标头(20字节),所以四个包的IP数据包的长度分别为1500、1500、1500、560。

#3.7 服务器响应

经过多个网关的转发,Google的服务器172.194.72.105,收到了这四个以太网数据包。

根据IP标头的序号,Google将四个包拼起来,取出完整的TCP数据包,然后读出里面的"HTTP请求",接着做出"HTTP响应",再用TCP协议发回来。

本机收到HTTP响应以后,就可以将网页显示出来,完成一次网络通信。

整理自:http://www.ruanyifeng.com/blog/2012/06/internet_protocol_suite_part_ii.html

7.一步一步理解HTTPS

这是计算机网络相关的第七篇文章。HTTPS(SSL/TLS)的加密机制是前端后端ios安卓等都应了解的基本问题。也是面试经常问的点。

一、为什么需要加密?

小时候看谍战片,情报发过来了之后,用一个小本本进行翻译,然后解密出情报。加密就是防止明文被别人看到甚至篡改嘛!

回到互联网,因为http的内容是明文传输的,明文数据会经过中间代理服务器、路由器、wifi热点、通信服务运营商等多个物理节点,如果信息在传输过程中被劫持,传输的内容就完全暴露了,他还可以篡改传输的信息且不被双方察觉,这就是中间人攻击。所以我们才需要对信息进行加密。最简单容易理解的就是对称加密 。

二、什么是对称加密?

image

小明写个求爱信给小红,小明担心小红的妈妈看到这封信的内容,他灵机一动,对信加个密,并确定好我用这个密钥加密的,小红收到之后也用这个密钥解密才行。

但是呢,这里有个麻烦的地方就是,小明和小红不在一个学校,这个钥匙呢,不方便直接送到手里。所以呢,小明得想办法把这个钥匙寄一个送给小红,好吧,就用最贵的顺丰吧!

就是有一个密钥,它可以对一段内容加密,加密后只能用它才能解密看到原本的内容,和我们日常生活中用的钥匙作用差不多。

三、用对称加密可行吗?

顺丰快递到了,结果小红不在家,小红的妈妈收到了,一看是个男同学寄的,怎么能忍住,赶紧打开,以看是一把钥匙,作为程序猿,妈妈得意一笑:哼哼,还能逃过我的眼睛?我赶紧复制一把藏着,我倒要看看他后面要寄啥来,还要加密?!

果然小红的妈妈等到了来自小明寄过来的情书,解密一看,实锤早恋。

同样地,小明这边也非常危险,快递员刚出发,就被小明的妈妈拦截了,拿到了这个钥匙,那小明还没寄出的信已经被妈妈看光了。

所以问题的根本就是,这把钥匙要传输,传输就可能被截取。

image

回到互联网,如果通信双方都各自持有同一个密钥,且没有别人知道,这两方的通信安全当然是可以被保证的(除非密钥被破解)。

然而最大的问题就是这个密钥怎么让传输的双方知晓,同时不被别人知道。

如果由服务器生成一个密钥并传输给浏览器,那这个传输过程中密钥被别人劫持弄到手了怎么办?

换种思路?试想一下,如果浏览器内部就预存了网站A的密钥,且可以确保除了浏览器和网站A,不会有任何外人知道该密钥,那理论上用对称加密是可以的,这样浏览器只要预存好世界上所有HTTPS网站的密钥就行啦!这么做显然不现实。

怎么办?所以我们就需要神奇的非对称加密。

四、什么是非对称加密?

有两把密钥,通常一把叫做公钥、一把叫做私钥。

用公钥加密的内容必须用私钥才能解开,同样,私钥加密的内容只有公钥能解开。

五、用非对称加密可行吗?

image

公钥呢,还是要通过快递员送给小红的。OK,假设小红要回信,写好了用公钥加密,小红的妈妈因为拿不到私钥,看不到信的内容。

OK,但是反过来呢?小明用私钥加密传给小红,那么小红的妈妈可就能解密了(因为公钥可能会被小红的妈妈拿到)。

回到互联网,服务器先把公钥直接明文传输给浏览器,之后浏览器向服务器传数据前都先用这个公钥加密好再传,这条数据的安全似乎可以保障了!因为只有服务器有相应的私钥能解开这条数据。

然而由服务器到浏览器的这条路怎么保障安全?

如果服务器用它的的私钥加密数据传给浏览器,那么浏览器用公钥可以解密它,而这个公钥是一开始通过明文传输给浏览器的,这个公钥被谁劫持到的话,他也能用该公钥解密服务器传来的信息了。

所以目前似乎只能保证由浏览器向服务器传输数据时的安全性(其实仍有漏洞,下文会说)。

六、改良的非对称加密方案,似乎可以?

小明和小红年纪不大,但是很聪明,针对这个情况,还是迅速升级加密方法。他们想到既然一组公钥私钥不够,那两组呢?

image

OK,小明和小红各造了一对。下面就是互相交换公钥。那么就变成:

image

下面就好办啦,小明写信用公钥B加密,那么信的内容只有小红能破解,因为小红是随身携带私钥B。相反,小红用公钥A对信加密,这样只有小明能破解,因为小明也是随身携带私钥A。好像很安全啦!除了下面提到的漏洞,唯一的缺点可能是:小红得花半天时间才能解密完这封信,有点受不了。

回到互联网。请看下面的过程:

  1. 某网站拥有用于非对称加密的公钥A、私钥A;浏览器拥有用于非对称加密的公钥B、私钥B。
  2. 浏览器像网站服务器请求,服务器把公钥A明文给传输浏览器。
  3. 浏览器把公钥B明文传输给服务器。
  4. 之后浏览器向服务器传输的所有东西都用公钥A加密,服务器收到后用私钥A解密。由于只有服务器拥有这个私钥A可以解密,所以能保证这条数据的安全。
  5. 服务器向浏览器传输的所有东西都用公钥B加密,浏览器收到后用私钥B解密。同上也可以保证这条数据的安全。

的确可以!抛开这里面仍有的漏洞不谈(下文会讲),HTTPS的加密却没使用这种方案,为什么?最主要的原因是非对称加密算法非常耗时,特别是加密解密一些较大数据的时候有些力不从心。

七、非对称加密+对称加密?

小明也知道,这个信很长,用非对称加密,太慢!办法也有,没有必要对那么长的信加密,我只要保证这个真正解密的钥匙不被别人拿到就行,那么他灵机一动想到这个方法:

image

小明和小红利用非对称加密对钥匙加密,姑且认为是这个钥匙被放在了一个盒子里,这个盒子也被锁起来了,只有小红或者小明才能打开盒子,再用钥匙去解密。

这个真正用于对称加密解密的钥匙别人就拿不到啦!

自从用了这个方案,感觉又安全,解密又快,感情又深温了呢!

回到互联网,步骤如下:

  1. 某网站拥有用于非对称加密的公钥A、私钥A。
  2. 浏览器像网站服务器请求,服务器把公钥A明文给传输浏览器。
  3. 浏览器随机生成一个用于对称加密的密钥X,用公钥A加密后传给服务器
  4. 服务器拿到后用私钥A解密得到密钥X
  5. 这样双方就都拥有密钥X了,且别人无法知道它。之后双方所有数据都用密钥X加密解密

HTTPS的基本**就是基于这个。但是这个方案也存在上面一直在说的漏洞。

八、中间人攻击

像妈妈这样级别的程序猿可能是那他们两没办法啦,但是呢,校区有个看门的大爷,以前是个黑客,也不知道咋回事,明明才50岁,但是看起来像80岁,头上光溜溜的,冬天冷呢。整天在那胡言乱语:docker牛逼啊,spring cloud牛逼啊,这个开源软件XXX写的真好,跟周围的老大爷老大妈根本谈不到一起去。

他也是闲的蛋疼,非要掺和,因为据说他以前单身30年,苦逼敲代码,不知道谈恋爱是啥滋味,姑且认为他好奇心重吧。

在小明第一次寄公钥A的时候,大爷出手了,截取下来。换成自己做的公钥B。然后送给小红。

小红哪里会知道这公钥被掉包了呢,所以直接就用了,按照正常步骤,小红想了一个随机字符串,这次就叫xiaomingwoxuanni吧,OK,用这个公钥B对这个字符串加个密,这个字符串就被锁进了用大爷公钥B锁的盒子里。

老大爷在门口守着呢,一看到小红寄东西了,又偷偷地截取下来,用自己的私钥B来解密这个盒子。轻易地拿到了里面的字符串,OK,怕小明察觉,再用小明寄来的公钥A加密传给小明,这样双方都不知道他们的钥匙已经被大爷给获取了。

小明和小红之间的信就用xiaomingwoxuanni这个钥匙进行对称加密和对称解密,完全不知道有个大爷就天天拿着这个字符串去解密信件,看的不亦乐乎,甚至还偷偷改几个字呢。

回到互联网。中间人的确无法得到浏览器生成的密钥B,这个密钥本身被公钥A加密了,只有服务器才有私钥A解开拿到它呀!然而中间人却完全不需要拿到密钥A就能干坏事了。请看:

  1. 某网站拥有用于非对称加密的公钥A、私钥A。
  2. 浏览器向网站服务器请求,服务器把公钥A明文给传输浏览器。
  3. 中间人劫持到公钥A,保存下来,把数据包中的公钥A替换成自己伪造的公钥B(它当然也拥有公钥B对应的私钥B)。
  4. 浏览器随机生成一个用于对称加密的密钥X,用公钥B(浏览器不知道公钥被替换了)加密后传给服务器。
  5. 中间人劫持后用私钥B解密得到密钥X,再用公钥A加密后传给服务器。
  6. 服务器拿到后用私钥A解密得到密钥X。

这样在双方都不会发现异常的情况下,中间人得到了密钥B。根本原因是浏览器无法确认自己收到的公钥是不是网站自己的。只要解决了这个公钥一定是这个网站发来的,那么基本就OK了

九、如何证明浏览器收到的公钥一定是该网站的公钥?

现实生活中,如果想证明某身份证号一定是小明的,怎么办?看身份证。这里政府机构起到了“公信”的作用,身份证是由它颁发的,它本身的权威可以对一个人的身份信息作出证明。互联网中能不能搞这么个公信机构呢?给网站颁发一个“身份证”?

十、数字证书

网站在使用HTTPS前,需要向“CA机构”申请颁发一份数字证书,即SSL证书,数字证书里有证书持有者、证书持有者的公钥等信息,服务器把证书传输给浏览器,浏览器从证书里取公钥就行了,证书就如身份证一样,可以证明“该公钥对应该网站”。然而这里又有一个显而易见的问题了,证书本身的传输过程中,如何防止被篡改?即如何证明证书本身的真实性?身份证有一些防伪技术,数字证书怎么防伪呢?解决这个问题我们就基本接近胜利了!

SSL证书内容:

  1. 证书的发布机构CA
  2. 证书的有效期
  3. 公钥
  4. 证书所有者
  5. 签名

十一、如何放防止数字证书被篡改?

我们把证书内容生成一份“签名”,比对证书内容和签名是否一致就能察觉是否被篡改。这种技术就叫数字签名。

提到数字签名,其实原理很简单啦,就是比如我要传输一句话叫:“你给我转100块钱,我的账号是123456,转完了告诉我一声。”,如果不做任何处理,被刚才的老大爷截取了,他偷偷地改一下内容“你给我转200块钱,我的账号是654321,不要告诉任何人,尤其是你嫂子。”

是不是太坏了,弄不好被抓,大爷可不敢做大的,只敢骗个喝酒钱。

那么怎么防止大爷这种猥琐技术又高的人篡改呢?数字签名排上用场啦!

以后再传消息就是“你给我转100块钱,我的账号是123456,转完了告诉我一声。”+“!……@&@%#……!¥@¥!@%……#¥!%……”,后面那一串东西就是数字签名,简单来说,就是想办法对前面的内容进行非对称加密(这样别人根本不知道你加密的私钥是什么,也就伪装不了签名了)。传过去之后,我要对其进行解密,与传过来的明文一一对比参数,看有没有被改动过。一旦发现哪里不对应,说明已经被篡改了。

“CA机构”制作签名的过程:

  1. CA拥有非对称加密的私钥和公钥
  2. CA对证书明文信息进行hash
  3. 对hash后的值用私钥加密,得到数字签名

明文和数字签名共同组成了数字证书,这样一份数字证书就可以颁发给网站了。网站把这个数字证书传给浏览器。

那浏览器拿到服务器传来的数字证书后,如何验证它是不是真的?(有没有被篡改、掉包)

浏览器验证过程:

  1. 拿到证书,得到明文T,数字签名S。
  2. 用CA机构的公钥对S解密(由于是浏览器信任的机构,所以浏览器保有它的公钥。详情见下文),得到S’。
  3. 用证书里说明的hash算法对明文T进行hash得到T’。
  4. 比较S’是否等于T’,等于则表明证书可信。

为什么这样可以证明证书可信呢?我们来仔细想一下。

十二、中间人有可能篡改该证书吗?

老大爷就算有天大的能耐,也拿不到加密的私钥,那么只是单纯地篡改明文,只会造成校验不通过。

回到互联网,假设中间人篡改了证书的原文,由于他没有CA机构的私钥,所以无法得到此时加密后签名,无法相应地篡改签名。

浏览器收到该证书后会发现原文和签名解密后的值不一致,则说明证书已被篡改,证书不可信,从而终止向服务器传输信息,防止信息泄露给中间人。

十三、中间人有可能把证书掉包吗?

假设有另一个网站B也拿到了CA机构认证的证书,它想搞垮网站A,想劫持网站A的信息。于是它成为中间人拦截到了A传给浏览器的证书,然后替换成自己的证书,传给浏览器,之后浏览器就会错误地拿到B的证书里的公钥了,会导致上文提到的漏洞。

其实这并不会发生,因为证书里包含了网站A的信息,包括域名,浏览器把证书里的域名与自己请求的域名比对一下就知道有没有被掉包了。

总结:因为一个网站域名对应一个证书,你的证书根其他人的证书肯定是不一样的,那么你就算拿到了其他人的证书再掉包成自己的,也没用,毕竟浏览器那边只要看一下是不是我要查看的域名。

十四、为什么制作数字签名时需要hash一次?

最显然的是性能问题,前面我们已经说了非对称加密效率较差,证书信息一般较长,比较耗时。而hash后得到的是固定长度的信息(比如用md5算法hash后可以得到固定的128位的值),这样加密解密就会快很多。

十五、怎么证明CA机构的公钥是可信的?

让我们回想一下数字证书到底是干啥的?没错,为了证明某公钥是可信的,即“该公钥是否对应该网站/机构等”,那这个CA机构的公钥是不是也可以用数字证书来证明?没错,操作系统、浏览器本身会预装一些它们信任的根证书,如果其中有该CA机构的根证书,那就可以拿到它对应的可信公钥了。

实际上证书之间的认证也可以不止一层,可以A信任B,B信任C,以此类推,我们把它叫做信任链或数字证书链,也就是一连串的数字证书,由根证书为起点,透过层层信任,使终端实体证书的持有者可以获得转授的信任,以证明身份。

另外,不知你们是否遇到过网站访问不了、提示要安装证书的情况?这里安装的就是根证书。说明浏览器不认给这个网站颁发证书的机构,那么没有该机构的根证书,你就得手动下载安装(风险自己承担XD)。安装该机构的根证书后,你就有了它的公钥,就可以用它验证服务器发来的证书是否可信了。

也就是说,公钥是从证书中获取的。证书是网站从机构那边申请来的,证书+签名传给浏览器。只要校验通过,那么公钥必然没有被篡改过,并且一定是这个网站传来的,那么解决了我们最核心的问题:确定公钥是我们指定的网站传来的。

既然公钥是正确的,那么小红就会用正确的公钥对随机字符串加密,中间不会出现篡改。

十六、HTTPS必须在每次请求中都要先在SSL/TLS层进行握手传输密钥吗?

这也是我当时的困惑之一,显然每次请求都经历一次密钥传输过程非常耗时,那怎么达到只传输一次呢?用session就行。

服务器会为每个浏览器(或客户端软件)维护一个session ID,在TSL握手阶段传给浏览器,浏览器生成好密钥传给服务器后,服务器会把该密钥存到相应的session ID下,之后浏览器每次请求都会携带session ID,服务器会根据session ID找到相应的密钥并进行解密加密操作,这样就不必要每次重新制作、传输密钥了!

十七、HTTPS原理

下面再来看看HTTPS原理就特别简单啦!

HTTPS 协议(HyperText Transfer Protocol over Secure Socket Layer):可以理解为HTTP+SSL/TLS, 即 HTTP 下加入 SSL 层,HTTPS 的安全基础是 SSL,因此加密的详细内容就需要 SSL,用于安全的 HTTP 数据传输。

HTTP
SSL/TLS
TCP
IP

我们只要知道,在SSL层里面可以完成校验和密钥的传输。

image

理解了上面,这个图也就没啥好解释的了。

整理自:https://zhuanlan.zhihu.com/p/43789231

4.TCP协议入门

这是计算机网络相关的第四篇文章。首先要明确:信道本身不可靠(丢包、重复包、出错、乱序),不安全。所以引出了七层或五层模型来保证。因此,任何一个东西的提出都是为了解决某个问题的。学习计算机,从他的历史出发,理解为什么会有不断低迭代,因为是为了解决某个痛点问题。比如HTTP的发展,为什么在HTTP1.0基础上还要提出HTTP1.1,为什么还要提出HTTP2.0,我们学习了他的发展历史之后就会明白了。同样,下面再说一说为什么要有TCP协议,TCP到底解决了什么问题。

一、回顾

首先简单回顾一下。

1.1 物理层

物理层是相当于物理连接,将0101以电信号的形式传输出去。

1.2 数据链路层

数据链路层,有一个叫做以太网协议,规定了电子信号是如何组成数据包的,这个协议的头里面,包含了自身的网卡信息,还有目的地的网卡信息(一般我们可以知道对方的IP,IP可以通过DNS解析到,然后根据ARP协议将IP转换为MAC地址)。那么,如果在同一个局域网内,我们就可以通过广播的方式找到对应MAC地址的主机。---即以太网协议解决了子网内部的点对点通信。

1.3 网络层

但是呢,以太网协议不能解决多个局域网通信,每个局域网之间不是互通的,那么以太网这种广播的方式不可用,就算可用,网络那么大,通过广播进行找,是一个可怕的场景。那么,IP协议可以连接多个局域网,简单来说,IP 协议定义了一套自己的地址规则,称为 IP 地址。物理器件,比如说路由器,就是基于IP协议,里面保存一套地址指路牌,想去哪个局域网,可以通过这个牌子来找,然后逐步路由到目标局域网,最后就可以找到那台主机了。IP层就是对应了网络层。

1.4 传输层

那么,此时解决了多个局域网路由问题,也解决了局域网内寻址问题,即我这台主机已经可以找到那台主机了,下面还有什么事情需要做呢?显然,找到主机还不行啊,比如我用微信发一条消息,我发到你主机了,但是你主机上的微信不知道这条消息发给他了,这里说的就是端口,信息要发到这个端口上,监听这个端口的程序才会收到消息。

1.5 应用层

OK,最上层的应用层,就是最贴近用户的,他的一系列协议只是为了让两台主机会互相都理解而已。

二、问题和解决

2.1 存在的问题

在明白了计算机网络为什么要这几层模型之后,我们再回到一开始,如何保证安全、可靠、完整地传输信息呢?

很显然,上面提到的,只是保证信息能找到对方主机和端口,但是这个信息中途被拦截了、甚至被篡改了、信息延迟了(几分钟或者几个小时,或者几个世纪)、网络不通或者挂了,信息自己可不会告诉你他挂了或者要迟到一会,如果没有一个协议来保障可靠性,那么我这条消息发出去,能不能到、能不能及时到、能不能完整到、能不能不被篡改到等这些问题将会造成灾难,网络传输也就没有了意义。

计算机的前辈们,为我们提供了一系列的措施来尽可能保证信息能正确送达。

2.2 数据校验

首先在数据链路层,可以通过各种校验,比如奇偶校验等手段来判断数据包传的是否正确。

2.3 数据可靠性

好了,解决了数据是否正确之后,但是还不能保证线路是可靠的,加入某个包没发出去或者发错了,应该有一个出错重传机制,保证信息传输的可靠性。这就引出了TCP协议。

TCP(Transmission Control Protocol 传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。

下面来看看TCP是如何解决丢包、重复包、出错、乱序等不可靠的一些问题的。

三、滑动窗口协议的提出

这就引出了TCP中最终的一个东西:滑动窗口协议。

3.1 朴素的方法来确保可靠性

先从简单的角度出发,自己想一下,如何保证不丢包、不乱序。

image

按照顺序,发送一个确认一个,显然,吞吐量非常低。那么,一次性发几个包,然后一起确认呢?

3.2 改进方案

image

那么就引出第二个问题,我一次性发几个包合适呢?就这引出了滑动窗口。

四、数据包编号和重传机制

4.1 数据包编号

在说明滑动窗口原理之前,必须要说一下TCP数据包的编号SEQ。

我们知道,由于以太网数据包大小限制,所以每个包承载的数据是有限的,如果发一个很大的包,必然是要拆分的。

发送的时候,TCP 协议为每个包编号(sequence number,简称 SEQ),以便接收的一方按照顺序还原。万一发生丢包,也可以知道丢失的是哪一个包。

第一个包的编号是一个随机数。为了便于理解,这里就把它称为1号包。假定这个包的负载长度是100字节,那么可以推算出下一个包的编号应该是101。这就是说,每个数据包都可以得到两个编号:自身的编号,以及下一个包的编号。接收方由此知道,应该按照什么顺序将它们还原成原始文件。

4.2 数据重传机制

TCP协议就是根据这些编号来重新还原文件的。并且接收端保证顺序性返回ACK确认,比如有两个包发过去,为1号和2号,2号接收成功,但是发现1号包还没接收到,所以2号的ACK是不会发回去的,这个时候,如果在重传时间内收到1号了,那么就把这两个包的ACK都返回回去,如果超时了,就重传1号包。知道1号包接收成功,后续的才会返回ACK。

具体是如何做到的呢?

前面说过,每一个数据包都带有下一个数据包的编号。如果下一个数据包没有收到,那么 ACK 的编号就不会发生变化。

举例来说,现在收到了4号包,但是没有收到5号包。ACK 就会记录,期待收到5号包。过了一段时间,5号包收到了,那么下一轮 ACK 会更新编号。如果5号包还是没收到,但是收到了6号包或7号包,那么 ACK 里面的编号不会变化,总是显示5号包。这会导致大量重复内容的 ACK。

如果发送方发现收到三个连续的重复 ACK,或者超时了还没有收到任何 ACK,就会确认丢包,即5号包遗失了,从而再次发送这个包。通过这种机制,TCP 保证了不会有数据包丢失。

image

(图片说明:Host B 没有收到100号数据包,会连续发出相同的 ACK,触发 Host A 重发100号数据包。)

五、慢启动

下面再来说说慢启动。

服务器发送数据包,当然越快越好,最好一次性全发出去。但是,发得太快,就有可能丢包。带宽小、路由器过热、缓存溢出等许多因素都会导致丢包。线路不好的话,发得越快,丢得越多。

最理想的状态是,在线路允许的情况下,达到最高速率。但是我们怎么知道,对方线路的理想速率是多少呢?答案就是慢慢试。

TCP 协议为了做到效率与可靠性的统一,设计了一个慢启动(slow start)机制。开始的时候,发送得较慢,然后根据丢包的情况,调整速率:如果不丢包,就加快发送速度;如果丢包,就降低发送速度。

Linux 内核里面设定了(常量TCP_INIT_CWND),刚开始通信的时候,发送方一次性发送10个数据包,即"发送窗口"的大小为10。然后停下来,等待接收方的确认,再继续发送。

默认情况下,接收方每收到两个 TCP 数据包,就要发送一个确认消息。"确认"的英语是 acknowledgement,所以这个确认消息就简称 ACK。

ACK 携带两个信息:

  • 期待要收到下一个数据包的编号
  • 接收方的接收窗口的剩余容量

发送方有了这两个信息,再加上自己已经发出的数据包的最新编号,就会推测出接收方大概的接收速度,从而降低或增加发送速率。这被称为"发送窗口",这个窗口的大小是可变的。

我们可以知道,发送发和接收方都维护了一个缓冲区,可以理解为窗口。根据接收速度可以调整发送速度,逐渐达到这条线路最高的传输速率。

ok,下面就可以研究一下滑动窗口了。

六、滑动窗口原理

正常情况下:

image

(如图,123表示已经正常发送并且收到了ACK确认。4567属于已发送但是还没有收到ACK。8910表示待发送。这个窗口当前长度为7.正常情况下,4号包收到ACK,那么窗口就会右移一格。)

但是往往会出现一些问题,比如5号包迟迟收不到ACK,在接收端可能是没有收到5号包,但是可能会收到6号包甚至是7、8号包,那么此时只能等待5号包,如果5号包顺利到达了,那么就把5678号包的ACK都发给发送端,那么发送端滑动窗口向右右移四格。如果迟迟收不到5号包,只能重传。

image

以上就是关于TCP中比较重要的出错重传、编号、慢启动以及滑动窗口。这些保证了数据传输的可靠性。

整理自:http://www.ruanyifeng.com/blog/2017/06/tcp-protocol.html

5.TCP三次握手和四次挥手

这是计算机网络相关的第五篇文章。面试讲到TCP,那么基本都会问三次握手和四次挥手的过程,以及比如对于握手,为什么是三次,而不是两次或者四次,本章详细探讨其中的门道。

1.复习

首先针对http协议,我们有必要复习一下最重要的东西。

HTTP协议即超文本传送协议(Hypertext Transfer Protocol ),是Web联网的基础,也是手机联网常用的协议之一,HTTP协议是建立在TCP协议之上的一种应用。

在HTTP 1.0以0.9版本中,客户端的每次请求都要求建立一次单独的连接,在处理完本次请求后,就自动释放连接。

在HTTP 1.1中则可以在一次连接中处理多个请求,并且多个请求可以重叠进行,不需要等待一个请求结束后再发送下一个请求。

由于HTTP在每次请求结束后都会主动释放连接,因此HTTP连接是一种“短连接”,要保持客户端程序的在线状态,需要不断地向服务器发起连接请求。

通常的做法是即使不需要获得任何数据,客户端也保持每隔一段固定的时间向服务器发送一次“保持连接”的请求,服务器在收到该请求后对客户端进行回复,表明知道 客户端“在线”。

若服务器长时间无法收到客户端的请求,则认为客户端“下线”,若客户端长时间无法收到服务器的回复,则认为网络已经断开。

2.SOCKET原理

2.1 套接字(socket)概念

初次接触这个名词:“套接字”,说实话,心里是蒙蔽的,这是啥玩意,但是可以去搜索一下什么是套接管:

image

我们可以看出来,两个管子可能直接连的话连不起来,那么可以通过中间一个东西连接起来。

那么,现在就好理解了,两个程序要通信,需要知道对方的一些信息:连接使用的协议,本地主机的IP地址,本地进程的协议端口,远地主机的IP地址,远地进程的协议端口。

image

它是什么呢?它是网络通信过程中端点的抽象表示,这个抽象里面就包含了网络通信必须的五种信息:连接使用的协议,本地主机的IP地址,本地进程的协议端口,远地主机的IP地址,远地进程的协议端口。

那为什么一定要用它呢?

在同一台计算机上,TCP协议与UDP协议可以同时使用相同的port而互不干扰。 操作系统根据套接字地址,可以决定应该将数据送达特定的进程或线程。这就像是电话系统中,以电话号码加上分机号码,来决定通话对象一般。

因为我们电脑上可能会跑很多的应用程序,TCP协议端口需要为这些同时运行的程序提供并发服务,或者说,传输层需要为应用层的多个进程提供通信服务,每个进程起一个TCP连接,那么这多个TCP连接可能是通过同一个 TCP协议端口传输数据。

如何区别哪个进程对应哪个TCP连接呢?

许多计算机操作系统为应用程序与TCP/IP协议交互提供了套接字(Socket)接口。应 用层可以和传输层通过Socket接口,区分来自不同应用程序进程或网络连接的通信,实现数据传输的并发服务。

2.2 建立socket连接

建立Socket连接至少需要一对套接字,其中一个运行于客户端,称为ClientSocket ,另一个运行于服务器端,称为ServerSocket

套接字之间的连接过程分为三个步骤:服务器监听,客户端请求,连接确认。

服务器监听:服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态,等待客户端的连接请求。

客户端请求:指客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连接请求。

连接确认:当服务器端套接字监听到或者说接收到客户端套接字的连接请求时,就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发 给客户端,一旦客户端确认了此描述,双方就正式建立连接。而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求。

2.3 SOCKET连接与TCP连接

创建Socket连接时,可以指定使用的传输层协议,Socket可以支持不同的传输层协议(TCP或UDP),当使用TCP协议进行连接时,该Socket连接就是一个TCP连接。

3.TCP基本字段

TCP(Transmission Control Protocol 传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。

针对协议中的字段,我们只需要了解一下:ACK、SYN、序号这三个部分。

  • ACK : 确认

    • TCP协议规定,只有ACK=1时有效,也规定连接建立后所有发送的报文的ACK必须为1
  • SYN : 在连接建立时用来同步序号。

    • 当SYN=1而ACK=0时,表明这是一个连接请求报文。
    • 对方若同意建立连接,则应在响应报文中使SYN=1和ACK=1.
    • 因此, SYN置1就表示这是一个连接请求或连接接受报文。
  • FIN 即终结的意思, 用来释放一个连接。

    • 当 FIN = 1 时,表明此报文段的发送方的数据已经发送完毕,并要求释放连接。

4.三次握手(重要,细读)

image

首先,TCP作为一种可靠传输控制协议,其核心**:既要保证数据可靠传输,又要提高传输的效率,而用三次恰恰可以满足以上两方面的需求!

然后,要明确TCP连接握手,握的是啥?

答案:通信双方数据原点的序列号

我们在上面一篇文章知道,消息的完整是靠给每个消息包搞一个编号,依次地ACK确认。确认机制是累计的,意味着 X 序列号之前(不包括 X) 包都是被确认接收到的。

TCP可靠传输的精髓:TCP连接的一方A,由操作系统动态随机选取一个32位长的序列号(Initial Sequence Number)

假设A的初始序列号为1000,以该序列号为原点,对自己将要发送的每个字节的数据进行编号,1001,1002,1003…,并把自己的初始序列号ISN告诉B。

让B有一个**准备,什么样编号的数据是合法的,什么编号是非法的,比如编号900就是非法的,同时B还可以对A每一个编号的字节数据进行确认。

如果A收到B确认编号为2001,则意味着字节编号为1001-2000,共1000个字节已经安全到达。

同理B也是类似的操作,假设B的初始序列号ISN为2000,以该序列号为原点,对自己将要发送的每个字节的数据进行编号,2001,2002,2003…,并把自己的初始序列号ISN告诉A,以便A可以确认B发送的每一个字节。如果B收到A确认编号为4001,则意味着字节编号为2001-4000,共2000个字节已经安全到达。

好了,在理解了握手的本质之后,下面就可以总结上面图的握手过程了。

对于A与B的握手过程,可以总结为:

  1. A 发送同步信号SYN + A's Initial sequence number(丢失会A会重传)
  2. B 确认收到A的同步信号,并记录 A's ISN 到本地,命名 B's ACK sequence number
  3. B发送同步信号SYN + B's Initial sequence number (丢失B会周期性超时重传,直到收到A的确认)
  4. A确认收到B的同步信号,并记录 B's ISN 到本地,命名 A's ACK sequence number

很显然2和3 这两个步骤可以合并,只需要三次握手,可以提高连接的速度与效率

这里就会引出一个问题,两次不行吗?

  1. A 发送同步信号SYN + A's Initial sequence number
  2. B发送同步信号SYN + B's Initial sequence number + B's ACK sequence number

这里有一个问题,A与B就A的初始序列号达成了一致,但是B无法知道A是否已经接收到自己的同步信号,如果这个同步信号丢失了,A和B就B的初始序列号将无法达成一致。

所以A必须再给B一个确认,以确认A已经接收到B的同步信号。

如果A发给B的确认丢了,该如何?

A会超时重传这个ACK吗?不会!TCP不会为没有数据的ACK超时重传。

那该如何是好?B如果没有收到A的ACK,会超时重传自己的SYN同步信号,一直到收到A的ACK为止。

写到这里,其实我们已经明白了,握手其实就是各自确认对方的序列号。因为后面的数据编号就会以此为基础,从而保证后续数据的可靠性。

谢希仁版《计算机网络》中的例子是这样的,“已失效的连接请求报文段”的产生在这样一种情况下:client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。本来这是一个早已失效的报文段。但server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求。于是就向client发出确认报文段,同意建立连接。假设不采用“三次握手”,那么只要server发出确认,新的连接就建立了。由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送数据。但server却以为新的运输连接已经建立,并一直等待client发来数据。这样,server的很多资源就白白浪费掉了。采用“三次握手”的办法可以防止上述现象发生。例如刚才那种情况,client不会向server的确认发出确认。server由于收不到确认,就知道client并没有要求建立连接。”

但是有的人指出,其实这只是表象,或者说并不是三次握手的设计初衷,我表示认同,这个防止已失效的连接请求报文段应该只是附加的一些好处,而不应该是解释为什么是三次握手的原因。

TCP初始阶段为什么是三次握手,原因总结如下:

为了实现可靠数据传输, TCP 协议的通信双方, 都必须维护一个序列号, 以标识发送出去的数据包中, 哪些是已经被对方收到的。

三次握手的过程即是通信双方相互告知序列号起始值, 并确认对方已经收到了序列号起始值的必经步骤,如果只是两次握手, 至多只有连接发起方的起始序列号能被确认, 另一方选择的序列号则得不到确认。

5.四次挥手

image

当主机1发出FIN报文段时,只是表示主机1已经没有数据要发送了,主机1告诉主机2,它的数据已经全部发送完毕了;

但是,这个时候主机1还是可以接受来自主机2的数据;

当主机2返回ACK报文段时,表示它已经知道主机1没有数据发送了,但是主机2还是可以发送数据到主机1的;

当主机2也发送了FIN报文段时,这个时候就表示主机2也没有数据要发送了,就会告诉主机1,我也没有数据要发送了;

主机1告诉主机2知道了,主机2收到这个确认之后就立马关闭自己。

主机1等待2MSL之后也关闭了自己。

针对最后一条消息,即主机1发送ack后,主机2接收到此消息,即认为双方达成了同步:双方都知道连接可以释放了,此时B可以安全地释放此TCP连接所占用的内存资源、端口号。

所以被动关闭的B无需任何wait time,直接释放资源。

但是主机1并不知道主机2是否接到自己的ACK,主机1是这么想的

  • 如果主机2没有收到自己的ACK,主机2会超时重传FiN,那么主机1再次接到重传的FIN,会再次发送ACK
  • 如果主机2收到自己的ACK,也不会再发任何消息,包括ACK

无论是情况1还是2,A都需要等待,要取这两种情况等待时间的最大值,以应对最坏的情况发生,这个最坏情况是:

主机2没有收到主机1的ACK,那么超时之后主机2会重传FIN,也就是说,要浪费一个主机1发出ACK的最大存活时间(MSL)+FIN消息的最大存活时间(MSL)

不可能时间再多了,这个已经针对最糟糕的状况。

等待2MSL时间,A就可以放心地释放TCP占用的资源、端口号,此时可以使用该端口号连接任何服务器。

在等待的时间内,主机2可以重试多次,因为2MSL时间为240秒,超时重传只有0.5秒,1秒,2秒,,16秒。

当主机2重试次数达到上限,主机2会reset连接。

那么为什么是2MSL我们已经了解了,但是为什么要等这个时间呢?

如果不等,释放的端口可能会重连刚断开的服务器端口,这样依然存活在网络里的老的TCP报文可能与新TCP连接报文冲突,造成数据冲突,为避免此种情况,需要耐心等待网络老的TCP连接的活跃报文全部死翘翘,2MSL时间可以满足这个需求。

整理自:

6.HTTP基础知识提炼

这是计算机网络相关的第六篇文章。这里简单记录一些关于HTTP的基本概念,比较基础。下面的内容是对《图解HTTP》提炼的再提炼,主要原因是很多重要的东西前面已经详细说过了,还有一些东西知道即可,用到再去查,作为一个后端攻城狮,也没有必要了解那么琐碎。

HTTP是不保存状态的协议

HTTP是无状态协议。自身不对请求和响应之间通信状态进行保存(即不做持久化处理)。 HTTP之所以设计得如此简单,是为了更快地处理大量事物,确保协议的可伸缩性。 HTTP/1.1 随时无状态协议,但可通过 Cookie 技术保存状态。

告知服务器意图的HTTP方法

  • GET:获取资源
  • POST:传输实体主体
  • PUT:传输文件
  • HEAD:获得报文首部,与GET方法一样,只是不返回报文主体内容。用于确认URI的有效性及资源更新的日期时间等。
  • DELETE:删除文件,与PUT相反(响应返回204 No Content)。
  • OPTIONS:询问支持的方法,查询针对请求URI指定的资源支持的方法(Allow:GET、POST、HEAD、OPTIONS)。
  • TRACE:追踪路径
  • CONNECT:要求用隧道协议连接代理(主要使用SSL(Secure Sockets Layer,安全套接层)和TLS(Transport Layer Security,传输层安全)协议把通信内容加密后经网络隧道传输)。

URI、URL

官方解释都是什么乱起八糟的东西。各种博客也是跟着抄,这两者到底是什么关系和意义?

统一资源标志符URI就是在某一规则下能把一个资源独一无二地标识出来。

对应于实际例子就是:每个人都有身份证,这个身份证号码就对应这个人。比如张三的身份证号码为123456,那么我只要知道123456就可以找到这个人。

那什么是URL呢?从名字看是:统一资源定位器。

如果做类比,URL就是:动物住址协议://地球/**/浙江省/杭州市/西湖区/某大学/14号宿舍楼/525号寝/张三.人

我们通过这个详细的地址也可以找到张三这个人。

那么他们俩到底是什么关系呢?

URI是以某种规则唯一地标识资源,手段不限,比如身份证号。当然了,地址可以唯一标识,那么也属于URI的一种手段。所以说URL是URI的子集

回到Web上,假设所有的Html文档都有唯一的编号,记作html:xxxxx,xxxxx是一串数字,即Html文档的身份证号码,这个能唯一标识一个Html文档,那么这个号码就是一个URI。

而URL则通过描述是哪个主机上哪个路径上的文件来唯一确定一个资源,也就是定位的方式来实现的URI。

对于现在网址我更倾向于叫它URL,毕竟它提供了资源的位置信息,如果有一天网址通过号码来标识变成了http://741236985.html,那感觉叫成URI更为合适。

HTTP请求报文

image

返回结果的HTTP状态码

状态码的职责是当客户端向服务器端发送请求时,描述返回的请求结果。 状态码如200 OK,以3为数字和原因短语组成。 数字中的第一位定义了响应类别,后两位无分类。响应类别有以下五种:

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

⭐2XX 成功

  • 200 OK:请求被正常处理
  • 204 No Content:一般在只需从客户端往服务器发送信息,而对客户端不需要发送新信息内容的情况下使用。
  • 206 Partial Content:客户端进行范围请求

⭐3XX 重定向

  • 301 Moved Permanently永久重定向。表示请求的资源已被分配了新的URI,以后应使用资源现在所指的URI。 也就是说,如果已经把资源对应的URI保存为书签了,这时应该按Location首部字段提示的URI重新保存。
  • 302 Found临时性重定向。表示请求的资源已被分配了新的URI,希望用户(本次)能使用新的URI访问。 和301 Moved Permanently状态码相似,但302状态码代表的资源不是被永久移动,只是临时性质的。换句话说,已移动的资源对应的URI将来还有可能发生改变。比如,用户把URI保存成书签,但不会像301状态码出现时那样去更新书签,而是仍旧保留返回302状态码的页面对应的URI(在Chrome中,还是会保存为重定向后的URI,不解)。
  • 303 See Other:表示由于请求对应的资源存在着另一个URI,应使用GET方法定向获取请求的资源。这与302类似,但303明确表示客户端应当采用GET方法获取资源。
  • 304 Not Modified:该状态码表示客户端发送附带条件的请求(指采用GET方法的请求报文中包含If-Match,If-Modified-Since,If-None-March,If-Range,If-Unmodified-Since中任一首部。)时,服务器端允许请求访问资源,但因发生请求为满足条件的情况后,直接返回304(服务器端资源未改变,可直接使用客户端未过期的缓存)。304状态码返回时,不包含任何响应的主体部分。
    304虽被划分在3XX类别,但是和重定向没有关系。
  • 307 Temporary Redirect:临时重定向。与302有相同含义。307遵守浏览器标准,不会从POST变成GET。

⭐4XX 客户端错误

4XX的响应结果表明客户端是发生错误的原因所在。

  • 400 Bad Request:表示请求报文中存在语法错误。
  • 401 Unauthorized:表示发送的请求需要有通过HTTP认证(BASIC认证、DIGEST认证)的认证信息。
  • 403 Forbidden:表明对请求资源的访问被服务器拒绝了。服务器端可在实体的主体部分对原因进行描述(可选)
  • 404 Not Found:表明服务器上无法找到请求的资源。除此之外,也可以在服务器端拒绝请求且不想说明理由时时用。

⭐5XX 服务器错误

5XX的响应结果表明服务器本身发生错误。

  • 500 Interval Server Error:表明服务器端在执行请求时发生了错误。也有可能是Web应用存在的bug或某些临时的故障。
  • 503 Service Unavailable:表明服务器暂时处于超负载或正在进行停机维护,现在无法处理请求。如果事先得知解除以上状况需要的时间,最好写入Retry-After首部字段再返回给客户端。

HTTP的瓶颈

  • 一条连接上只可发送一个请求(前面讲到,持久化可保持TCP连接状态,但仍完成一次请求/响应后才能进行下一次请求/响应,而管线化方式可让一个TCP连接并行发送多个请求。)
  • 请求只能从客户端开始。客户端不可以接收除响应以外的指令
  • 请求/响应首部未经压缩就发送。首部信息越多延迟越大
  • 发送冗长(重复)的首部。每次互相发送相同的首部造成的浪费较多

SPDY以会话层的形式加入,控制对数据的流动,但还是采用HTTP建立通信连接。因此,可照常使用HTTP的GET和POST等方法、Cookie以及HTTP报文等。

使用 SPDY后,HTTP协议额外获得以下功能。

  • 多路复用流:通过单一的TCP连接,可以无限制处理多个HTTP请求。所有请求的处理都在一条TCP连接上完成,因此TCP的处理效率得到提高。
  • 赋予请求优先级:SPDY不仅可以无限制地并发处理请求,还可以给请求逐个分配优先级顺序。这样主要是为了在发送多个请求时,解决因带宽低而导致响应变慢的问题。
  • 压缩HTTP首部:压缩HTTP请求和响应的首部。
  • 推送功能:支持服务器主动向客户端推送数据的功能。
  • 服务器提示功能:服务器可以主动提示客户端请求所需的资源。由于在客户端发现资源之前就可以获知资源的存在,因此在资源已缓存等情况下,可以避免发送不必要的请求。

WebSocket

利用AjaxComet技术进行通信可以提升Web的浏览速度。但问题在于通信若使用HTTP协议,就无法彻底解决瓶颈问题。

WebSocket技术主要是为了解决AjaxCometXMLHttpRequst附带的缺陷所引起的问题。

一旦Web服务器与客户端之间建立起WebSocket协议的通信连接,之后所有的通信都依靠这个专用协议进行。通信过程中可互相发送JSONXMLHTML或图片等任意格式的数据。

WebSocket的主要特点:

  • 推送功能:支持由服务器向客户端推送数据。
  • 减少通信量:和HTTP相比,不但每次连接时的总开销减少,而且由于WebSocket首部信息很小,通信量也相应较少

为了实现WebSocket通信,在HTTP连接建立之后,需要完成一次“握手”的步骤。

  • 握手·请求:为了实现WebSocket通信,需要用到HTTP的Upgrade首部字段,告知服务器通信协议发生改变,以达到握手的目的。
  • 握手·响应:对于之前的请求,返回状态码101 Switching Protocols 的响应。
    成功握手确立WebSocket连接后,通信时不再使用HTTP的数据帧,而采用WebSocket独立的数据帧。

由于是建立在HTTP基础上的协议,因此连接的发起方仍是客户端,而一旦确立WebSocket通信连接,不论服务器端还是客户端,任意一方都可直接向对方发送报文。

整理自:https://github.com/JChehe/blog/blob/master/posts/%E3%80%8A%E5%9B%BE%E8%A7%A3HTTP%E3%80%8B%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0.md

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.