分层模型
OSI 七层模型
TCP/IP 四层模型
- 应用层:HTTP (超文本传输协议)DHCP (动态主机配置)DNS (域名系统)FTP(文件传输协议)电子邮件协议(SMTP、POP3、IMAP)
- 传输层:TCP (传输控制协议) UDP(用户数据报协议)
- 网络层:IP (网际协议) ARP (地址解析协议)
- 网络接口层
HTTP
HTTP 状态码
1xx 类状态码属于提示信息,是协议处理中的一种中间状态,实际用到的比较少。
2xx 类状态码表示服务器成功处理了客户端的请求,也是我们最愿意看到的状态。
- 「200 OK」是最常见的成功状态码,表示一切正常。如果是非
HEAD请求,服务器返回的响应头都会有 body 数据。 - 「204 No Content」也是常见的成功状态码,与 200 OK 基本相同,但响应头没有 body 数据。
- 「206 Partial Content」是应用于 HTTP 分块下载或断点续传,表示响应返回的 body 数据并不是资源的全部,而是其中的一部分,也是服务器处理成功的状态。
3xx 类状态码表示客户端请求的资源发生了变动,需要客户端用新的 URL 重新发送请求获取资源,也就是重定向。
- 「301 Moved Permanently」表示永久重定向,说明请求的资源已经不存在了,需改用新的 URL 再次访问。
- 「302 Found」表示临时重定向,说明请求的资源还在,但暂时需要用另一个 URL 来访问。
301 和 302 都会在响应头里使用字段 Location,指明后续要跳转的 URL,浏览器会自动重定向新的 URL。
- 「304 Not Modified」不具有跳转的含义,表示资源未修改,重定向已存在的缓冲文件,也称缓存重定向,也就是告诉客户端可以继续使用缓存资源,用于缓存控制。
4xx 类状态码表示客户端发送的报文有误,服务器无法处理,也就是错误码的含义。
- 「400 Bad Request」表示客户端请求的报文有错误,但只是个笼统的错误。
- 「403 Forbidden」表示服务器禁止访问资源,并不是客户端的请求出错。
- 「404 Not Found」表示请求的资源在服务器上不存在或未找到,所以无法提供给客户端。
5xx 类状态码表示客户端请求报文正确,但是服务器处理时内部发生了错误,属于服务器端的错误码。
- 「500 Internal Server Error」与 400 类型,是个笼统通用的错误码,服务器发生了什么错误,我们并不知道。
- 「501 Not Implemented」表示客户端请求的功能还不支持,类似“即将开业,敬请期待”的意思。
- 「502 Bad Gateway」通常是服务器作为网关或代理时返回的错误码,表示服务器自身工作正常,访问后端服务器发生了错误。
- 「503 Service Unavailable」表示服务器当前很忙,暂时无法响应客户端,类似“网络服务正忙,请稍后重试”的意思
HTTP报文
常见字段
- Host 字段:客户端发送请求时,用来指定服务器的域名。
- Content-Length 字段:服务器在返回数据时,会有
Content-Length字段,表明本次回应的数据长度。 - Connection 字段:
Connection字段最常用于客户端要求服务器使用「HTTP 长连接」机制,以便其他请求复用 - Content-Type 字段:
Content-Type字段用于服务器回应时,告诉客户端,本次数据是什么格式。 - Content-Encoding 字段:
Content-Encoding字段说明数据的压缩方法。表示服务器返回的数据使用了什么压缩格式
请求方法
- GET:从服务器获取指定的资源
- POST:根据请求负荷(报文body)对指定的资源做出处理
- PUT:从客户端向服务器传送的数据取代指定的文档的内容
- DELETE:请求服务器删除指定的资源。
HTTP 缓存
对于一些具有重复性的 HTTP 请求,比如每次请求得到的数据都一样的,我们可以把这对「请求-响应」的数据都缓存在本地,那么下次就直接读取本地的数据,不必在通过网络获取服务器的响应了。
HTTP 缓存有两种实现方式,分别是强制缓存和协商缓存
强制缓存
强制缓存指的是只要浏览器判断缓存没有过期,则直接使用浏览器的本地缓存,决定是否使用缓存的主动性在于浏览器这边。
强制缓存是利用下面这两个 HTTP 响应头部(Response Header)字段实现的,它们都用来表示资源在客户端缓存的有效期:
Cache-Control, 是一个相对时间;Expires,是一个绝对时间;
具体的实现流程如下:
- 当浏览器第一次请求访问服务器资源时,服务器会在返回这个资源的同时,在 Response 头部加上 Cache-Control,Cache-Control 中设置了过期时间大小;
- 浏览器再次请求访问服务器中的该资源时,会先通过请求资源的时间与 Cache-Control 中设置的过期时间大小,来计算出该资源是否过期,如果没有,则使用该缓存,否则重新请求服务器;
- 服务器再次收到请求后,会再次更新 Response 头部的 Cache-Control。
协商缓存
通过服务端告知客户端是否可以使用缓存的方式被称为协商缓存(304响应码)
协商缓存这两个字段都需要配合强制缓存中 Cache-Control 字段来使用,只有在未能命中强制缓存的时候,才能发起带有协商缓存字段的请求。
协商缓存可以基于两种头部来实现。
第一种:请求头部中的 If-Modified-Since 字段与响应头部中的 Last-Modified 字段实现,这两个字段的意思是:
- 响应头部中的
Last-Modified:标示这个响应资源的最后修改时间; - 请求头部中的
If-Modified-Since:当资源过期了,浏览器发现响应头中具有 Last-Modified 声明,则再次向服务器发起请求时,会将请求头 If-Modified-Since 值设置为 Last-Modified 的值。服务器收到请求后发现有 If-Modified-Since 则与被请求资源的最后修改时间进行对比(Last-Modified),如果最后修改时间较新(大),说明资源又被改过,则返回最新资源,HTTP 200 OK;如果最后修改时间较旧(小),说明资源无新修改,响应 HTTP 304 走缓存。
第二种:请求头部中的 If-None-Match 字段与响应头部中的 ETag 字段,这两个字段的意思是:
- 响应头部中
Etag:唯一标识响应资源; - 请求头部中的
If-None-Match:当资源过期时,浏览器发现响应头里有 Etag,则再次向服务器发起请求时,会将请求头 If-None-Match 值设置为 Etag 的值。服务器收到请求后进行比对,如果资源没有变化返回 304,如果资源变化了返回 200。
具体实现流程
当浏览器第一次请求访问服务器资源时,服务器会在返回这个资源的同时,在 Response 头部加上 ETag 唯一标识,这个唯一标识的值是根据当前请求的资源生成的;
当浏览器再次请求访问服务器中的该资源时,首先会先检查强制缓存是否过期:
- 如果没有过期,则直接使用本地缓存;
- 如果缓存过期了,会在 Request 头部加上 If-None-Match 字段,该字段的值就是 ETag 唯一标识;
服务器再次收到请求后,
会根据请求中的 If-None-Match 值与当前请求的资源生成的唯一标识进行比较
- 如果值相等,则返回 304 Not Modified,不会返回资源;
- 如果不相等,则返回 200 状态码和返回资源,并在 Response 头部加上新的 ETag 唯一标识;
如果浏览器收到 304 的请求响应状态码,则会从本地缓存中加载资源,否则更新资源
HTTP 与 HTTPS
HTTP 与 HTTPS 的区别
- 端口号 :HTTP 默认是 80,HTTPS 默认是 443。
- URL 前缀 :HTTP 的 URL 前缀是
http://,HTTPS 的 URL 前缀是https://。 - 安全性和资源消耗 : HTTP 协议运行在 TCP 之上,所有传输的内容都是明文,客户端和服务器端都无法验证对方的身份。HTTPS 是运行在
SSL/TLS之上的 HTTP 协议,SSL/TLS运行在 TCP 之上。所有传输的内容都经过加密,加密采用对称加密,但对称加密的密钥用服务器方的证书进行了非对称加密。所以说,HTTP 安全性没有 HTTPS 高,但是 HTTPS 比 HTTP 耗费更多服务器资源。
SSL/TLS 基本流程
- 客户端向服务器索要并验证服务器的公钥。
- 双方协商生产「会话秘钥」。
- 双方采用「会话秘钥」进行加密通信。
SSL/TLS 工作原理
混合加密
HTTPS 采用的是对称加密和非对称加密结合的「混合加密」方式,实现信息的机密性:
- 在通信建立前采用非对称加密的方式交换「会话秘钥」,后续就不再使用非对称加密。
- 在通信过程中全部使用对称加密的「会话秘钥」的方式加密明文数据。
数字证书
将服务器公钥放在CA (数字证书认证机构)数颁布的数字证书中,利用数字签名技术防止证书被伪造,确保服务器公钥的可信
摘要算法 + 数字签名
- 摘要算法:使用哈希函数来计算出内容的哈希值,保证传输的内容不被篡改
- 数字签名:对内容的哈希值,私钥加密,公钥解密,来确认消息的身份
HTTP 1.0 vs HTTP 1.1
连接方式 : HTTP 1.0 为短连接,HTTP 1.1 支持长连接。
状态响应码 : HTTP/1.1中新加入了大量的状态码,光是错误响应状态码就新增了24种。比如说,100 (Continue)——在请求大资源前的预热请求,206 (Partial Content)——范围请求的标识码,409 (Conflict)——请求与当前资源的规定冲突,410 (Gone)——资源已被永久转移,而且没有任何已知的转发地址。
缓存处理 : 在 HTTP1.0 中主要使用 header 里的 If-Modified-Since,Expires 来做为缓存判断的标准,HTTP1.1 则引入了更多的缓存控制策略例如 Entity tag,If-Unmodified-Since, If-Match, If-None-Match 等更多可供选择的缓存头来控制缓存策略。
带宽优化及网络连接的使用 :HTTP1.0 中,存在一些浪费带宽的现象,例如客户端只是需要某个对象的一部分,而服务器却将整个对象送过来了,并且不支持断点续传功能,HTTP1.1 则在请求头引入了 range 头域,它允许只请求资源的某个部分,即返回码是 206(Partial Content),这样就方便了开发者自由的选择以便于充分利用带宽和连接。
Host头处理 : HTTP/1.1在请求头中加入了Host字段
TCP
TCP:面向连接的,可靠的,基于字节流,一般用于FTP 文件传输,HTTP / HTTPS。
UDP:无连接的,尽力分发的,基于报文,一般用于即时通信,比如: 语音、 视频 、直播等。
TCP 头部格式

序列号:在建立连接时由计算机生成的随机数作为其初始值,通过 SYN 包传给接收端主机,每发送一次数据,就「累加」一次该「数据字节数」的大小。用来解决网络包乱序问题。
确认应答号:指下一次「期望」收到的数据的序列号,发送端收到这个确认应答以后可以认为在这个序号以前的数据都已经被正常接收。用来解决丢包的问题。
控制位:
- ACK:该位为 1 时,「确认应答」的字段变为有效,TCP 规定除了最初建立连接时的 SYN 包之外该位必须设置为 1 。
- RST:该位为 1 时,表示 TCP 连接中出现异常必须强制断开连接。
- SYN:该位为 1 时,表示希望建立连接,并在其「序列号」的字段进行序列号初始值的设定。
- FIN:该位为 1 时,表示今后不会再有数据发送,希望断开连接。当通信结束希望断开连接时,通信双方的主机之间就可以相互交换 FIN 位为 1 的 TCP 段
TCP 连接建立
TCP三次握手

- 一开始,客户端和服务端都处于
CLOSE状态。先是服务端主动监听某个端口,处于LISTEN状态 - 客户端会随机初始化序号(
client_isn),将此序号置于 TCP 首部的「序号」字段中,同时把SYN标志位置为1,表示SYN报文。接着把第一个 SYN 报文发送给服务端,表示向服务端发起连接,该报文不包含应用层数据,之后客户端处于SYN-SENT状态。 - 服务端收到客户端的
SYN报文后,首先服务端也随机初始化自己的序号(server_isn),将此序号填入 TCP 首部的「序号」字段中,其次把 TCP 首部的「确认应答号」字段填入client_isn + 1, 接着把SYN和ACK标志位置为1。最后把该报文发给客户端,该报文也不包含应用层数据,之后服务端处于SYN-RCVD状态。 - 客户端收到服务端报文后,还要向服务端回应最后一个应答报文,首先该应答报文 TCP 首部
ACK标志位置为1,其次「确认应答号」字段填入server_isn + 1,最后把报文发送给服务端,这次报文可以携带客户到服务端的数据,之后客户端处于ESTABLISHED状态。 - 服务端收到客户端的应答报文后,也进入
ESTABLISHED状态。
为什么要三次握手?
双方确认自己与对方的发送与接收是正常的。
第一次握手丢失了,客户端就会触发「超时重传」机制,重传 SYN 报文,而且重传的 SYN 报文的序列号都是一样的。
第二次握手丢失了,客户端就会触发超时重传机制,重传 SYN 报文,服务端也会触发超时重传机制,重传 SYN-ACK 报文。
第三次握手丢失了,服务端会触发超时重传机制,重传 SYN-ACK 报文。
ACK 报文是不会有重传的,当 ACK 丢失了,就由对方重传对应的报文。
SYN 攻击
在 TCP 三次握手的时候,Linux 内核会维护两个队列,分别是:
- 半连接队列,也称 SYN 队列;
- 全连接队列,也称 accept 队列;
工作流程
- 当服务端接收到客户端的 SYN 报文时,会创建一个半连接的对象,然后将其加入到内核的「 SYN 队列」;
- 接着发送 SYN + ACK 给客户端,等待客户端回应 ACK 报文;
- 服务端接收到 ACK 报文后,从「 SYN 队列」取出一个半连接对象,然后创建一个新的连接对象放入到「 Accept 队列」;
- 应用通过调用
accpet()socket 接口,从「 Accept 队列」取出连接对象。
SYN 攻击方式最直接的表现就会把 TCP 半连接队列打满,这样当 TCP 半连接队列满了,后续再在收到 SYN 报文就会丢弃,导致客户端无法和服务端建立连接。
TCP连接断开
TCP 四次挥手
- 客户端打算关闭连接,此时会发送一个 TCP 首部
FIN标志位被置为1的报文,也即FIN报文,之后客户端进入FIN_WAIT_1状态。 - 服务端收到该报文后,就向客户端发送
ACK应答报文,接着服务端进入CLOSE_WAIT状态。 - 客户端收到服务端的
ACK应答报文后,之后进入FIN_WAIT_2状态。 - 等待服务端处理完数据后,也向客户端发送
FIN报文,之后服务端进入LAST_ACK状态。 - 客户端收到服务端的
FIN报文后,回一个ACK应答报文,之后进入TIME_WAIT状态 - 服务端收到了
ACK应答报文后,就进入了CLOSE状态,至此服务端已经完成连接的关闭。 - 客户端在经过
2MSL一段时间后,自动进入CLOSE状态,至此客户端也完成连接的关闭
为什么挥手需要四次?
- 关闭连接时,客户端向服务端发送
FIN时,仅仅表示客户端不再发送数据了但是还能接收数据。 - 服务端收到客户端的
FIN报文时,先回一个ACK应答报文,而服务端可能还有数据需要处理和发送,等服务端不再发送数据时,才发送FIN报文给客户端来表示同意现在关闭连接。
为什么 TIME_WAIT 等待的时间是 2MSL?
第四次挥手时,客户端发送给服务器的 ACK 有可能丢失,如果服务端因为某些原因而没有收到 ACK 的话,服务端就会重发 FIN,如果客户端在 2*MSL 的时间内收到了 FIN,就会重新发送 ACK 并再次等待 2MSL,防止 Server 没有收到 ACK 而不断重发 FIN。
MSL(Maximum Segment Lifetime) : 报文最大生存时间,2MSL 就是一个发送和一个回复所需的最大时间。如果直到 2MSL,Client 都没有再次收到 FIN,那么 Client 推断 ACK 已经被成功接收,则结束 TCP 连接
为什么需要 TIME_WAIT 状态
- 防止历史连接中的数据,被后面相同四元组的连接错误的接收;
- 等待足够的时间以确保最后的 ACK 能让被动关闭方接收,从而帮助其正常关闭;
TCP 传输可靠性保障
TCP 是通过序列号、确认应答、超时重传,流量控制,拥塞控制等机制实现可靠性传输的。
重传机制
超时重传
在发送数据时,设定一个定时器,当超过指定的时间后,没有收到对方的 ACK 确认应答报文,就会重发该数据
TCP 会在以下两种情况发生超时重传:
- 数据包丢失
- 确认应答丢失
超时时间应该设置为多少呢?
超时重传时间 RTO 的值应该略大于报文往返 RTT 的值。
如果超时重发的数据,再次超时的时候,又需要重传的时候,TCP 的策略是超时间隔加倍。
快速重传
当收到三个相同的 ACK 报文时,会在定时器过期之前,重传丢失的报文段。
流量控制
TCP 利用滑动窗口实现流量控制,让「发送方」根据「接收方」的实际接收能力控制发送的数据量
发送窗口
接受窗口
拥塞控制
拥塞控制目的就是避免「发送方」的数据填满整个网络。
慢启动(指数增长)
当发送方每收到一个 ACK,拥塞窗口 cwnd 的大小就会加 1
拥塞避免(线性增长)
当拥塞窗口 cwnd 「超过」慢启动门限 ssthresh 就会进入拥塞避免算法
每当收到一个 ACK 时,cwnd 增加 1/cwnd
拥塞发生
发生超时重传的拥塞发生算法:ssthresh 设为 cwnd/2,cwnd 重置为 初始值,进入慢启动
发生快速重传的拥塞发生算法:ssthresh = cwnd/2,cwnd = ssthresh+3,进入快速恢复
快速恢复
每收到一个重复的ACK拥塞窗口增加1MSS,如果收到新的ACK则拥塞窗口置成阀值
Socket 编程
- 服务端和客户端初始化
socket,得到文件描述符; - 服务端调用
bind,将 socket 绑定在指定的 IP 地址和端口; - 服务端调用
listen,进行监听; - 服务端调用
accept,等待客户端连接; - 客户端调用
connect,向服务端的地址和端口发起连接请求; - 服务端
accept返回用于传输的socket的文件描述符; - 客户端调用
write写入数据;服务端调用read读取数据; - 客户端断开连接时,会调用
close,那么服务端read读取数据的时候,就会读取到了EOF,待处理完数据后,服务端调用close,表示连接关闭