介绍一下TCP/IP模型和OSI模型的区别

OSI和TCP/IP都是计算机网络的分层模型;

  • OSI 先有模型后有协议,是理论上的标准模型;
  • TCP/IP 是先有协议后有模型,从实践中总结来的事实标准;

OSI把网络从上到下分为应用层、表示层、会话层、传输层、网络层、数据链路层、物理层;

而TCP/IP分为:

  • 应用层:TCP/IP认为应用层、表示层、会话层应由应用程序本身处理,合为一个应用层;提供与应用程序交互的接口,比如HTTP、FTP等;
  • 传输层:提供进程间、端到端的通信;主要协议有TCP和UDP,其中TCP保证可靠性而UDP不保证可靠性;
  • 网络层:提供跨网络的通信;主要协议是IP,提供数据包的路由和转发,也就是如何从一台电脑找到另一台电脑;IP协议使用IP地址来区分主机和网络,并进行寻址;
  • 网络接口层:对应OSI模型的数据链路层和物理层;它负责物理传输媒介的传输;该层包含硬件地址,也就是MAC地址的管理;

从输入 URL 到页面展示到底发生了什么?

  1. 输入URL,解析并准备发送HTTP请求
  2. 浏览器进行缓存查询,如果没有则进入下一步网络请求
  3. DNS域名解析:通过DNS解析获得想要访问的域名的IP地址,按照浏览器缓存 → 操作系统缓存 → 本地HOSTS文件 → 本地DNS服务器 → 迭代查询,直到找到域名的IP地址
  4. 通过TCP三次握手建立连接
  5. Client发送HTTP请求:建立连接后浏览器会构建请求行、请求头等信息,发起HTTP请求数据;
  6. Server解析请求,返回响应数据
  7. Client拿到数据,通过TCP四次挥手断开连接
  8. 浏览器解析数据并渲染页面
    • 如果响应头状态码是301、302,则会重定向
    • 如果数据类型是字节流,则将请求提交给下载器
    • 如果是HTML,则开始渲染,创建DOM树,解析CSS样式,将CSS与DOM合并,构建渲染树,最后布局和绘制渲染树得到页面

HTTP请求报文和响应报文是怎样的,有哪些常见的字段?

HTTP请求报文由四部分组成:请求行、请求头、空行、请求体;

其中请求行由三个部分组成:

  • 方法:如GET、POST、PUT、DELETE
  • 资源路径:URI,资源唯一标识,绝大多数时候就是资源路径URL
  • HTTP版本

请求头是键值对,常见字段有:

  • Host:目标主机名
  • User-Agent:浏览器标识
  • Accept:可接受的响应类型
  • Accept-Language:可接受的语言
  • Cookie:携带的Cookie
  • Connection:连接管理,如keep-alive

空行:用于分割head和body

请求体通常见于POST和PUT,包含发送给Server的数据;

HTTP响应报文也是四部分组成:状态行、响应头、空行、响应体

其中状态行包括:

  • HTTP版本
  • 状态码:比如200、301、404
  • 状态信息:OK

响应头常见字段有:

  • Date:响应时间
  • Server:服务器标识
  • Content-Type:响应体的媒体类型及编码
  • Content-Length:响应体大小
  • Set-Cookie:向客户端写入Cookie
  • Location:301、302重定向时跳转URL

响应体则是响应返回的数据,常见的有HTML、视频、图片等等;


HTTP有哪些请求方式?

常见CRUD:

  • GET:获取资源,幂等安全,可被缓存;
  • POST:提交数据,非幂等,不可缓存;
  • PUT:整体更新,替换资源,幂等;
  • DELETE:删除指定资源,幂等;

其他:

  • HEAD:只返回头部不返回资源,常用于检查资源是否存在;
  • PATCH:部分更新;
  • OPTIONS:查询某服务器支持的方法;

GET请求和POST请求的区别

  • 语义层面:GET用于获取资源,是读操作;POST用于提交数据,是写操作;
  • 参数位置:GET的参数直接写在URL中,POST的参数放在请求体中;
  • 安全性:GET是明文,可以直接看到;POST相对安全,但是如果不走HTTPS,抓包一样可以看到;
  • 幂等性:GET是读操作不改变资源状态,天然幂等;POST提交数据会改变资源状态,不幂等;
  • 缓存:GET会被浏览器缓存;POST则默认不缓存;
  • 长度限制:GET有长度限制,最大一般几KB;POST理论上没有;

注意上述的一些区别主要来自于浏览器而不是HTTP协议本身,比如GET也可以写请求体,POST也可以用于获取数据,并不违反协议但是不够RESTful;


HTTP中常见的状态码有哪些?

  • 200:请求成功
  • 201:创建成功,会返回创建资源的路径
  • 204:请求成功但是没有返回内容,常见于DELETE
  • 301:永久重定向,资源的URL已永久改变;浏览器会缓存这个重定向,下次直接访问新地址;
  • 304:协商缓存成功,不返回请求体,浏览器直接访问缓存
  • 401:未认证,需要登录
  • 403:已认证但是无权访问资源
  • 404:资源不存在
  • 500:服务器内部错误
  • 502:网关或代理收到了无效的上游响应

什么是强缓存和协商缓存

强缓存和协商缓存都是浏览器使用缓存加速访问的方法,区别在于有没有发起请求:

强缓存(不发请求):

  • Cache-Control:响应体返回一个时间段,表明资源的有效时长,如果浏览器在该时长内则直接使用该缓存;
  • Expires:响应体返回一个时间点,表明资源到什么时间节点之前有效;但是该方法依赖于浏览器本地时间的准确,已废弃;

如果强缓存没有命中,则客户端向服务器发起一个请求,服务器协商缓存通过则返回304,如果没通过则返回200与新资源;

协商缓存(发请求)由两组字段实现:

  • ETag / If-None-Match:响应体在返回时返回一个ETag,通常是资源的哈希值,浏览器在发起请求时带上If-None-Match与该哈希值,如果相等则协商缓存通过;
  • Last-Modified / If-Modified-Since:响应体在返回时返回一个Last-Modified,即资源最后修改时间,浏览器请求时把这个时间放在If-Modified-Since发给服务器,服务器对比最新时间进行判断;但是该方法只精确到秒,同时如果一个资源重新生成了但是内容不变,也会导致时间改变;

HTTP1.0和HTTP1.1的区别

  • 持久连接:HTTP1.0默认每次请求都要新建连接;HTTP1.1支持keepalive,让TCP连接可以复用,节省了反复建立连接的时间;
  • HOST的引入:HTTP1.0没有HOST名,一个IP只能和一个域名绑定;HTTP1.1引入HOST,使得一个主机上可以挂载多个虚拟主机,实现多域名访问;
  • 管线化:HTTP1.1支持连续发送多条请求而不用等响应回来;但是因为队头阻塞用的并不多;
  • 缓存优化:HTTP1.0使用的Expires和Last-Modified比较粗糙;HTTP1.1引入了Cache-Control和ETag等更加精细的缓存控制方法;
  • 断点续传:HTTP1.1引入了Range字段,可以只请求资源的某一部分;

HTTP2.0与HTTP1.1的区别?

HTTP2.0主要是优化了HTTP1.1的性能瓶颈;

  • 二进制分帧:HTTP1.1的报文是明文传输,HTTP2.0将报文拆分成更小的二进制帧;
  • 多路复用:一个TCP连接中可以同时发送多个请求和响应,通过二进制分帧拆成小包,支持乱序,只需要在到达后按照ID重新拼接起来;解决了HTTP1.1的队头阻塞问题;
  • 头部压缩:HTTP1.1每次都要重新发送头部信息;HTTP2.0让client和server各自维护一个头部索引表,重复信息只发索引,减少了头部信息反复传递的浪费;
  • 服务推送:HTTP2.0支持server根据历史行为提前准备资源,比如一个HTML响应之后提前准备好CSS资源;但实际用的很少,Chrome甚至移除了对服务推送的支持;

HTTP3.0有了解过吗?

HTTP3.0最大的不同便是传输层改用了基于UDP的QUIC协议;HTTP2.0虽然引入了多路复用,但是如果发生了丢包,这之后的所有数据都要等它重传;

QUIC解决了这些问题:

  • 彻底解决了队头阻塞:QUIC在协议层面支持多路复用,每个流的丢包进行单独恢复;
  • 内建TLS:QUIC默认进行TLS加密;
  • 更快建立连接:TCP建立连接需要3次握手,加上TLS握手需要2-3个RTT;QUIC把传输层握手和加密握手放在一起,能实现1RTT建立连接,如果是之前建立过连接的,能实现0RTT,在第一个数据包中就带上数据;
  • 连接迁移:TCP依靠四元组建立连接(源IP、源端口、目标IP、目标端口),如果切换网络(如手机流量到WIFI)则需要重新建立连接;QUIC依靠唯一的连接ID而不是IP来建立连接,网络可以实现无缝切换;

HTTPS和HTTP有哪些区别

HTTPS和HTTP最大的区别就是HTTPS有一层TLS加密协议层

  • 安全性:HTTP是明文报文,而HTTPS经过加密之后都是加密报文;
  • 证书:HTTPS会申请一个CA证明自己就是要访问的服务器;
  • 端口:HTTP端口是80,而HTTPS的端口是443;

HTTPS的工作原理(HTTPS建立连接的过程)

HTTPS的建立就是TCP建立 + TLS认证的过程;

  1. TCP三次握手
  2. TLS握手
    1. Client:发送Client Hello,包含TLS版本 + Client Random + 加密套件;
    2. Server:收到后发送Server Hello,包含Server Random + ECDHE + CA证书,然后发送一个Server Hello Done表示自己发送完了;
    3. Client收到CA证书之后进行验证;
    4. Client验证通过后发送Client Key Exchange,包含ECDHE;
    5. 双方自行计算Pre-Master Secret,再各自生成最终密钥;
    6. 双方互相发送Change Cipher Spec和Finished,之后就进入加密通信;

TCP和UDP的区别

  • 连接方式:TCP是面向连接的,需要三次握手建立连接,四次挥手断开连接;UDP是无连接的,直接发数据过去,并不确认任何状态;
  • 可靠性:TCP通过一系列的方式保证数据准确、按顺序到达;UDP不保证可靠性,数据包可能是乱序、丢失、重复的;
  • 传输方式:TCP是面向字节流的,数据被视为一串连续的字节流,没有明确边界;UDP是面向数据报的,每次发送都是一个完整的数据报;
  • 通信方式:TCP是点对点的,天然只能一对一;UDP支持一对一、一对多、多对多,支持广播、组播;
  • 拥塞控制:TCP有拥塞控制,网络阻塞时会降速;UDP只按原速发送;

TCP连接如何确保可靠性

要保证可靠性,就是要通信的双方知道哪些信息传了、传得对不对、接下来要传什么;

  • 序列号与确认应答:TCP给每一个字节都标了序列号,接收方在接收到报文后会返回ACK,告诉发送方它收到了多少序列号之前的报文,接下来需要接收什么;发送方在收到ACK之后才继续发送;
  • 超时重传:发送方在发送了报文之后开始一个计时器,如果在计时器时间内ACK都没有被传回,则发送方再次发送同一个报文;
  • 快速重传:接收方在发现丢包之后,直接向发送方连续多次请求同一个包,如果发送方连续三次接到请求同一个包的,则直接开始重传;
  • 滑动窗口:如果发送方每次都等接收方传回ACK再开始传下一个则会很慢,滑动窗口则允许发送方一次性发出多个包;
  • 拥塞控制:发送方感知拥塞窗口,防止挤爆接收方的网络;
  • 流量控制:接收方维护自己的缓冲区,防止被发送方挤爆;

拥塞控制是怎么实现的

拥塞控制是发送方为了不挤爆网络链路进行的主动控制;

  • 慢启动:发送方在刚开始的时候每次发送很少的数据包,如果成功收到ACK,则每次指数翻倍,直至一个阈值;
  • 线性增长:在达到阈值之后,每次发送数量+1;

而在发现网络丢包之后为了不进一步挤占网络需要控制速度:

  • 如果是超时重传,则说明网络情况糟糕,会直接掉回慢启动的初始状态;
  • 如果是快速重传,则说明只是偶尔丢包,进入快速恢复:会先把发送数量砍半,然后每成功一次+1;

TCP流量控制是怎么实现的?

流量控制是接收方为了让发送方不要打爆自己的缓冲区进行的控制;

接收方会维护一个缓冲区比如4000字节,发送方第一次发送2000字节之后,接收方就告诉发送方你最多还能传2000字节;如果缓冲区归0则会让发送方停止发送,直至恢复空间;

零窗口探活:为了防止丢包导致明明有空间而发送方却不知道,发送方会进行窗口探活,每次发送一个1字节的小包去试探,如果能发送了则再发送;

糊涂窗口综合症:接收方一有空间就让发送方发送,浪费了资源在反复传递头文件上;解决方法是接收方在空闲空间达到一个阈值(比如1/2个缓冲区大小)才告诉发送方可以发送;而发送方也会攒着手里的先不发,等攒够一定大小了才发;


UDP怎么实现可靠传输

UDP协议不保证可靠传输,所以可靠传输就要靠在应用层进行保证;

可靠传输的核心就是知道传了什么和要传什么:

  • 序列号和确认应答:保证接收方接到的数据有序、可排查、发送方可感知;
  • 超时重传:发送方在一定时间内没接收到ACK则需要重传;

简单的实践:发送方在头部加入序列号和时间戳,接收方在接收到数据包之后,对数据包进行排序,如果没问题则返回ACK;如果发送方在超时时间内收到ACK则发下一个,如果没收到则重发,并把超时时间翻倍;


TCP连接三次握手的过程,为什么是三次,可以是两次或者更多吗?

三次握手过程

  1. Client发送一个SYN(SYN=1,序列号=x),告诉Server我想建立连接,确认了Client可以发,进入SYN_SENT
  2. Server收到SYN之后回复一个SYN+ACK(SYN=1,ACK=1,确认号=x+1,序列号=y),告诉Client可以建立连接,确认了Server可以接收也可以发送,进入SYN_RCVD
  3. Client收到之后回复一个ACK(ACK=1,确认号=y+1),确认Client能收,双方建立连接;

为什么是三次:因为Client和Server都需要确认自己能收也能发,其中Server在收到SYN之后就能立即发送SYN+ACK,1次握手就能确认收和发,但是Client必须要两次;

两次不行:因为两次的话服务器无法确认客户端能收;假设客户端之前发的一个SYN在网络中绕了很久才到达服务器,客户端早就放弃了。如果两次就建立连接,服务器收到这个过期的SYN就会直接分配资源建立连接等待数据,但客户端根本不会发任何数据过来,服务器的资源就白白浪费了。

更多没必要:三次就已经能确认双方的状态,再多就是多余的了;虽然可以把Server的回信拆成一次SYN和一次ACK,但是Server一次动作就能确认两个状态,所以直接合并;


TCP连接四次挥手的过程,为什么是四次?

四次挥手过程

  1. Client发送一个FIN(序列号=u),告诉Server我要关闭了,接下来我不发消息了,进入FIN_WAIT_1
  2. Server收到后发一个ACK(确认号=u+1,序列号=v),告诉Client我知道了,但是我可能还有消息要传输,进入CLOSE_WAIT
  3. Server发完所有信息后发一个FIN(序列号=w),告诉Client我发完了,我要关了,进入LAST_ACK
  4. Client收到FIN之后回复一个ACK(确认号=w+1),通知Server关闭,进入TIME_WAIT;等待2MSL之后彻底关闭;

为什么是四次:TCP是全双工的,双方都可以独立地发送信息;Client和Server都要告诉对方自己不再发送,所以两次FIN都需要,而Server不能把ACK和FIN合一则是因为Server可能还有未发送的信息,所以必须先通知Client自己可能还要发送,再通知自己不再发送;

TIME_WAIT的意义:最后的ACK可能丢包,如果发送完就关闭,丢包之后Server的重传Client就收不到了,导致Server被挂着;


HTTP的Keep-Alive是什么?TCP的Keepalive和HTTP的Keep-Alive是一个东西吗?

HTTP的Keep-Alive是应用层使用一个TCP连接发送多次请求;在HTTP1.0时代默认每次发起请求都要新建TCP连接,非常浪费,从HTTP1.1之后加入了默认的关键字Keep-Alive复用TCP连接;

TCP的Keepalive是一种探活机制,当连接在长时间(默认是2h)没有发送任何信息,本端会发送一个小的探测包,如果对方还活着就会回复一个ACK,保持连接;如果多次发送之后都没有回复,则判断对端已掉线,本端断开;防止连接成为僵尸连接占用端口;


DNS查询过程

DNS查询的目的就是把域名翻译为IP地址;大致可以分为两个阶段:

1. 本地查询阶段

浏览器输入一个域名之后会按照以下的流程进行本地查询,如果查询到了就直接返回:

  • 浏览器缓存:如果浏览器之前有缓存过该域名的IP,则会直接返回;
  • 操作系统缓存:操作系统也会维护一个DNS映射表;
  • 本地HOSTS文件:本地HOSTS也会维护DNS映射表;
  • 本地DNS服务器:通常是运营商提供的,它也有自己的缓存,如果之前有别人访问过这个域名则可以直接返回;

2. 迭代查询阶段

如果本地没有找到缓存则会开始迭代查询:

  • 本地DNS服务器会先向根域名服务器进行查询,根域名服务器会返回顶级域名服务器的地址,比如要查询example.com,就会告诉本地DNS服务器.com服务器在哪;
  • 接下来向顶级域名服务器进行查询,顶级域名服务器会返回管理该域名的权威域名服务器地址;
  • 最后本地DNS服务器会查询权威域名服务器获取域名对应的IP地址,返回地址后记录缓存并交给浏览器;

CDN是什么,有什么作用?

CDN(内容分发网络),本质上是一个分布式的缓存网络,核心思想就是把内容放在距离用户更近的地方;

假如没有CDN,一个位于日本的用户访问Youtube就需要每次向美国的服务器发起请求,太慢;而且一台服务器也扛不住所有用户的请求;

CDN就是在各个重要节点部署服务器,将资源提前缓存在服务器上,在用户发起请求时,直接去距离用户最近的服务器获取资源,如果没有才向源服务器发起请求并把资源缓存起来;

作用:

  • 提高访问速度:用户从最近的节点获取资源;
  • 提高并发能力:请求分散到多个节点;
  • 提高可用性:即使一台服务器挂掉了也有其他稍远的节点可用;

Cookie和Session是什么?有什么区别?

HTTP是无状态的,服务器并不知道每次请求的是谁,Cookie和Session正是为了让Server知道Client是谁而使用的;

Cookie:储存在Client的一段数据,记录了该Client的一些信息和用户信息,在发起请求时会发给Server;

Session:Server为某个用户创建的个性化数据,比如有用户的ID、状态、订单等等信息;在响应请求时会把Session对应的Session ID包装进Cookie里发给Client;

区别

  • 储存位置:Cookie在Client,Session在Server
  • 大小:Cookie一般只有几KB,Session理论无上限
  • 安全性:Cookie对用户是透明的,用户可以随意修改;Session存储在Server中不透明;
  • 生命周期:Cookie可以设置过期时间,Session的生命周期依赖于会话的持续和用户状态;