作为上层应用的开发者,对网络通讯知识平时接触的少,久而久之很多都忘了,但这又是IT人的饭碗,出去面试,这些基础知识说不出一二三,得会鄙视。本篇就为您全面解析这些基础知识,只要原理,不讲细节,只需理解,不必深究,通过场景和过程演绎,尽量做到浅显易懂。本文篇幅较长,需耐心阅读。
目录
一、前言
二、OSI七层模型
二、TCP/UDP
1、TC协议
(1)创建连接
(2)数据传输
(3)关闭连接
2、UDP
三、HTTP1.1/HTTP2
1、HTTP 1.1
(1) 组装请求报文
(2) 发送请求报文
(3)接受响应报文
2、HTTP2.0
(1)多路复用
(2)Header压缩
(3)服务端推送
(4)小结
四、HTTPS
1、通讯流程
(1)对称加密报文
(2)非对称加密密钥
(3)数字证书
(4)SSL连接过程
2、协议加密层
3、小结
五、总结
我们从七层模型说起,这是整个网络通讯技术的基石,所有的网络设备和通讯协议都依附于这七层模型上。话不多说先上图。
1、物理层
物理层是OSI模型的第一层,主要功能是:利用传输介质为数据链路层提供物理连接,实现比特流的透明传输。它负责管理电脑通信设备和网络媒体之间的互通。该层传递是比特流,主要的设备有包括了针脚、集线器、中继器、网卡、主机接口卡等。
2、数据链路层
数据链路层主要功能:在物理层提供比特流服务的基础上,建立相邻结点之间的数据链路,通过差错控制提供数据帧(Frame)在信道上无差错的传输。
在计算机网络中由于各种干扰的存在,物理链路是不可靠的,因此,通过差错控制、流量控制方法,使有差错的物理线路变为无差错的数据链路,即提供可靠的通过物理介质传输数据的方法。
数据链路层将比特组合成字节进而组合成帧(frame),通过MAC地址进行寻址,访问介质。
我们常用的接入交换机(二层交换机)就是工作在这层,交互机连接的设备在同一个广播域,如果想抓某个设备的网络包,就可以使用交换机将电脑和设备互联。
3、网络层
网络层是七层模型中复杂的,茫茫机海中,两台计算机顺利的牵手就靠网络层,比如我们访问百度,将数据链路层提供的帧转化成数据包(packets),该数据包包含IP头。通过路径选择、分段组合、顺序、进/出路由等控制,将我们机器的访问信息从我们的机器传送到百度的服务器,这中间经过很多通信子网,也有N个路径可以选择,如何选择一条最优路径,是该层重要的功能。
在数据链路层,在一个广播域的内部采用的是MAC寻址;在网络层,实现不同的子网平面间采用的IP寻址。所以和IP相关的都是三层,比如我们ping 一个ip地址看通不通,就是看网络层是否连通。
这层的主要设备就是路由器,熟知的是家庭路由器(现在都被称为wifi)。
4、传输层
传输层起到承上启下的作用,一方面向高层屏蔽下层数据通信的细节,即向用户透明地传送报文,另一方面将数据传递到网络层,并确保数据能正确无误地传送到网络层。因此,传输层提供建立、维护和拆除传输连接的功能,跟踪数据单元碎片、乱序到达的 数据包和其它在传输过程中可能发生的危险,保证报文的正确传输。
我们通常说的检查下443,80端口通不通,就是指的是传输层端口,今天要讲的TCP/UDP协议就是该层的协议,另外大名鼎鼎的负载LVS也是工作在四层上。
5、会话层
会话层是用户应用程序和网络之间的接口,主要任务是:向两个实体的表示层提供建立和使用连接的方法。将不同实体之间的表示层的连接称为会话。因此会话层的任务就是组织和协调两个会话进程之间的通信,并对数据交换进行管理。会话控制和远程过程调用均属于这一层的功能。
6、表示层
表示层对来自应用层的命令和数据进行解释,对各种语法赋予相应的含义,并按照一定的格式传送给会话层。其主要功能是“处理用户信息的表示问题,如编码、数据格式转换和加密解密”等。
数据的压缩和解压缩, 加密和解密等工作都由表示层负责。
7、应用层
应用层是计算机用户,以及各种应用程序和网络之间的接口,其功能是直接向用户提供服务,完成用户希望在网络上完成的各种工作。应用层为用户提供的服务和协议,比如http,ftp,telnet等。
在日常工作中,将传输层以上统称为应用层,划分TCP/IP五层模型。
先来看TCP协议,提供可靠性的服务,所谓可靠性,就是要将两台计算器的信息准确无误的传递,就好比两个人通话,要传递每一个字,不能听一句没一句的。那么为了保证信息的无误,TCP协议就需要有以下的约束。
(1)、一对一的连接,在数据传输时,客户端与服务器端需要通过"三次握手"建立"隧道",且这个通道只能够被客户端和服务端使用,传输完毕后,通过"四次挥手"关闭"隧道"。
(2)、传输过程中确保数据的准确性。虽然建立的一对一的通道,但是由于网络的抖动,路由的拥塞等情况,不能确保传递的数据都是准确的,那么tcp通过一系统复杂的控制和算法解决这个问题,主要有以下几点。
这个过程的原理和我们的上传下载文件时,通过MD5值校验非常类似。
下面我们按照创建连接,数据传输,关闭连接三个阶段为大家详细介绍。
TCP通过"三次握手"过程实现连接的创建。
我们通过狗剩子和小胡子队长的通话来演绎下三次握手
1) 客户端向服务端发送一个SYN同步报文,该报文段中包含初始的序列号Seq。客户端进入SYN-SENT状态,等待服务端确认。
场景演绎:狗剩子给小胡子队长打电话,电话打通后,狗剩子自报家门"队长,我,狗剩子"。狗剩子等待队长的确认。
2)服务端接收到客户端的SYN报文后,回复SYN+ACK报文,该报文段包含序列号Seq(Seq=Y),以及确认序列号ack(ack=X+1,表示接收到了Seq=X的序列报文),服务端进入SYN-RECEIVED状态。
场景演绎:小胡子队长接到狗剩子电话,给出确认回复:"剩子啊,啥事"。
3) 客户端接收到服务端的确认报文,再次发送ACK报文,该报文包含序列号Seq(Seq=Z),确认序列号ack=y+1,完成三次握手。
场景演绎:狗剩子听到小胡子队长的回复,非常高兴,立即回复道"找您汇报点事"。下面就可以正常的通话了。
接收方的确认报文,都包含一个确认序列号ack,该值是发送方报文中序列号Seq再加1,告诉发送方,该Seq序号的报文我已经接受,也就是我们上面说的有序传递。
我们来思考一个问题,为什么不是两次握手,或者是四次握手完成连接呢。我们来分析下。
场景演绎:小胡子队长很忙的,等上一段时间没有听到狗剩子的回复,"八嘎呀路",气急败坏挂掉电话,不要指望他能等你等到死。
第一次,狗剩子:"队长,我,狗剩子"。等待中...
第二次,小胡子队长:"剩子啊,啥事"。等待中...
第三次, 狗剩子:"找您汇报点事"。等待中...
第四次,小胡子队长:"听到了,你到底啥事啊"。等待中...
狗剩子:"队长快跑,我们被包围了"。
小胡子队长:"八嘎呀路"。
增加了延迟,浪费了带宽,并没有提升多少效果。
我们用wireshark抓包看下客户端访问百度三次握手的报文
三次握手后,开始https的报文(后面讲到)。
TCP连接是全双工的连接,也就是客户端到服务端,以及服务端到客户端存在双向的通道。
数据传输过程中,TCP协议做了大量的算法和优化,无外乎围绕以下两点展开:
对于第一条,这里我们重点分析下重传机制。
1) 重传机制
如果发送了丢包,就需要启动重传机制,包括重复累积确认重传,以及超时重传。
重复累积确认重传
1、假设有一个数据包4096个字节,被分割为4个小包(每个1024个字节)并发出去。假设初始Seq为1,后续序列号则为实际字节数+1。
2、接受方在接收到第一个报文时,返回确认信息,ack=1025,表示第一个1024个字节报文已收到。
3、第二条报文由于某种原因丢失,接受方没有收到,而第三,四条报文收到,接受方并不是回复三,四条报文确认信息,而是继续回复第二条报文的确认序号1025。
4、发送方在收到3个重复的ack=1025时,判断第二个报文已经丢失,启动重传,再次发送第二条报文。
5、接受方正确的接受了第二条报文,由于第三,四条报文已经接受到了,不需要重复发送,直接回复第四条确认序号4097。
6、发送方接收到第四条确认号后,知道二三四条报文已经收到,继续第五条的发送。
超时重传
重复累积确认的前提是丢失了部分包,如果连第一条报文都没收到,怎么解?这就需要超时重传机制。
发送方使用一个保守估计的时间作为收到数据包的确认的超时上限(RTO)。如果超过这个上限仍未收到确认包,发送方将重传这个数据包。每当发送方收到确认包后,会重置这个重传定时器。
接下来我们看下第二条,TCP通过一系列方法进行了传输的控制,确保弹性适应负载,包含流量控制和拥塞控制。
2)流量控制
发送方不知道服务器的处理能力,使劲的发送报文,会导致接收方来不及处理,就好比小胡子队长中文一般般,狗剩子还用地道的方言不停的唠叨。那怎么办,接受方要告知发送方我的接受能力,发送方根据接收方的能力来发送数据。好比两个人对话要在一个频道上,否则鸡同鸭讲。
这种方式叫做滑块窗口协议。
建立连接时,各端分配一个缓冲区用来存储接收的数据,并将缓冲区的尺寸发送给另一端。接受方发送的确认消息中包含了自己剩余的缓冲区尺寸。剩余缓冲区空间的数量叫做窗口(rwwd)。其实就是互相知道彼此剩余的缓冲区大小。
如果接受方的窗口为0,那么发送方就停止发送,开始了“保持定时器”。当“保持定时器”到期时,TCP发送方尝试恢复发送一个小的ZWP包,尝试三次,如果还是0,一般就是断掉连接。
3)拥塞控制
流程控制仅考虑了接受方的能力,但是传输是个全局过程,还需要考虑整个网络的状况。为了防止网络拥塞现象,TCP提出了一系列的拥塞控制机制。
慢启动
TCP创建连接后,如果一开始就发送大量的包,可能由于网络中路由器的缓存耗尽,导致拥塞。TCP采用"试探"的方式,根据网络的状态逐步增加发送量,从而避免上述现象。
1、TCP连接创建后,初始化拥塞窗口(cwnd)为1个报文段(MSS大小),发送方发送一个报文。
2、发送方接受到ACK后,cwnd设置为2(cwnd=1*2),可发送两个报文。
3、发送方接受到两个报文的ACK后,cwnd设置为4(cwnd=2*2),可发送4个报文。
4、以此类推,每次ACK,cwnd++,每经过一个RTT时间,cwnd*2。在这期间cwnd呈指数级增长。
这个涨幅是很快的,最大程度利用网络带宽资源,但不可能无限增长下去,TCP设置了慢启动门限(ssthresh)的状态变量,当cwnd
拥塞避免
拥塞避免是将慢启动的指数增长改变成线性增长,当一个窗口内所有报文都确认后,cwnd才+1,也就是一个RTT后,cwnd++。
继续上面的例子,比如ssthresh=4,达到拥塞避免的条件,那么确认4条报文都返回后,cwnd才加1。
虽然速度慢下来了,但还是处于增长的趋势,我们不考虑其他的限制因素,那么总会有个时候到达上限发送拥塞,判断发生了拥塞的情况,就是前面说的丢包,有两种场景。
超时的情况,如果发送方判断超过了RTO规定的时间,没有收到报文确认,进行如下的"激烈"处理。
1、把ssthresh降低为cwnd值的一半
2、把cwnd重新设置为1
3、重新进入慢启动过程。
重复累积确认的情况,即3次收到重复ACK,确认该报文丢失,将进入快速重传
1.把ssthresh设置为cwnd的一半
2.把cwnd再设置为ssthresh的值(具体实现有些为ssthresh+3)
3.重新进入拥塞避免阶段。
后来又有改进的快速恢复算法,这里就不一一介绍。
从整体上来讲,TCP拥塞控制窗口变化的原则是加法增大、乘法减小。较好地保证流之间的公平性,因为一旦出现丢包,那么立即减半退避,可以给其他新建的流留有足够的空间,从而保证整个的公平性。
TCP的连接关闭,采用"四次挥手"完成。
1、客户端主动关闭连接,发送FIN报文,进入FIN-WAIT1阶段。
场景演绎:狗剩子:"队长,我汇报完了",等待中...
2、服务端接受到报文后,先发送ACK确认。如果还有报文没有发送关闭,继续发送报文,进入CLOSE-WAIT阶段。
场景演绎:队长:"你等下,我还有点事和你交代下"
3、客户端接受到ACK确认报文后,进入FIN-WAIT2阶段,接受剩余报文的同时,同时等待FIN关闭报文。
场景演绎:队长:"吧唧吧唧..."
4、服务端报文全部发送完毕后,发送FIN报文,进入LAST-ACK状态
场景演绎:队长:"好了,你忙吧"。
5、客户端接受到FIN报文,发送ACK确认报文。同时进入TIME-WAIT状态。
场景演绎:狗剩子:"队长,收到",等待中...
6、服务端接受到ACK报文,直接关闭连接。
7、客户端等待2MSL(Max Segment Lifetime),确保服务端关闭后,关闭连接。为什么要有TIME-WAIT状态,而不是直接关闭,效率岂不是更高?如果服务端没有接受到ACK报文,会重新发送FIN,而此时如果客户端已关闭,会导致收不到ACK报文,所以TCP协议处处都是以可靠为设计原则。
场景演绎: 狗剩子:等待一段时间,确认队长已经关闭,挂断电话。
TCP连接为全双工连接,不一定是从客户端发起断连,也可以从服务端发起断连。
这里我们介绍了TCP协议的主要特点,至于TCP协议的报文可以参考RCF 793,不做详述。
总之,TCP使用一系列的控制措施,确保其"准,稳",但是也必然牺牲了"快"。
同样,我们也看下四次挥手的报文,这次我们用tcpdump抓包(在wireshark上抓包经常乱序)
F代表FIN,.表示ACK
与TCP相比较,UDP属于不可靠的无连接协议,发送方只负责将报文传递出去,但是报文最终能否完整的到达接收方,无法保证,在可靠性上无法与TCP相比,但是UDP也有以下优势:
(1)不需要与接收方建立连接,只需要将报文封装好,发送出去即可,其传输的速度取决于生成数据的能力,以及带宽的限制。
(2)UDP的信息报的标题很短,只有8个字节,相对于TCP的20个字节信息包的额外开销很小。
(3) 由于传输数据不建立连接,因此也就不需要维护连接状态,包括收发状态等,因此一台服务机可同时向多个客户机传输相同的消息。
(4)吞吐量不受拥挤控制算法的调节,只受应用程序生成数据的速率、传输带宽、源端和终端主机性能的限制。
(5) UDP是面向报文的。发送方的UDP对应用程序交下来的报文,在添加首部后就向下交付给IP层。既不拆分,也不合并,而是保留这些报文的边界,因此,应用程序需要选择合适的报文大小。
总之,UDP具有"短平快"的优势,但是"准头"不够。如果TCP看做是"发短信",那么UDP就是"漂流瓶"。
TCP | UDP | |
可靠性 | 可靠 | 不可靠 |
连接 | 面向连接 | 无连接 |
传输方式 | 面向字节流 | 面向报文 |
传输效率 | 高 | 低 |
双工性 | 全双工 | 一对一,一对多,多对一,多对多 |
流量控制 | 滑动窗口 | 无 |
拥塞控制 | 慢启动,拥塞避免,快重传,快恢复 | 无 |
应用场景 | 文件传输,网页浏览等 | 视频,语音,QQ等 |
HTTP即是一个"古老"协议,与互联网同步诞生;同时又是一个充满朝气的"年轻"协议,不断的自我完善和更新。已经迭代了多个版本,主要的如下:
版本 | 产生时间 | 功能 | 发展现状 |
HTTP/0.9 | 1991 | 适用于各种数据信息的简洁快速协议,单仅限于 | 没有作为标准 |
HTTP/1.0 | 1996 | 传输内容格式不限制,增加PUT、PATCH、HEAD、 OPTIONS、DELETE命令 | 正式作为标准 |
HTTP/1.1 | 1997 | 持久连接(长连接)、节约带宽、HOST域、管道机制、分块传输编码 | 已广泛使用 |
HTTP/2.0 | 2015 | 多路复用、服务器推送、头信息压缩、二进制协议等 | 逐渐覆盖 |
HTTP1.1是目前广泛使用的协议,发送一个http的请求,需要经历三个阶段,组装请求报文,发送请求报文,接受响应报文。
一个HTTP请求报文由请求行(request line)、请求头部(header)、空行和请求数据4个部分组成。
我们抓包对照看下:
请求行由请求方法字段、URL字段和HTTP协议版本字段3个字段组成,它们用空格分隔。例如,POST /q.cgi HTTP/1.1
HTTP协议的请求方法有GET、POST、HEAD、PUT、DELETE、OPTIONS、TRACE、CONNECT。其中常用的GET,POST。
请求头部由关键字/值对组成,每行一对,关键字和值用英文冒号“:”分隔,以下是部分列表
Header | 解释 | 示例 | 使用场景 |
---|---|---|---|
Accept | 指定客户端能够接收的内容类型 | Accept: text/plain, text/html | |
Accept-Charset | 浏览器可以接受的字符编码集。 | Accept-Charset: iso-8859-5 | |
Accept-Encoding | 指定浏览器可以支持的web服务器返回内容压缩编码类型。 | Accept-Encoding: compress, gzip | |
Accept-Language | 浏览器可接受的语言 | Accept-Language: en,zh | |
Accept-Ranges | 可以请求网页实体的一个或者多个子范围字段 | Accept-Ranges: bytes | |
Authorization | HTTP授权的授权证书 | Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== | |
Cache-Control | 指定请求和响应遵循的缓存机制 | Cache-Control: no-cache | 一般使用no-cache,表示可以使用缓存,但是需要服务端进行资源验证,配合If-Modified-Since使用 |
Connection | 表示是否需要持久连接。(HTTP 1.1默认进行持久连接),keep-alive表示长连接,close表示短连接 |
Connection: close | 1.1版本默认开启 |
Cookie | HTTP请求发送时,会把保存在该请求域名下的所有cookie值一起发送给web服务器。 | Cookie: $Version=1; Skin=new; | 客户端和服务端都可以设置,一般放置需要持久化的共享数据,如登录状态(用户清除cookie将失效) |
Content-Length | 请求的内容长度 | Content-Length: 348 | |
Content-Type | 请求的与实体对应的MIME信息 | Content-Type: application/x-www-form-urlencoded | application/json表示传递json串 |
Date | 请求发送的日期和时间 | Date: Tue, 15 Nov 2010 08:12:31 GMT | |
Expect | 客户端用来告知服务器,期望出现的某种特定行为。 | Expect: 100-continue | |
From | 用来告知服务器使用用户代理的用户的电子邮件地址 | From: [email protected] | |
Host | 指定请求的服务器的域名和端口号,1.1版本新增 | Host: www.zcmhi.com | 一台服务器上可以部署多个网站,服务器可以根据该值识别请求网站 |
If-Match | 与服务端的ETag比较,只有一致服务器才能处理该内容。 | If-Match: “737060cd8c284d8af7ad3082f209582d” | 根据上一次服务器返回的ETag设定 |
If-Modified-Since | 如果请求的部分在指定时间之后被修改则请求成功,未被修改则返回304代码 | If-Modified-Since: Sat, 29 Oct 2010 19:43:31 GMT | 根据服务器返回的Last-Modified设定 |
If-None-Match | 与服务端的ETag比较,不一致服务器才能处理该内容,与If-Match相反。 | If-None-Match: “737060cd8c284d8af7ad3082f209582d” | |
If-Range | 字段值若是更与ETge 值或更新日期时间一致,那么就作为范围请求处理。若不一致,则忽略范围请求,返回全部资源 |
If-Range: “737060cd8c284d8af7ad3082f209582d” | |
If-Unmodified-Since | 只在实体在指定时间之后未被修改才请求成功,否则返回412错误码。这个和if-Modified-SInce相反。 | If-Unmodified-Since: Sat, 29 Oct 2010 19:43:31 GMT | |
Max-Forwards | 限制信息通过代理和网关传送的时间 | Max-Forwards: 10 | |
Pragma | 用来包含实现特定的指令 | Pragma: no-cache | |
Proxy-Authorization | 连接到代理的授权证书 | Proxy-Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== | |
Range | 只请求实体的一部分,指定范围,1.1版本新增 | Range: bytes=500-999 | 断点续传 |
Referer | 先前网页的地址,该链接的宿主url | Referer: http://www.zcmhi.com/archives/71.html | 一般用于防盗链 |
TE | 客户端愿意接受的传输编码,并通知服务器接受接受尾加头信息 | TE: trailers,deflate;q=0.5 | |
Upgrade | 向服务器指定某种传输协议以便服务器进行转换(如果支持) | Upgrade: HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11 | |
User-Agent | User-Agent的内容包含发出请求的用户信息 | User-Agent: Mozilla/5.0 (Linux; X11) | 在webapp中,使用该字段区别是android还是ios |
Via | 通知中间网关或代理服务器地址,通信协议 | Via: 1.0 fred, 1.1 nowhere.com (Apache/1.1) | |
Warning | 关于消息实体的警告信息 | Warn: 199 Miscellaneous warning |
HTTP是基于TCP协议的,也就是必须经过TCP三次握手建立连接后,才能发送请求报文。1.0版本每个请求都需要创建连接,导致效率很低;1.1版本进行了改进,支持长连接和请求流水线pipelining(也就是header中的Connection默认设置为keep-alive),在pipelinling中发送多个请求,避免了每次请求创建和关闭连接带来的消耗和延迟。
如果客户端已完成请求,但是TCP连接一直保持长链,那么也是浪费资源。在ng,apache等服务端都可以设置keepAlive的超时时间,并随响应报返回客户端,比如Keep-Alive:timeout:20,表示TCP通道可以保持20s,没有新的请求就会关闭,当然不告诉客户端也没关系,服务端也可以通过"四次挥手"关闭通道。
服务端接受到请求,处理完成后,返回响应报文。与请求报文的格式类似,也是有响应行,响应头,响应体组成。
响应行一般由协议版本、状态码及其描述组成 比如 HTTP/1.1 200 OK。常用的状态码如下:
100~199:表示成功接收请求,要求客户端继续提交下一次请求才能完成整个处理过程。
200~299:表示成功接收请求并已完成整个处理过程。200表示成功,
300~399:为完成请求,客户需进一步细化请求。302表示重定向到新的url,304表示客户端缓存没有过期,还可以使用,
400~499:客户端的请求有错误。400表示语法错误,服务器无法处理;404,请求资源不存在。
500~599:服务器端出现错误。500表示服务器未知错误;502充当代理角色,未收到上游的响应;503表示服务器不可用(宕机或者挂掉)。
响应头 | 说明 | 示例 | 使用场景 |
---|---|---|---|
Access-Control-Allow-Origin | 指定哪些网站可以跨域源资源共享 |
Access-Control-Allow-Origin: * |
|
Accept-Patch | 指定服务器所支持的文档补丁格式 | Accept-Patch: text/example;charset=utf-8 | |
Accept-Ranges | 服务器所支持的内容范围 | Accept-Ranges: bytes |
|
Age | 响应对象在代理缓存中存在的时间,以秒为单位 | Age: 12 |
|
Allow | 用于通知客户端能够支持 的http方法,如GET,POST | Allow: GET, HEAD |
|
Cache-Control | 通知客户端是否可以缓存这个对象及缓存有效时间。其单位为秒 | Cache-Control: max-age=3600 |
|
Connection | 针对该连接所预期的选项 | Connection: close |
|
Content-Disposition | 对已知MIME类型资源的描述,浏览器可以根据这个响应头决定是对返回资源的动作,如:将其下载或是打开。 | Content-Disposition: attachment; filename="fname.ext" | |
Content-Encoding | 响应资源所使用的编码类型。 | Content-Encoding: gzip |
|
Content-Language | 响就内容所使用的语言 | Content-Language: zh-cn |
|
Content-Length | 响应消息体的长度,用8进制字节表示 | Content-Length: 348 |
|
Content-Location | 所返回的数据的一个候选位置 | Content-Location: /index.htm |
|
Content-MD5 | 响应内容的二进制 MD5 散列值,以 Base64 方式编码 | Content-MD5: IDK0iSsgSW50ZWd0DiJUi== | |
Content-Range | 如果是响应部分消息,表示属于完整消息的哪个部分 | Content-Range: bytes 21010-47021/47022 | |
Content-Type | 当前内容的MIME 类型 |
Content-Type: text/html; charset=utf-8 | |
Date | 此条消息被发送时的日期和时间(以RFC 7231中定义的"HTTP日期"格式来表示) | Date: Tue, 15 Nov 1994 08:12:31 GMT | |
ETag | 对于某个资源的某个特定版本的一个标识符,通常是一个 消息散列 | ETag: "737060cd8c284d8af7ad3082f209582d" | |
Expires | 告知客户端该资源的失效时间 | Expires: Thu, 01 Dec 1994 16:00:00 GMT | |
Last-Modified | 所请求的对象的最后修改日期(按照 RFC 7231 中定义的“超文本传输协议日期”格式来表示) | Last-Modified: Dec, 26 Dec 2015 17:30:00 GMT | |
Link | 用来表示与另一个资源之间的类型关系,此类型关系是在RFC 5988中定义 | Link: ; rel="alternate" |
|
Location | 用于在进行重定向,或在创建了某个新资源时使用。 | Location: http://www.itbilu.com/nodejs | 重定向时,告知定向的url资源 |
P3P | P3P策略相关设置 | P3P: CP="This is not a P3P policy! | |
Pragma | 与具体的实现相关,这些响应头可能在请求/回应链中的不同时候产生不同的效果 | Pragma: no-cache |
|
Proxy-Authenticate | 要求在访问代理时提供身份认证信息。 | Proxy-Authenticate: Basic |
|
Public-Key-Pins | 用于防止中间攻击,声明网站认证中传输层安全协议的证书散列值 | Public-Key-Pins: max-age=2592000; pin-sha256="……"; | |
Refresh | 用于重定向,或者当一个新的资源被创建时。默认会在5秒后刷新重定向。 | Refresh: 5; url=http://itbilu.com | |
Retry-After | 如果某个实体临时不可用,那么此协议头用于告知客户端稍后重试。其值可以是一个特定的时间段(以秒为单位)或一个超文本传输协议日期。 |
|
|
Server | 服务器的名称 | Server: nginx/1.6.3 |
|
Set-Cookie | 设置HTTP cookie |
Set-Cookie: UserID=itbilu; Max-Age=3600; Version=1 | |
Status | 通用网关接口的响应头字段,用来说明当前HTTP连接的响应状态。 | Status: 200 OK |
|
Trailer | Trailer 用户说明传输中分块编码的编码信息 |
Trailer: Max-Forwards |
|
Transfer-Encoding | 用表示实体传输给用户的编码形式。包括:chunked 、compress 、 deflate 、gzip 、identity 。 |
Transfer-Encoding: chunked | |
Upgrade | 要求客户端升级到另一个高版本协议。 | Upgrade: HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11 | |
Vary | 告知下游的代理服务器,应当如何对以后的请求协议头进行匹配,以决定是否可使用已缓存的响应内容而不是重新从原服务器请求新的内容。 | Vary: * |
|
Via | 告知代理服务器的客户端,当前响应是通过什么途径发送的。 | Via: 1.0 fred, 1.1 itbilu.com (nginx/1.6.3) | |
Warning | 一般性警告,告知在实体内容体中可能存在错误。 | Warning: 199 Miscellaneous warning | |
WWW-Authenticate | 表示在请求获取这个实体时应当使用的认证模式。 | WWW-Authenticate: Basic |
虽然HTTP1.1中在性能上做了大量的优化,如长连接,但是缺陷也很明显。
(1)线头阻塞(Head-Of-Line Blocking),HTTP1.1通过pipelining管道技术使客户端能并发多个请求(同一个域名一般可以发送6个),但是在接受response时,需要按照顺序处理,如果第一个请求阻塞了,那么后面的也就无法处理了。
(2)开销过大,1.1版本中header携带的内容过大,增加了传输成本。
在HTTP2.0的版本中,在性能上做了大量的工作,之前我们做过一个实测,HTTP2.0要比HTTP1.1传输性能上提升30%。大家可以直观感受下演示。那2.0的版本是怎么做到的呢?
http2.0采用了多路复用技术,很好的解决了浏览器限制同一个域名下的请求数量的问题,同时也更容易实现全速传输。
场景演绎:我们来做个类比,买了新房子,订购了一套全新家具,厂家有两种发货方式,一种是做好一件家具,就发送一件,这就是HTTP1.1的方式,还有一种,将家具的零部件打包一起,做好标记,分批运送到家里再安装,这个就是HTTP2.0的方式。
实现这种传输方式的核心在于使用了新的二进制分帧技术,HTTP1.1版本请求和响应中使用的文本格式,这种模式对于计算机来说效率并不高,HTTP2.0版本使用了二进制进行编码。下面介绍几个关键术语:
关系总结如下:
HHTTP1.1版本中的并发限制,线头阻塞等问题,HTTP/2 中通过二进制分帧技术得到了解决,实现了完整的请求和响应复用:客户端和服务器可以将 HTTP 消息分解为互不依赖的帧,然后交错发送,最后再在另一端把它们重新组装起来。
在 HTTP/1.x 中,元数据始终以纯文本形式,通常会给每个传输增加 500–800 字节的开销。如果使用 HTTP Cookie,增加的开销有时会达到上千字节。 为了减少此开销和提升性能,HTTP/2 对请求和响应标头元数据进行压缩。中心的思路就是"差异化增量"式,每次仅发送差异化的数据。具体的流程如下:
例如下图中的两个请求, 请求一发送了所有的头部字段,第二个请求则只需要发送差异数据,这样可以减少冗余数据,降低开销。
服务端推送一直是HTTP协议的痛点,多路复用技术打破了严格意义上的请求-响应,其数据流模式也为开启服务端推送打下来基础。
当我们请求一个页面,页面中包含了内联的脚本,样式等,服务端不需要等客户端发起资源请求,主动的将这些资源推送到客户端,减少了请求,降低了延迟。
当然,客户端可以根据情况,选择接受还是拒收以及缓存。
HTTP2.0以其优越的性能,得到了主流web容器以及客户端的支持,可以参见支持Http2.0的服务端和客户端列表,
HTTP2.0不仅用在restful通讯模式,还用在了RPC模式,著名的gRPC的就是使用http2.0作为传输协议。
HTTP协议采用的明文传递,其请求头(响应头)请求行(响应行)通过抓包等方式就能获取(如图),如果银行等一些金融机构,提供这种网站进行转账,打死我们也不敢用啊,除非钱多人傻的。
最好的方式就是对报文进行加密,而且只有客户端与服务端能能解密。我们先来了解下几种加密算法:
我们演绎HTTPS通讯过程。
首先,使用对称加密的方式,假设客户端生成会话密钥A,用该密钥对请求报文加密,服务端也使用该密钥进行解密,获取报文。
这个方案的前提是,服务端需要提前获取这个密钥A。
客户端需要将密钥A发送给服务端,但是不能直接发,需要对密钥A加密成密文。这时候不能再用对称加密了,否则成了死循环。所以考虑使用非对称加密,假设服务端保存非对称算法的一对密钥(公钥B,私钥B)
1)客户端发送一个https的请求,告知服务端,我要访问你了;服务端将公钥B发送给客户端。
2)客户端接受到公钥B后,生成对称加密算法的会话密钥A,并用公钥B对其加密,发送给服务端。
3)服务端接受到报文后,用私钥B解密,获取会话密钥A,再用密钥A加密一个响应报文,告知客户端,我已获知会话密钥A了。这样就完成了会话密钥A的告知流程。
4)客户端接受到响应报文后,就可以放心的用会话密钥A对后续的报文进行加解密了。
整个流程貌似是顺畅了,但是还是存在安全漏洞,因为客户端对公钥没有任何判断能力,只能被动信任。客户端与服务端消息被黑客拦截和篡改,客户端将无感知。
黑客伪造了公钥C,替换了真正的公钥B,轻松获取了会话密钥A,导致后续的报文完全透明化。
为了解决上述问题,引入了第三方的CA认证机构(比如沃通CA),CA 负责核实公钥的拥有者的信息,并颁发认证"证书",证明公钥是可信任的,同时能够为使用者提供证书验证服务。该"证书"就是数字证书。
我们看下数字证书的申请,签发,验证流程。
1)服务提供者生成非对称算法的密钥对,也就是我们上面说的公钥B,私钥B,JDK就专门生成密钥对的工具keytool。私钥自己保留,公钥提交给CA。
2) 提交证书申请信息,包括需要绑定的域名,申请者信息,csr文件(即公钥B)。当然向CA申请证书,需要付费,包年,包周期都有,价格不菲。
3)CA审核提交的信息,审核通过后继续下一步。
4) CA生成证书,首先对明文信息INFO进行散列函数hash处理(比如使用SHA1),生成一串不可逆的字符,明文信息INFO包括签发机构,有效期,域名,公钥等;再使用CA的私钥对其进行加密,生成证书文件(CER),证书包含签名和明文两部分信息。
5)签发证书,将证书文件(CER文件)发送给申请者。
6)申请者拿到证书后,与之前的私钥B一起部署到自己的服务器上。
7)客户端向服务端发送https请求。
8) 服务端将证书发送给客户端。
9)客户端拿到证书后,需要完成两步验证。
证书验证通过后,客户端认为公钥是可信任的,从明文信息中获取公钥,继续后面的流程。
数字证书不一定全部有第三方CA提供,也可以自己制作,但是需要客户端的对其授信。
前面分析了这么多,终于到正题了,我们看下实际的https的SSL连接过程。
1)客户端发送https的请求,包含随机数1,以及客户端支持的算法。
2)服务端收到报文后,回复响应,包含随机数2以及匹配的加密算法。
3) 服务端紧接着发送证书给客户端。
4) 客户端验证证书,参见上一小节。验证通过后,获取公钥,并生成一个随机数(预主密钥)。
5)客户端通过随机值1、随机值2和预主秘钥组装会话秘钥,并通过公钥加密后发送到服务端。
6)服务端使用对应的私钥进行解密,获取会话密钥。
7) 客户端与服务端的通讯报文,采用该会话密钥加密和解密。
HTTPS涉及到多个场景的对称,非对称,hash的加解密,那么将支持这些加密算法的功能提取出来,作为独立的一层,嵌入到应用层与传输层之间(TCP层)。
SSL(Secure Socket Layer 安全套接层),由从前的网景公司开发,有1,2,3三个版本。在3.0后改成TSL1.0。
HTTPS虽然解决了报文传输的安全问题,但是也为此付出了代价。
对于敏感的报文建议采用https,其他的继续使用http,既能保证安全,又能兼顾效率。
我们用常见的面试题作为本篇的最终总结。
1、为什么TCP是三次握手,而不是两次。
如果是两次握手,客户端无意或者恶意发送SYN包,而无需再次确认,会导致服务端维护大量无效连接,浪费资源。
2、为什么TCP握手是三次,而挥手却是四次
挥手时,当服务端接受到客户端FIN报文后,服务端此时可能还有报文没有发送完毕,只能先回复ACK,告知客户端"我已经收到你的关闭请求了,但是我还有报文没有发送完毕,需要等我发送完成",全部发生完成后,再发送FIN。
3、TCP与UDP的区别和适用场景
TCP是面向连接,可靠的,基于字节流的的传输协议,UDP是无连接,不可靠的基于数据报文的传输协议。
TCP | UDP | |
可靠性 | 可靠 | 不可靠 |
连接 | 面向连接 | 无连接 |
传输方式 | 面向字节流 | 面向报文 |
传输效率 | 高 | 低 |
双工性 | 全双工 | 一对一,一对多,多对一,多对多 |
流量控制 | 滑动窗口 | 无 |
拥塞控制 | 慢启动,拥塞避免,快重传,快恢复 | 无 |
应用场景 | 文件传输,网页浏览等 | 视频,语音,QQ等 |
4、HTTP2.0与HTTP1.1版本的区别
5、HTTP协议常用的响应状态码
6、HTTPS的SSL过程