02-传输层应用层
传输层
UDP
- UDP是无连接的传输层协议;
- UDP使用尽最大努力交付,不保证可靠交付;
- UDP是面向报文的,对应用层交下来的报文,不合并,不拆分,保留原报文的边界;
- UDP没有拥塞控制,因此即使网络出现拥塞也不会降低发送速率;
- UDP支持一对一 一对多 多对多的交互通信;
- UDP的首部开销小,只有8字节

TCP
- 是一个可以提供可靠的,支持全双工、连接导向的协议
- 报文拆分 ->增加TCP头 -> 数据重组 顺序发出,乱序到达
- 根据时间窗口进行排序
- TCP序号:发送序号(Seq)、接收序号(Ack) 一个端的发送序号是另一个端的接收序号 序号的增加是根据已经发送的字节数来进行计算的
TCP头部

- 序号:seq序号,占32位,用来标识从TCP源端向目的端发送的字节流, 发起方发送数据时对此进行标记。
- 确认序号:ack序号,占32位,只有ACK标志位为1时,确认序号字段才有 效,ack=seq+1。
- 标志位:共6个,即URG、ACK、PSH、RST、SYN、FIN等,具体含义如 下:
- ACK:确认序号有效。
- FIN:释放一个连接。
- PSH:接收方应该尽快将这个报文交给应用层。
- RST:重置连接。
- SYN:发起一个新连接。
- URG:紧急指针(urgent pointer)有效。
- 同步 SYN
- 终止FIN
- 数据偏移 :指的是数据部分距离报文段起始处的偏移量,实际上指的是首部的长度。
- 窗口 :窗口值作为接收方让发送方设置其发送窗口的依据。之所以要有这个限制,是因为接收方的数据缓存空间是有限的。
- 检验和:将原文映射到一个不可逆的16bit的编码中
TCP的三次握手

SYN:它的全称是 Synchronize Sequence Numbers,同步序列编号。是 TCP/IP 建立连接时使用的握手信号。在客户机和服务器之间建立 TCP 连接时,首先会发送的一个信号。客户端在接受到 SYN 消息时,就会在自己的段内生成一个随机值 X。
SYN-ACK:服务器收到 SYN 后,打开客户端连接,发送一个 SYN-ACK 作为答复。确认编号设置为比接收到的序列号多一个,即 X + 1,服务器为数据包选择的序列号是另一个随机数 Y。
ACK:Acknowledge character, 确认字符,表示发来的数据已确认接收无误。最后,客户端将 ACK 发送给服务器。序列号被设置为所接收的确认值即 Y + 1。
客户端优化
- 修改 SYN 的重传次数
- 客户端作为主动发起连接方,首先它将发送 SYN 包,于是客户端的连接就会处于
SYN_SENT
状态。,正常情况下,服务器会在几毫秒内返回 SYN+ACK ,但如果客户端长时间没有收到 SYN+ACK 报文,则会重发 SYN 包,重发的次数由 tcp_syn_retries 参数控制,默认是 5 次:通常,第一次超时重传是在 1 秒后,第二次超时重传是在 2 秒,第三次超时重传是在 4 秒后,第四次超时重传是在 8 秒后,第五次是在超时重传 16 秒后。没错,每次超时的时间是上一次的 2 倍。
- 客户端作为主动发起连接方,首先它将发送 SYN 包,于是客户端的连接就会处于
服务端优化
- 调整SYN半连接队列长度
- 调整SYN+ACK报文的重传次数
- 调整accpet队列长度
绕过三次握手
- 打开TCP Fast Open
- 首次建立时:
- 客户端发送 SYN 报文,该报文包含 Fast Open 选项,且该选项的 Cookie 为空,这表明客户端请求 Fast Open Cookie;
- 支持 TCP Fast Open 的服务器生成 Cookie,并将其置于 SYN-ACK 数据包中的 Fast Open 选项以发回客户端;
- 客户端收到 SYN-ACK 后,本地缓存 Fast Open 选项中的 Cookie。
- 再次建立连接时:
- 客户端发送 SYN 报文,该报文包含「数据」(对于非 TFO 的普通 TCP 握手过程,SYN 报文中不包含「数据」)以及此前记录的 Cookie;
- 支持 TCP Fast Open 的服务器会对收到 Cookie 进行校验:如果 Cookie 有效,服务器将在 SYN-ACK 报文中对 SYN 和「数据」进行确认,服务器随后将「数据」递送至相应的应用程序;如果 Cookie 无效,服务器将丢弃 SYN 报文中包含的「数据」,且其随后发出的 SYN-ACK 报文将只确认 SYN 的对应序列号;
- 如果服务器接受了 SYN 报文中的「数据」,服务器可在握手完成之前发送「数据」,这就减少了握手带来的 1 个 RTT 的时间消耗;
- 客户端将发送 ACK 确认服务器发回的 SYN 以及「数据」,但如果客户端在初始的 SYN 报文中发送的「数据」没有被确认,则客户端将重新发送「数据」;
- 此后的 TCP 连接的数据传输过程和非 TFO 的正常情况一致。
TCP的四次挥手
首先,客户端应用程序决定要终止连接(这里服务端也可以选择断开连接)。这会使客户端将 FIN 发送到服务器,并进入 FIN_WAIT_1 状态。当客户端处于 FIN_WAIT_1 状态时,它会等待来自服务器的 ACK 响应。
然后第二步,当服务器收到 FIN 消息时,服务器会立刻向客户端发送 ACK 确认消息。
当客户端收到服务器发送的 ACK 响应后,客户端就进入 FIN_WAIT_2 状态,然后等待来自服务器的 FIN 消息.
服务器发送 ACK 确认消息后,一段时间(可以进行关闭后)会发送 FIN 消息给客户端,告知客户端可以进行关闭。
当客户端收到从服务端发送的 FIN 消息时,客户端就会由 FIN_WAIT_2 状态变为 TIME_WAIT 状态。处于 TIME_WAIT 状态的客户端允许重新发送 ACK 到服务器为了防止信息丢失。客户端在 TIME_WAIT 状态下花费的时间取决于它的实现,在等待一段时间后(等待是为了避免建立新的连接后,接收到上次连接延迟的数据包 还有就是保证连接正确得关闭),连接关闭,客户端上所有的资源(包括端口号和缓冲区数据)都被释放。
重传机制
超时重传
- 在发送数据时,设定一个定时器,当超过指定的时间后,没有收到对方的
ACK
确认应答报文,就会重发该数据,也就是我们常说的超时重传 - 超时重发的数据,再次超时的时候,又需要重传的时候,TCP 的策略是超时间隔加倍。也就是每当遇到一次超时重传的时候,都会将下一次超时时间间隔设为先前值的两倍。两次超时,就说明网络环境差,不宜频繁反复发送。
快速重传
快速重传的工作方式是当收到三个相同的 ACK 报文时,会在定时器过期之前,重传丢失的报文段。
SACK(选择性确认)
- 为了解决重传的时候,是重传之前的一个,还是重传所有的问题。
- 在 TCP 头部「选项」字段里加一个
SACK
的东西,它可以将缓存的地图发送给发送方,这样发送方就可以知道哪些数据收到了,哪些数据没收到,知道了这些信息,就可以只重传丢失的数据。
D-SACK
使用了 SACK 来告诉「发送方」有哪些数据被重复接收了。
第一种情况ack超时:
接收方」发给「发送方」的两个 ACK 确认应答都丢失了,所以发送方超时后,重传第一个数据包(3000 ~ 3499)
于是「接收方」发现数据是重复收到的,于是回了一个 SACK = 3000~3500,告诉「发送方」 3000~3500 的数据早已被接收了,因为 ACK 都到了 4000 了,已经意味着 4000 之前的所有数据都已收到,所以这个 SACK 就代表着
D-SACK
。这样「发送方」就知道了,数据没有丢,是「接收方」的 ACK 确认报文丢了。
第二种情况网络延迟
数据包(1000~1499) 被网络延迟了,导致「发送方」没有收到 Ack 1500 的确认报文。
而后面报文到达的三个相同的 ACK 确认报文,就触发了快速重传机制,但是在重传后,被延迟的数据包(1000~1499)又到了「接收方」;
所以「接收方」回了一个 SACK=1000~1500,因为 ACK 已经到了 3000,所以这个 SACK 是 D-SACK,表示收到了重复的包。
这样发送方就知道快速重传触发的原因不是发出去的包丢了,也不是因为回应的 ACK 包丢了,而是因为网络延迟了。
D-SACK的好处
- 可以让「发送方」知道,是发出去的包丢了,还是接收方回应的 ACK 包丢了;
- 可以知道是不是「发送方」的数据包被网络延迟了;
- 可以知道网络中是不是把「发送方」的数据包给复制了;
滑动窗口
- 为了解决TCP 是每发送一个数据,都要进行一次确认应答。当上一个数据包收到了应答了, 再发送下一个。这种效率低的问题,出现了窗口,就可以指定窗口大小,窗口大小就是指无需等待确认应答,而可以继续发送数据的最大值。
- 窗口的实现实际上是操作系统开辟的一个缓存空间,发送方主机在等到确认应答返回之前,必须在缓冲区中保留已发送的数据。如果按期收到确认应答,此时数据就可以从缓存区清除。按窗口最后一个来确认
窗口的大小
- TCP 头里有一个字段叫
Window
,也就是窗口大小。通常窗口的大小是由接收方的决定的。
发送方的滑动窗口
- #1 是已发送并收到 ACK确认的数据:1~31 字节
- #2 是已发送但未收到 ACK确认的数据:32~45 字节
- #3 是未发送但总大小在接收方处理范围内(接收方还有空间):46~51字节
- #4 是未发送但总大小超过接收方处理范围(接收方没有空间):52字节以后
当发送方把数据「全部」都一下发送出去后,可用窗口的大小就为 0 了,表明可用窗口耗尽,在没收到 ACK 确认之前是无法继续发送数据了。
当收到之前发送的数据
32~36
字节的 ACK 确认应答后,如果发送窗口的大小没有变化,则滑动窗口往右边移动 5 个字节,因为有 5 个字节的数据被应答确认,接下来52~56
字节又变成了可用窗口,那么后续也就可以发送52~56
这 5 个字节的数据了。
接收方的滑动窗口
- #1 + #2 是已成功接收并确认的数据(等待应用进程读取);
- #3 是未收到数据但可以接收的数据;
- #4 未收到数据并不可以接收的数据;
接收窗口和发送窗口大小不完全相等
- 接收窗口的大小是约等于发送窗口的大小的。
因为滑动窗口并不是一成不变的。比如,当接收方的应用进程读取数据的速度非常快的话,这样的话接收窗口可以很快的就空缺出来。那么新的接收窗口大小,是通过 TCP 报文中的 Windows 字段来告诉发送方。那么这个传输过程是存在时延的,所以接收窗口和发送窗口是约等于的关系。
流量控制
- TCP 提供一种机制可以让「发送方」根据「接收方」的实际接收能力控制发送的数据量,这就是所谓的流量控制。
- TCP 规定是不允许同时减少缓存又收缩窗口的,而是采用先收缩窗口,过段时间在减少缓存,这样就可以避免了丢包情况。
窗口关闭
- 如果窗口大小为 0 时,就会阻止发送方给接收方传递数据,直到窗口变为非 0 为止,这就是窗口关闭。
- TCP 是如何解决窗口关闭时,潜在的死锁现象呢?
- TCP 为每个连接设有一个持续定时器,只要 TCP 连接一方收到对方的零窗口通知,就启动持续计时器。
- 如果持续计时器超时,就会发送窗口探测 ( Window probe ) 报文,而对方在确认这个探测报文时,给出自己现在的接收窗口大小。
糊涂窗口综合征
- 如果接收方腾出几个字节并告诉发送方现在有几个字节的窗口,而发送方会义无反顾地发送这几个字节,这就是糊涂窗口综合症。
- 解决方案
- 让接收方不通告小窗口给发送方
- 当「窗口大小」小于 min( MSS,缓存空间/2 ) ,也就是小于 MSS 与 1/2 缓存大小中的最小值时,就会向发送方通告窗口为
0
,也就阻止了发送方再发数据过来。 - 等到接收方处理了一些数据后,窗口大小 >= MSS,或者接收方缓存空间有一半可以使用,就可以把窗口打开让发送方发送数据过来。
- 当「窗口大小」小于 min( MSS,缓存空间/2 ) ,也就是小于 MSS 与 1/2 缓存大小中的最小值时,就会向发送方通告窗口为
- 让发送方避免发送小数据
- 使用 Nagle 算法,该算法的思路是延时处理,它满足以下两个条件中的一条才可以发送数据:
- 要等到窗口大小 >=
MSS
或是 数据大小 >=MSS
- 收到之前发送数据的
ack
回包
只要没满足上面条件中的一条,发送方一直在囤积数据,直到满足上面的发送条件。
另外,Nagle 算法默认是打开的,如果对于一些需要小数据包交互的场景的程序,比如,telnet 或 ssh 这样的交互性比较强的程序,则需要关闭 Nagle 算法。
- 要等到窗口大小 >=
- 使用 Nagle 算法,该算法的思路是延时处理,它满足以下两个条件中的一条才可以发送数据:
- 让接收方不通告小窗口给发送方
拥塞控制
- 在网络出现拥堵时,如果继续发送大量数据包,可能会导致数据包时延、丢失等,这时 TCP 就会重传数据,但是一重传就会导致网络的负担更重,于是会导致更大的延迟以及更多的丢包,这个情况就会进入恶性循环被不断地放大…于是就有了拥塞控制,控制的目的就是避免「发送方」的数据填满整个网络。
- 拥塞窗口 cwnd
- 拥塞窗口 cwnd是发送方维护的一个 的状态变量,它会根据网络的拥塞程度动态变化的。
- 只要网络中没有出现拥塞,
cwnd
就会增大; - 但网络中出现了拥塞,
cwnd
就减少;
- 接收者窗口rwnd(receiver windows)
- 用于流量控制的窗口大小,主要取决于接收方的处理速度,由接收方通知发送方被动调整
- 同时考虑流量控制与拥塞处理,则发送方窗口的大小不超过
min{rwnd, cwnd}
- 如何确认发生了拥塞
- 只要「发送方」没有在规定时间内接收到 ACK 应答报文,也就是发生了超时重传,就会认为网络出现了用拥塞。
慢启动
- TCP 在刚建立连接完成后,首先是有个慢启动的过程,这个慢启动的意思就是一点一点的提高发送数据包的数量
- 当发送方每收到一个 ACK,拥塞窗口 cwnd 的大小加1倍。慢启动算法,发包的个数是指数性的增长。
- 慢启动门限
ssthresh
,一般来说ssthresh
的大小是65535
字节。 - 当
cwnd < ssthresh
时,使用慢启动算法。 - 当
cwnd >= ssthresh
时,就会使用「拥塞避免算法」。
- 慢启动门限
拥塞避免
每当收到一个 ACK 时,cwnd 增加 1。
从慢启动到拥塞避免增长从指数增长变为了线性增长
只要发送方判断网络出现了阻塞就开始启用超时重传的拥塞发生算法
拥塞发生
- 当触发了重传机制,也就进入了「拥塞发生算法」。
超时重传的拥塞发生算法
- sshresh 和 cwnd 的值会发生变化:
ssthresh
设为cwnd/2
,cwnd重置为
1 - 就重新开始慢启动,慢启动是会突然减少数据流的。这真是一旦「超时重传」,马上回到解放前。但是这种方式太激进了,反应也很强烈,会造成网络卡顿。
快速重传的拥塞发生算法
- 快重传要求接收方在收到一个失序的报文段后就立即发出重复确认(为的是使发送方及早知道有报文段没有到达对方,可提高网络吞吐量约20%)而不要等到自己发送数据时捎带确认。
- 快重传算法规定,发送方只要一连收到三个重复确认就应当立即重传对方尚未收到的报文段,而不必继续等待设置的重传计时器时间到期
- 进入快速恢复算法
快速恢复
快速重传和快速恢复算法一般同时使用,快速恢复算法是认为,你还能收到 3 个重复 ACK 说明网络也不那么糟糕,所以没有必要像
RTO
超时那么强烈。流程
- 拥塞窗口
cwnd = ssthresh + 3
( 3 的意思是确认有 3 个数据包被收到了) - 重传丢失的数据包
- 如果再收到重复的 ACK,那么 cwnd 增加 1
- 如果收到新数据的 ACK 后,设置 cwnd 为 ssthresh,接着就进入了拥塞避免算法
- 拥塞窗口
UDP和TCP的特点
区别
- 1.基于连接与无连接
- 2.TCP要求系统资源较多,UDP较少;
- 3.UDP程序结构较简单
- 4.流模式(TCP)与数据报模式(UDP);
- 5.TCP保证数据正确性,UDP可能丢包
- 6.TCP保证数据顺序,UDP不保证
应用层
HTTP
概述
默认端口:80
传输协议:定义了,客户端和服务器端通信时,发送数据的格式
特点:
- 基于TCP/IP的高级协议
- 默认端口号:80
- 基于请求/响应模型的:一次请求对应一次响应
- 无状态的:每次请求之间相互独立,不能交互数据
各版本区别
HTTP 1.0(1996)
- 仅仅提供了最基本的认证,这时候用户名和密码还未经加密,因此很容易收到窥探。
- HTTP 1.0 被设计用来使用短链接,即每次发送数据都会经过 TCP 的三次握手和四次挥手,效率比较低。
- HTTP 1.0 只使用 header 中的 If-Modified-Since 和 Expires 作为缓存失效的标准。
- HTTP 1.0 不支持断点续传,也就是说,每次都会传送全部的页面和数据。
- HTTP 1.0 认为每台计算机只能绑定一个 IP,所以请求消息中的 URL 并没有传递主机名(hostname)。
HTTP 1.1(1999)
- HTTP 1.1 使用了摘要算法来进行身份验证
- HTTP 1.1 默认使用长连接,长连接就是只需一次建立就可以传输多次数据,传输完成后,只需要一次切断连接即可。长连接的连接时长可以通过请求头中的 keep-alive 来设置
- HTTP 1.1 中新增加了 E-tag,If-Unmodified-Since, If-Match, If-None-Match 等缓存控制标头来控制缓存失效。
- HTTP 1.1 支持断点续传,通过使用请求头中的 Range 来实现。
- HTTP 1.1 使用了虚拟网络,在一台物理服务器上可以存在多个虚拟主机(Multi-homed Web Servers),并且它们共享一个IP地址。
HTTP 2.0HTTP(2015)
- 头部压缩,由于 HTTP 1.1 经常会出现 User-Agent、Cookie、Accept、Server、Range 等字段可能会占用几百甚至几千字节,而 Body 却经常只有几十字节,所以导致头部偏重。HTTP 2.0 使用 HPACK 算法进行压缩。
- 二进制格式,HTTP 2.0 使用了更加靠近 TCP/IP 的二进制格式,而抛弃了 ASCII 码,提升了解析效率
- 强化安全,由于安全已经成为重中之重,所以 HTTP2.0 一般都跑在 HTTPS 上。
- HTTP1.1协议的KeepAlive让多个请求复用一个tcp连接,非多路复用,一个请求阻塞,其他请求也全都阻塞.2.0实现了多路复用,即每一个请求都是是用作连接共享。一个请求对应一个id,这样一个连接上可以有多个请求
- 服务器推送
- 问题
- 多个 HTTP 请求在复用一个 TCP 连接,下层的 TCP 协议是不知道有多少个 HTTP 请求的。所以一旦发生了丢包现象,就会触发 TCP 的重传机制,这样在一个 TCP 连接中的所有的 HTTP 请求都必须等待这个丢了的包被重传回来。
- HTTP2.0的多路复用和HTTP1.X中的长连接复用有什么区别
- HTTP/1.1的Pipeling为若干个请求排队串行化单线程处理,后面的请求等待前面请求的返回才能获得执行机会,一旦有某请求超时等,后续请求只能被阻塞,毫无办法;
- HTTP2.0多个请求可同时在一个连接上并行执行,某个请求任务耗时严重,不会影响到其它连接的正常执行
http 3.0HTTP
使用UDP实现
谷歌QUIC TODO
请求消息数据格式
请求行
- 请求方式 请求url 请求协议/版本:GET /login.html HTTP/1.1
- 请求方式:
- HTTP协议有7中请求方式,常用的有2种
- GET:
- 请求参数在请求行中,在url后。
- 请求的url长度有限制的
- 不太安全
- POST:
- 请求参数在请求体中
- 请求的url长度没有限制的
- 相对安全
- OPTIONS:
- 用于请求获得由Request-URI标识的资源在请求/响应的通信过程中可以使用的功能选项,通过这个方法,客户端可以在采取具体资源请求之前,决定对该资源采取何种必要措施,或者了解服务器的性能
- GET:
- HTTP协议有7中请求方式,常用的有2种
请求头
- 客户端浏览器告诉服务器一些信息
- 请求头分类
通用标头
实体标头
Content-Length 实体报头指示实体主体的大小,以字节为单位,发送到接收方。
Content-Language 实体报头描述了客户端或者服务端能够接受的语言。
Content-Encoding 这又是一个比较麻烦的属性,这个实体报头用来压缩媒体类型。Content-Encoding 指示对实体应用了何种编码。常见的内容编码有这几种: gzip、compress、deflate、identity ,这个属性可以应用在请求报文和响应报文中。请求头: Accept-Encoding: gzip, deflate,响应头 Content-Encoding: gzip
请求标头
响应标头
- Access-Control-Allow-Origin:一个返回的 HTTP 标头可能会具有 Access-Control-Allow-Origin ,Access-Control-Allow-Origin 指定一个来源,它告诉浏览器允许该来源进行资源访问。
- Keep-Alive:Keep-Alive 表示的是 Connection 非持续连接的存活时间,可以进行指定。
- Server:服务器标头包含有关原始服务器用来处理请求的软件的信息。应该避免使用过于冗长和详细的 Server 值,因为它们可能会泄露内部实施细节,这可能会使攻击者容易地发现并利用已知的安全漏洞。例如下面这种写法Server: Apache/2.4.1 (Unix)
- Set-Cookie:Set-Cookie 用于服务器向客户端发送 sessionID。
- ansfer-Encoding:首部字段 Transfer-Encoding 规定了传输报文主体时采用的编码方式。HTTP /1.1 的传输编码方式仅对分块传输编码有效。
- Frame-Options:HTTP 首部字段是可以自行扩展的。所以在 Web 服务器和浏览器的应用上,会出现各种非标准的首部字段。首部字段 X-Frame-Options 属于 HTTP 响应首部,用于控制网站内容在其他 Web 网站的 Frame 标签内的显示问题。其主要目的是为了防止点击劫持(clickjacking)攻击。
- 常见的请求头:
1. User-Agent:浏览器告诉服务器,我访问你使用的浏览器版本信息
1. 可以在服务器端获取该头的信息,解决浏览器的兼容性问题
2. Referer:http://localhost/login.html
1. 告诉服务器,我(当前请求)从哪里来?
1. 作用:1. 防盗链 2.统计工作
请求空行
- 空行,就是用于分割POST请求的请求头,和请求体的。
请求体(正文)
- 封装POST请求消息的请求参数的
- 字符串格式:
POST /login.html HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Referer: http://localhost/login.html
Connection: keep-alive
Upgrade-Insecure-Requests: 1
username=zhangsan
- 响应消息数据格式
POST和GET的区别
- get的主要特征是请求服务器返回资源,而 post 方法一般用于表单的提交,相当于是把信息提交给服务器,等待服务器作出响应,get 相当于一个是 pull/拉的操作,而 post 相当于是一个 push/推的操作。get 方法是不安全的,因为你在发送请求的过程中,你的请求参数会拼在 URL 后面,从而导致容易被攻击者窃取,对你的信息造成破坏和伪造;
- get 请求的 URL 有长度限制,而 post 请求会把参数和值放在消息体中,对数据长度没有要求。
- get 请求会被浏览器主动 cache,而 post 不会,除非手动设置。
- get 请求在浏览器反复的 回退/前进 操作是无害的,而 post 操作会再次提交表单请求。
- get 请求在发送过程中会产生一个 TCP 数据包;post 在发送过程中会产生两个 TCP 数据包。
- 对于 get 方式的请求,浏览器会把 http header 和 data 一并发送出去,服务器响应 200(返回数据);而对于 post,浏览器先发送 header,服务器响应 100 continue,浏览器再发送 data,服务器响应 200 ok(返回数据)。
HTTPS
HTTPS = Http + TLS/SSl协议的组合
HTTPS 的默认端口是 443。
采用对称加密的方式加密传输数据,对称加密用的密钥是采用非对称加密的方式进行协商
用户在浏览器发起HTTPS请求(如 https://www.mogu.com/),默认使用服务端的443端口进行连接;
HTTPS需要使用一套CA数字证书,证书内会附带一个公钥Pub,而与之对应的私钥Private保留在服务端不公开;
服务端收到请求,返回配置好的包含公钥Pub的证书给客户端;
客户端收到证书,校验合法性,主要包括是否在有效期内、证书的域名与请求的域名是否匹配,上一级证书是否有效(递归判断,直到判断到系统内置或浏览器配置好的根证书),如果不通过,则显示HTTPS警告信息,如果通过则继续;
客户端生成一个用于对称加密的随机Key,并用证书内的公钥Pub进行加密,发送给服务端;
服务端收到随机Key的密文,使用与公钥Pub配对的私钥Private进行解密,得到客户端真正想发送的随机Key;
服务端使用客户端发送过来的随机Key对要传输的HTTP数据进行对称加密,将密文返回客户端;
客户端使用随机Key对称解密密文,得到HTTP数据明文;
后续HTTPS请求使用之前交换好的随机Key进行对称加解密。
TSL/SSL握手
- ClientHello
- 首先,由客户端向服务器发起加密通信请求,也就是
ClientHello
请求。
在这一步,客户端主要向服务器发送以下信息:
(1)客户端支持的 SSL/TLS 协议版本,如 TLS 1.2 版本。
(2)客户端生产的随机数(Client Random
),后面用于生产「会话秘钥」。
(3)客户端支持的密码套件列表,如 RSA 加密算法。
- 首先,由客户端向服务器发起加密通信请求,也就是
- SeverHello
- 服务器收到客户端请求后,向客户端发出响应,也就是
SeverHello
。服务器回应的内容有如下内容:
(1)确认 SSL/ TLS 协议版本,如果浏览器不支持,则关闭加密通信。
(2)服务器生产的随机数(Server Random
),后面用于生产「会话秘钥」。
(3)确认的密码套件列表,如 RSA 加密算法。
(4)服务器的数字证书。
- 服务器收到客户端请求后,向客户端发出响应,也就是
- 客户端回应
- 客户端收到服务器的回应之后,首先通过浏览器或者操作系统中的 CA 公钥,确认服务器的数字证书的真实性。
- 如果证书没有问题,客户端会从数字证书中取出服务器的公钥,然后使用它加密报文,向服务器发送如下信息:
(1)一个随机数(pre-master key
)。该随机数会被服务器公钥加密。
(2)加密通信算法改变通知,表示随后的信息都将用「会话秘钥」加密通信。
(3)客户端握手结束通知,表示客户端的握手阶段已经结束。这一项同时把之前所有内容的发生的数据做个摘要,用来供服务端校验。
上面第一项的随机数是整个握手阶段的第三个随机数,这样服务器和客户端就同时有三个随机数,接着就用双方协商的加密算法,各自生成本次通信的「会话秘钥」。
- 服务器的最后回应
- 服务器收到客户端的第三个随机数(
pre-master key
)之后,通过协商的加密算法,计算出本次通信的「会话秘钥」。然后,向客户端发生最后的信息:
(1)加密通信算法改变通知,表示随后的信息都将用「会话秘钥」加密通信。
(2)服务器握手结束通知,表示服务器的握手阶段已经结束。这一项同时把之前所有内容的发生的数据做个摘要,用来供客户端校验。 - 至此,整个 SSL/TLS 的握手阶段全部结束。接下来,客户端与服务器进入加密通信,就完全是使用普通的 HTTP 协议,只不过用「会话秘钥」加密内容。
- 服务器收到客户端的第三个随机数(
同源策略
- 禁止一个源(origin)的脚本及文档 与 另一个源的脚本和文档交互
- 同源:两个URL的协议 端口和host都一致,那么它们同源
- 解决方案
- CORS
- 预检
- 代理
CDN(内容分发网络)
实现原理
- 用户向浏览器输入www.web.com这个域名,浏览器第一次发现本地没有dns缓存,则向网站的DNS服务器请求;
- 网站的DNS域名解析器设置了CNAME,指向了www.web.51cdn.com,请求指向了CDN网络中的智能DNS负载均衡系统;
- 智能DNS负载均衡系统解析域名,把对用户响应速度最快的IP节点返回给用户
- 用户向该IP节点(CDN服务器)发出请求
- 由于是第一次访问,CDN服务器会向原web站点请求,并缓存内容(内容缓存淘汰机制)
- 请求结果发给用户
CDN的组成
- 中心节点
- 中心节点包括CDN网管中心和全局负载均衡DNS重定向解析系统,负责整个CDN网络的分发及管理
- 边缘节点
- 负载均衡设备负责每个节点中各个Cache的负载均衡,保证节点的工作效率;同时,负载均衡设备还负责收集节点与周围环境的信息,保持与全局负载DNS的通信,实现整个系统的负载均衡
- 高速缓存服务器存储客户网站的大量信息,就像一个靠近用户的网站服务器一样响应本地用户的访问请求。通过全局负载均衡DNS的控制,用户的请求被透明地指向离他最近的节点,节点中Cache服务器就像网站的原始服务器一样,响应终端用户的请求。因其距离用户更近,故其响应时间才更快。
Request和Response
Rquest
Request数据格式
- 请求行
- 请求方式 请求url 请求协议/版本:GET /login.html HTTP/1.1
- 请求方式:
- HTTP协议有7中请求方式,常用的有2种
- GET:
- 请求参数在请求行中,在url后。
- 请求的url长度有限制的
- 不太安全
- POST:
- 请求参数在请求体中
- 请求的url长度没有限制的
- 相对安全
- GET:
- HTTP协议有7中请求方式,常用的有2种
- 请求头:客户端浏览器告诉服务器一些信息
* 请求头名称: 请求头值- 常见的请求头:
- User-Agent:浏览器告诉服务器,我访问你使用的浏览器版本信息
- 可以在服务器端获取该头的信息,解决浏览器的兼容性问题
- Referer:http://localhost/login.html
- 告诉服务器,我(当前请求)从哪里来?
- 作用:
- 防盗链:
- 统计工作:
- 作用:
- 告诉服务器,我(当前请求)从哪里来?
- User-Agent:浏览器告诉服务器,我访问你使用的浏览器版本信息
- 常见的请求头:
- 请求空行
- 空行,就是用于分割POST请求的请求头,和请求体的。
- 请求体(正文):
- 封装POST请求消息的请求参数的
- 字符串格式:
POST /login.html HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Referer: http://localhost/login.html
Connection: keep-alive
Upgrade-Insecure-Requests: 1
username=zhangsan
- 响应消息数据格式
+
Response
Response数据格式
- 响应行
- 组成:协议/版本 响应状态码 状态码描述
- 响应状态码:服务器告诉客户端浏览器本次请求和响应的一个状态。
- 状态码都是3位数字
- 分类:
- 1xx:服务器就收客户端消息,但没有接受完成,等待一段时间后,发送1xx多状态码
- 2xx:成功。代表:200
- 3xx:重定向。代表:302(重定向),304(访问缓存)
- 4xx:客户端错误。
- 代表:
- 404(请求路径没有对应的资源)
- 405:请求方式没有对应的doXxx方法
- 代表:
- 5xx:服务器端错误。代表:500(服务器内部出现异常)
- 响应头:
- 格式:头名称: 值
- 常见的响应头:
- Content-Type:服务器告诉客户端本次响应体数据格式以及编码格式
- Content-disposition:服务器告诉客户端以什么格式打开响应体数据
- 值:
- in-line:默认值,在当前页面内打开
- attachment;filename=xxx:以附件形式打开响应体。文件下载
- 值:
- 响应空行
- 响应体:传输的数据
forward 和 redirect 区别
- 重定向的特点:redirect
- 地址栏发生变化
- 重定向可以访问其他站点(服务器)的资源
- 重定向是两次请求。不能使用request对象来共享数据
- 转发的特点:forward
- 转发地址栏路径不变
- 转发只能访问当前服务器下的资源
- 转发是一次请求,可以使用request对象来共享数据
常用名词和工具
带宽
- 表示链路的最大传输速率,单位是 b/s (比特 / 秒),带宽越大,其传输能力就越强。
吞吐量
- 表示单位时间内成功传输的数据量,单位是 b/s(比特 / 秒)或者 B/s(字节 / 秒),吞吐受带宽限制,带宽越大,吞吐率的上限才可能越高。
延时
- 表示请求数据包发送后,收到对端响应,所需要的时间延迟。不同的场景有着不同的含义,比如可以表示建立 TCP 连接所需的时间延迟,或一个数据包往返所需的时间延迟
PPS
- 全称是 Packet Per Second(包 / 秒),表示以网络包为单位的传输速率,一般用来评估系统对于网络的转发能力。
RTT
- 一个连接的往返时间,即数据发送时刻到接收到确认的时刻的差值;
RTO
- 重传超时时间,即从数据发送时刻算起,超过这个时间便执行重传。
Socket信息查看
我们可以使用
netstat
或者ss
,这两个命令查看 socket、网络协议栈、网口以及路由表的信息。
虽然netstat
与ss
命令查看的信息都差不多,但是如果在生产环境中要查看这类信息的时候,尽量不要使用netstat
命令,因为它的性能不好,在系统比较繁忙的情况下,如果频繁使用netstat
命令则会对性能的开销雪上加霜,所以更推荐你使用性能更好的ss
命令。比如都包含了 socket 的状态(State)、接收队列(Recv-Q)、发送队列(Send-Q)、本地地址(Local Address)、远端地址(Foreign Address)、进程 PID 和进程名称(PID/Program name)等。
接收队列(Recv-Q)和发送队列(Send-Q)比较特殊,在不同的 socket 状态。它们表示的含义是不同的。
当 socket 状态处于Established
时:Recv-Q 表示 socket 缓冲区中还没有被应用程序读取的字节数;
Send-Q 表示 socket 缓冲区中还没有被远端主机确认的字节数;
而当 socket 状态处于Listen
时:Recv-Q 表示全连接队列的长度;
Send-Q 表示全连接队列的最大长度;
地址栏输入URL发生了什么
- 解析URL拿到域名
- DNS查询,主机名到IP的映射,先查缓存,然后hosts,最后去网络上做DNS查询
- 网络上查询DNS分为递归查询和迭代查询
- TCP头,建立http连接三次握手,如果是https请求则建立tcp连接后要进行TSL握手,然后开始进行加密传输
- IP头,IP封装成网络包,查看路由表,先看看是不是内网的 如果不是发到路由器上
- 加上MAC头部,如果ARP缓存中没有IP对应的MAC地址,则通过ARP协议进行广播拿到路由器的MAC头部并存储到ARP协议的缓存
- 数字信号转电信号,封装成帧
- 走交换机到路由器,路由器会去掉MAC头,子网掩码 默认路由
- 根据路由表的网关列判断对方的地址。
- 如果网关是一个 IP 地址,则这个IP 地址就是我们要转发到的目标地址,还未抵达终点,还需继续需要路由器转发。
- 如果网关为空,则 IP 头部中的接收方 IP 地址就是要转发到的目标地址,也是就终于找到 IP 包头里的目标地址了,说明已抵达终点。
- 需要通过
ARP
协议根据 IP 地址查询 MAC地址,需要 MAC 地址在以太网内进行两个设备之间的包传输。 - 发送方端口是自己路由器的MAC地址
HTTP 状态码
状态码 | 原因短语 | |
---|---|---|
消息响应 | ||
100 | Continue(继续) | |
成功响应 | ||
200 | OK(成功) | |
201 | Created(已创建) | |
202 | Accepted(已创建) | |
203 | Non-Authoritative Information(未授权信息) | |
204 | No Content(无内容) | |
205 | Reset Content(重置内容) | |
206 | Partial Content(部分内容) | |
重定向 | ||
300 | Multiple Choice(多种选择) | |
301 | Moved Permanently(永久移动) | |
302 | Found(临时移动) | |
303 | See Other(查看其他位置) | |
304 | Not Modified(未修改) | |
305 | Use Proxy(使用代理) | |
306 | unused(未使用) | |
307 | Temporary Redirect(临时重定向) | |
308 | Permanent Redirect(永久重定向) | |
客户端错误 | ||
400 | Bad Request(错误请求) | |
401 | Unauthorized(未授权) | |
402 | Payment Required(需要付款) | |
403 | Forbidden(禁止访问) | |
404 | Not Found(未找到) | |
405 | Method Not Allowed(不允许使用该方法) | |
406 | Not Acceptable(无法接受) | |
407 | Proxy Authentication Required(要求代理身份验证) | |
408 | Request Timeout(请求超时) | |
409 | Conflict(冲突) | |
410 | Gone(已失效) | |
411 | Length Required(需要内容长度头) | |
412 | Precondition Failed(预处理失败) | |
413 | Request Entity Too Large(请求实体过长) | |
414 | Request-URI Too Long(请求网址过长) | |
415 | Unsupported Media Type(媒体类型不支持) | |
416 | Requested Range Not Satisfiable(请求范围不合要求) | |
417 | Expectation Failed(预期结果失败) | |
服务器端错误 | ||
500 | Internal Server Error(内部服务器错误) | |
501 | Implemented(未实现) | |
502 | Bad Gateway(网关错误) | |
503 | Service Unavailable(服务不可用) | |
504 | Gateway Timeout (网关超时) | |
505 | HTTP Version Not Supported(HTTP 版本不受支持) |