计算机网络学习整理:Http协议

这里整理一下关于Http协议的学习笔记。html

注:文章中的部分图片来自于网络,侵删java


TCP/IP五层模型

大学学过计算机网络课的都知道OSI模型,即计算机网络模型,OSI模型由7层组成,除了OSI模型还有网络协议栈(也称为TCP/IP模型),其表示以下图(图片来自网络)所示:linux

通常咱们都使用五层模型的概念,这里就以五层模型来总结一下各个层的功能。web

  • 应用层:网络应用程序以及对应应用层协议存放的地方,常见如Http,SMTP以及FTP等协议。在两个应用程序进行网络交互的时候,应用层对应生成/获取到的信息分组称之为报文
  • 运输层:负责为端和端提供应用程序进程间的数据传输服务,这一层包含两个传输协议,传输控制协议即TCP和用户数据报协议UDP。TCP提供了可靠的面向链接的服务,使用TCP协议能够确保传递以及流量控制,而且提供拥塞控制。而UDP则提供无链接服务,不可靠,没有流量控制,也没用拥塞控制,单纯传递数据,不保证是否到达对应端。运输层封装的数据称之为报文段,报文段主要是将应用层的报文数据加上运输层生成的信息(如端口号)。
  • 网络层:网络层封装的数据称之为数据报,其主要包含运输层传递过来的报文段以及对应IP地址信息。
  • 链路层:网络层的数据报封装成合适在物理网络上传输的格式并传输,或将从物理网络接收到的帧解封,取出IP数据报交给网络层。因特网的网络层经过一系列路由器在源和目的地之间发送分组。为了将分组从一个节点(主机或路由器)移动到路径上的下一个节点,网络层必须依靠链路层的服务。链路层协议主要有以太网,WiFi以及电缆接入网的DOCSIS协议等。
  • 物理层:物理层负责将链路层传递过来的帧转化为一个一个比特进行传输。该层协议仍然与链路层相关,而且进一步与该链路(如单模光纤,双绞铜线等)的实际传输媒体挂钩

五层模型在实际中的通讯过程以下所示:面试

下面一图囊括了大部分的各层协议:chrome


应用层协议介绍

linux上的进程通讯学习文章中介绍了套接字的使用,主要用于进行远程进程之间的通讯,在计算机网络知识领域,套接做为进程与网络之间沟通的媒介提供了应用层与传输层连接的功能。在应用程序中咱们经过将在应用层封装好的报文交付于套接字使得网络进程之间能够进行相互的通讯。既然进行通讯,就要商量好对应的协议,应用层协议就定义了应用程序进程中如何进行传递报文的。数据库

应用层协议定义了以下的规则:浏览器

  • 交换报文的类型,例如请求报文以及响应报文。
  • 各个报文类型的语法,如报文中各个字段以及字段描述。
  • 字段的语义。
  • 一个进程什么时候以及如何发送报文,接受报文的规则。

关于应用层协议能够查看RFC文档来了解对应详细规则。缓存


Http协议

Http(超文本传输协议)是互联网上应用最为普遍的一种网络协议。全部的WWW文件都必须遵照这个标准。Http协议使用TCP协议做为传输层的支撑,保证了在传输过程当中的可靠性,可是,Http也是一个无状态的协议,即一个请求对应一次响应,服务器只响应客户端的请求,不记录任何状态信息,一秒内发送2次相同的请求,服务器就会响应2次。服务器

当使用TCP的时候,TCP提供了两种链接的方式:非持续性链接以及持续性链接(默认),区别在于每一个请求/响应是单独的一个TCP链接发送仍是全部的请求都由一个TCP链接发送。

Http报文分为两种:请求报文和响应报文。请求报文的结构以下:

首先查看一个简单的请求报文:

GET /dir/page.html HTTP/1.1
Host: www/baidu.com
Connection: close
User-Agent: Mozilla/5.0
Accept-language: fr

报文的第一行称之为请求行,后续的称之为首部行(请求头部)。请求行包含三个字段,分别是方法字段,URL字段以及Http版本字段

关于方法字段,HTTP1.0定义了三种请求方法: GET, POST 和 HEAD方法。HTTP1.1新增了五种请求方法:OPTIONS, PUT, DELETE, TRACE 和 CONNECT 方法。下面是各个方法的意义(图片截图来自菜鸟教程):

Http中定义了大量的请求头部以及响应头部,详细的能够查看这篇文章,这里就不详细罗列出来了。从上面的图中还能够看到最后一行为请求数据(请求实体),请求实体在POST中会进行填充数据,如表单数据。

接下来看下响应报文,响应报文的结构与消息报文的结构一致,惟一不一样的是叫法,第一行为状态行,而后是响应行(状态行),响应头部,空行和响应正文。看下例子:

HTTP/1.1 200 OK
Date: Mon, 27 Jul 2009 12:28:53 GMT
Server: Apache
Last-Modified: Wed, 22 Jul 2009 19:15:56 GMT
ETag: "34aa387-d-1568eb00"
Accept-Ranges: bytes
Content-Length: 51
Content-Type: text/plain

关于Http响应状态码介绍以下:

罗列一些例子以下:

在Http使用中,我以为须要注意的是两点,一个cookie的使用,另外一个是Http的缓存机制。下面对两方面的知识作个整理。

首先是cookie,上述也介绍了Http是一个无状态的,所以也简化了服务器的设计。然而从用户的角度而言,用户更倾向于保存在某个网站上保存必定的信息,如用户信息(chrome上会常常看到提示咱们是否保存用户信息),这时候cookie就应运而生了。HTTP Cookie(也叫Web Cookie或浏览器Cookie)是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上。一般,它用于告知服务端两个请求是否来自同一浏览器,如保持用户的登陆状态。Cookie使基于无状态的HTTP协议记录稳定的状态信息成为了可能。

一次完整的cookie使用记录以下,更详细的能够查阅这篇文章

接下来就是Http缓存操做,首先自主思考一下若是咱们须要本身实现该怎么作呢?

  • 首先考虑一种状况,服务器的数据永远是不变的(某张具体的jpg),那么咱们就能够在服务器返回字段的时候标明这个数据不会变,客户端在第二次请求的时候发现有缓存,直接使用就能够了。一样的弱可变性也能这么实现。好比我一张图片一个月后过时,那么服务器告诉客户端一个月后过时就能够了。(强制缓存)
  • 其次可能存在另外一种状况,服务器的数据是可变的,这时候怎么办呢?能够这么作,假设咱们在获取一个文件,服务器返回文件的时候把文件的md5告诉咱们,客户端把值存下来,在客户端第二次请求的时候,咱们把md5传过去,服务器把md5跟最新的文件的md5作比对,若是相同,返回一个相同的字段给客户端,客户端直接使用本地缓存便可;若是不相同,那么服务器再把文件以及md5返回给客户端。(对比缓存)

既然咱们能想到,开发Http协议的人可能比咱们更厉害咯,下面总结一下这两种缓存方式对应Http的实现。

首先是Expires(对应第一种缓存状况)以及Pragma,Expires,Pragma都是Http1.0的产物,Pragma主要控制是否容许客户端缓存,若是服务器返回了:

Pragma: no-cache

那么就是告诉客户端禁止缓存,每次数据都从服务器去拿。Expires字段来自响应实体,服务器在返回数据时候能够加上当前字段来设置缓存时间,如底下返回数据:

Expires: Wed, 21 Oct 2015 07:28:00 GMT

Expires返回一个GMT标准时间,客户端获取以后存入数据库,在缓存时间内使用缓存,不然再次请求服务器。若是Expires,Pragma一块儿返回,Pragma的优先级高于Expires,即客户端不容许缓存。

响应报文中Expires所定义的缓存时间是相对服务器上的时间而言的,其定义的是资源“失效时刻”,若是客户端上的时间跟服务器上的时间不一致(特别是用户修改了本身电脑的系统时间),那缓存时间可能就没啥意义了。

接着介绍一下Cache-Control,Cache-Control在Http1.1中实现。Cache-Control的请求实体可选参数以下:

响应实体可选参数以下:

Cache-Control配合其余关键字能实现咱们上面说的任何一种缓存方式。这边咱们说的对应于响应实体Cache-Control,由于相对于客户端开发而言,客户端对于服务端的缓存策略控制相对叫弱。Cache-Control中经过max-age也实现了Expires的功能,不一样的是,max-age返回的是时间值,而不是明确的时间,如:

Cache-Control: max-age=36000

因为返回的是时间值,就能够趋避客户端时间与服务器时间相差较大的状况,从而解决了Expires的局限性。与Pragma对应的是no-store参数。

对比缓存实现主要有两种途径:Last-Modified/If-Modified-Since以及Etag/If-None-Match方式。

使用Last-Modified/If-Modified-Since方式的流程图以下:

Last-Modified主要回传的是对应文件服务器端最后修改的时间,客户端在第二次调用时将Last-Modified得到到的value存放在If-Modified-Since中从新传给服务端,服务端作数据比对,并返回对应的状态码给客户端,若是返回304,表明服务器数据未更新,直接使用客户端维护的缓存便可;更新了,返回200并带上数据发送给客户端。

经过Last-Modified也有必定的局限,若是一个文件更新了可是其内容本质上不变,那么服务器也会认为客户端须要进行更新数据,从而返回服务器认为更新后的,可是实际上没有更新的数据,这样形成了客户端从新得到一个如出一辙的文件。

因为Last-Modified的局限性,所以引入了Etag参数,Etag表明了文件的惟一标识码(如md5),Etag和If-None-Match一同使用,使用的流程以下图:

流程跟Last-Modified/If-Modified-Since一致。

总结一下相关关键字调用的优先级:

Pragma -> Cache-Control (max-age>Etag>Last-Modified)-> Expires

放上一张缓存流程图:


这里总结一下一题面试题吧,叙述一下在浏览器中输入http://www.baidu.com后发生的状况:

  1. 判断本地是否有缓存,若是是强制缓存,则直接返回缓存数据,请求执行结束,若是是对比缓存,则向服务端在请求体中添加参数If-None-Match/If-Modified-Since。
  2. DNS解析域名获取目标IP地址。
  3. 进行TCP三次握手过程,确认链接。
  4. 服务端发送数据,进行四次握手,一次请求结束。

参考资料

https://baike.baidu.com/item/%E4%BA%94%E5%B1%82%E5%9B%A0%E7%89%B9%E7%BD%91%E5%8D%8F%E8%AE%AE%E6%A0%88/8353884?fr=aladdin

<<计算机网络-自顶向下方法>>

http://www.cnblogs.com/Joans/p/3956490.html

http://www.javashuo.com/article/p-urqfeegv-ec.html

http://www.javashuo.com/article/p-drsaueus-ck.html

http://imweb.io/topic/5795dcb6fb312541492eda8c

相关文章
相关标签/搜索