参考javaguide,做回忆和补充,详细参考
HTTP和HTTPS
HTTP介绍
http协议:超文本传输协议,超文本可以理解为在网络浏览器中显示的各种各样的内容,其中存在可以指向其他内容的超链接。
并且,http是一个无状态的协议,也就是说服务器不维护任何有关客户端过去所发请求的消息。(例如,在某网站发送登陆请求之后,如不做任何处理,服务端并不能保存客户的登录状态。需要使用session、cookie和token来保存状态)。
HTTP是应用层协议,以TCP(传输层)为底层协议,默认端口为80。
HTTP通信过程
- 服务器在80端口等待客户端的连接请求
- 客户端浏览器发起到服务器的TCP连接
- 服务器接收来自浏览器的TCP连接
- 浏览器与web服务器交换http消息
- 关闭TCP连接
(相关知识:TCP的三次握手、TCP的四次挥手、http的请求和响应报文格式)
HTTPS介绍
https简单来说就是http的加强安全版本,额外使用SSL/TLS用作加密和安全认证,默认端口443
SSL/TLS工作原理
SSL/TLS的核心要素是非对称加密,这里还是要简单理解一下几个概念:对称加密和非对称加密,非对称加密中又有公钥、私钥、数字证书。
对称加密
对称加密简单来说就是加密和解密双方使用的是同一个密钥。对于客户端和服务端的场景来说,如果使用对称加密的话,如何保证双方的共享密钥的一致性比较困难。
非对称加密
非对称加密即加密和解密双方使用的密钥不一致,分为公钥和私钥。
密钥对:公钥和私钥是通过一种算法得到的一个密钥对,其中的一个向外界公开,称为公钥;另个自己保留,称为私钥。
公钥:用来给数据加密,用公钥加密的数据只能用私钥解密。
私钥:用来解密公钥加密的数据。
数字证书:由证书颁发机构(CA)颁发,保证证书信息的有效性。包含了公钥的信息。
详见 https://www.cnblogs.com/xujinzhong/p/11161531.html
HTTPS连接过程
- 客户端通过URL访问服务器建立SSL连接。
- 服务端收到客户端请求后,会将网站支持的证书信息(证书中包含公钥)传送一份给客户端。
- 客户端的服务器开始协商SSL连接的安全等级,也就是信息加密的等级。
- 客户端的浏览器根据双方同意的安全等级,建立会话密钥,然后利用网站的会话密钥加密,并返回给服务器。
- 服务器利用自己的私钥揭密处会话密钥。
- 服务器利用会话密钥加密与客户端之间的通信。
(个人理解就是,双方还是使用对称加密的密钥来进行信息的加密,但是客户端和服务器想使用同样的对称密钥的话,就需要有一个传输的过程,但是这个传输的过程是不安全的,有可能会使对称密钥暴露在外面,因此使用非对称加密的公钥和私钥,来对对称密钥的传输进行加密)
HTTPS缺点
- HTTPS多次握手,导致页面加载时间延长
- HTTPS连接缓存不如HTTP高效,会增加数据开销和功耗
- 申请SSL证书需要钱
- SSL涉及到的安全算法会消耗CPU资源,对服务器的资源消耗较大
HTTP和HTTPS区别
- HTTPS是HTTP的安全版本,HTTP是明文传输不安全的,HTTPS使用了SSL/TLS进行了加密处理
- HTTP和HTTPS连接方式不同,默认断后也不一样,HTTP是80,HTTPS是443
HTTP报文格式
请求报文
请求报文分为三部分:请求行、请求头、请求体
请求行:
- 请求方法:HTTP/1.1 定义的请求方法有8种:GET、POST、PUT、DELETE、PATCH、HEAD、OPTIONS、TRACE,最常的两种GET和POST,如果是RESTful接口的话一般会用到GET、POST、DELETE、PUT
- URL:和请求头的host组成完整的请求URL
- 协议名称和版本号
响应报文
响应报文包括:响应行、响应头、响应体
响应头:
- 报文协议及版本
- 状态码及状态描述
常见响应状态码
- 1xx 请求已收到,正在处理
- 2xx 处理成功
- 3xx 重定向到其他地方
- 4xx 客户端错误,如客户端请求一个不存在的资源、未被授权等
- 5xx 服务端错误,如服务端异常,路由出错等
TCP连接过程(三次握手和四次挥手)
三次握手
过程
- 客户端发起连接,发送报文
syn=1,seq=x
- 服务端收到请求如果接收连接,返回
syn=1,seq=y,ack=x+1
- 客户端收到确认连接,如果已有数据需要发送则发送
seq=x+1,ack=y+1
,并携带对应数据;否则发送seq=x,ack=y+1
为什么不能是两次握手
原理上来说,握手应该和挥手的次数一样。但是在握手的过程中,第二次握手后不需要传送数据(前两次握手只是告知对方序列号初始值,没有实现客户端和服务器给连接分配缓冲区和变量),因此B发送给A的确认以及B请求建立连接两条报文可以合并为一条。
更具体的原因:避免序号错误,如果只有两次的话,那么发送方没有取消建立连接的方法,如果发送方第一次发送后,又接着发起第二次(如发送方超时),那么可能会导致发送方收到的响应实际上是第一次连接的响应。
比如,发送方第一次发送了一个seq=x的报文,由于各种原因,接收方超时返回了一个ack=x+1的报文,但此时发送方已经第二次发送了一个seq=y的报文,此时接收到的却是一个ack=x+1的响应,与所期望的不符合。
全连接队列和半连接队列
- 半连接队列,被称为SYN队列,即在第一次握手后,如果半连接队列没有满,把从客户端接收到的socket放到半连接队列,服务端进入
SYN_RCVD
状态, - 全连接队列,被称为accept队列,即在第三次握手后,服务端收到客户端的ACK后,该socket会从半连接队列移出到全连接队列,等待应用使用。
- syn_flood攻击,故意大量不断发送味道的syn报文,使队列存满,服务器分配大量无用的资源,不能正常接收连接,是一种典型的DDoS攻击
四次挥手
过程
- 某一方希望关闭连接,向对方发送报文
FIN=1,ACK=1,seq=u
- 对方收到后发送确认报文
ACK=1,seq=v,ack=u+1
- 发起方不再发送数据,对方可能还需要发送数据,TCP处于半关闭状态
- 对方也没有需要发送的数据,发送释放报文
FIN=1,ACK=1,seq=w,ack=u+1
- 发起方返回确认报文
ACK=1,ack=w+1,seq=u+1
。发送2MSL后,连接关闭(可能会存在确认报文发送失败,对方请求重传的情况)
为什么结束后还要等待2MSL
因为第四次挥手,接收方可能没有收到来自发送方同意关闭连接的回应,会进行超时重传。1MSL代表发送一个报文从一端到另一端
的时间,2MSL即一次来往的时间。如果2MSL接收方还没有收到来自发送方的相应,即认为已经可以关闭连接。
滑动窗口、流量控制、拥塞控制
滑动窗口
由于传输本身存在时延,一问一答式的传输效率极低,更好的办法应该是同时发送很多组数据。
发送方和接收方各维护一个窗口(发送窗口和接收窗口)
发送窗口包含 4 部分:
- 已发送成功的部分:这部分数据是已经被接收方确认接收过
- 已发送但未确认的部分:这部分数据已经发送,但暂时未收到确认
- 未发送但接收方可处理的部分:这部分数据还没有发送,但在发送窗口的范围呢,将会继续发送
- 未发送且接收方不可处理的部分:这部分数据在窗口外,暂时不需要发送
通过冗余ACK机制,可以对已接收到的一组数据同时返回确认
接收窗口包含三个部分:
- 已确认接收的部分
- 未接收但可接收的部分
- 不可接收的部分
当接收窗口收到超出窗口范围的数据,将会被直接丢弃掉。而接收到数据,将会被标记为已接收成功。每次确认会将第一个违背确认的报文发送回去。
发送窗口和滑动窗口并不是一成不变的,两者近似相等,但是由于网络问题以及机器处理速度,实际上可能会稍有变动。接收窗口通过首部的相应字段告知发送方,而发送方将根据对方的接收窗口以及拥塞窗口共同确认。
当接收窗口为0时,表明接收窗口关闭,这时发送方会启动一个定时器,按时发送窗口探测报文,当接收方收到探测报文时,会返回当前的接收窗口大小。如果采用不定时确认窗口大小的策略,当接收窗口发送调整窗口的报文丢失,会造成死锁。
由于窗口对应的单位为字节,因此如果发送窗口很小,则会发送大量只有几个字节的报文,而TCP头部最少都有20字节,将会造成大量的浪费,因此往往当接收窗口小于min(MSS, buffersize/2)时,就会直接认为是0
流量控制
TCP提供基于滑动窗口协议的流量控制,实现了端到端的流量控制
通信过程中,接受方根据自己的接收缓存大小,动态调整发送方发送窗口的大小,这被称为接收窗口rwnd
如果滑动窗口设置过小:产生过多ACK(累计确认机制本身可以减少ACK)
如果滑动窗口设置过大:发送数据过多导致路由阻塞,丢失分组
传输层和数据链路层的流量控制区别在于:
- 数据链路层解决的是两个相邻节点之间的流量控制,且窗口不能动态变化
- 传输层解决的是端到端用户之间的流量控制,且窗口可以动态变化
拥塞控制
拥塞控制可以防止数据过多的发送到网络中,避免路由器或链路过载。通信双方本身并不能了解到拥塞的细节,只能根据通信时延的增加来确认发生了拥塞
发送方根据对当前网络的拥塞成都确定拥塞窗口大小cwnd
拥塞窗口的单位为最大报文段MSS,该值如果过小,则网络利用率会较低;过大则会在网络层大量分片
实际的发送窗口取rwnd
和cwnd
的最小值
- 拥塞控制是全局性的过程,涉及所有相关主机和路由器
- 流量控制是端到端的控制,通过抑制发送端的速率来确保接收端有能力全部接收
TCP的拥塞控制包含四个部分:
- 慢开始:拥塞窗口初始为1,没收到一个确认,则加1;从时间上看,每个单位时间都扩大一倍;增加存在上限
ssthresh
,当达到慢启动门限后,就会使用拥塞避免算法 - 拥塞避免:每收到
cwnd
个ACK,则加1;当出现超时时(发生拥塞),则设置ssthresh=cwnd/2
,cwnd=1
- 快重传:连续收到3个冗余确认,直接重传丢失的包,不等待计时器
- 快恢复:在快重传发生后,
cwnd=ssthresh=cwnd/2
,返回拥塞避免状态