0%

NOSQL和SQL区别

  • SQL数据库,指关系型数据库 ,主要代表:SQL Server,Oracle,MySQL,PostgreSQL。关系型数据库存储结构化数据。这些数据逻辑上以行列二维表的形式存在,每一列代表数据的一种属性,每一行代表一个数据实体。
  • NoSQL指非关系型数据库 ,主要代表:MongoDB,Redis。NoSQL 数据库逻辑上提供了不同于二维表的存储方式,存储方式可以是JSON文档、哈希表或者其他方式。

选择 SQL vs NoSQL,考虑以下因素。

  • ACID vs BASE:关系型数据库支持 ACID 即原子性,一致性,隔离性和持续性。相对而言,NoSQL 采用更宽松的模型BASE , 即基本可用,软状态和最终一致性。从实用的角度出发,我们需要考虑对于面对的应用场景,ACID 是否是必须的。比如银行应用就必须保证ACID,否则一笔钱可能被使用两次;又比如社交软件不必保证 ACID,因为一条状态的更新对于所有用户读取先后时间有数秒不同并不影响使用。

  • 扩展性对比:NoSQL数据之间无关系,这样就非常容易扩展,也无形之间,在架构的层面上带来了可扩展的能力。比如 redis 自带主从复制模式、哨兵模式、切片集群模式。相反关系型数据库的数据之间存在关联性,水平扩展较难 ,需要解决跨服务器 JOIN,分布式事务等问题。

数据库三大范式是什么?

  • 第一范式(1NF):要求数据库表的每一列都是不可分割的原子数据项
  • 第二范式(2NF):在1NF的基础上,非码属性必须完全依赖于候选码(在1NF基础上消除非主属性对主码的部分函数依赖)第二范式需要确保数据库表中的每一列都和主键相关,而不能只与主键的某一部分相关(主要针对联合主键而言)
  • 第三范式(3NF):在2NF基础上,任何非主属性不依赖于其它非主属性(在2NF基础上消除传递依赖)第三范式需要确保数据表中的每一列数据都和主键直接相关,而不能间接相关

MySQL 怎么连表查询?

  1. 内连接 (INNER JOIN)
  2. 左外连接 (LEFT JOIN)
  3. 右外连接 (RIGHT JOIN)
  4. 全外连接 (FULL JOIN)

MySQL如何避免重复插入数据?

  • 使用UNIQUE约束:在表的相关列上添加UNIQUE约束,确保每个值在该列中唯一。
  • 使用INSERT … ON DUPLICATE KEY UPDATE:这种语句允许在插入记录时处理重复键的情况。如果插入的记录与现有记录冲突,可以选择更新现有记录:
  • 使用INSERT IGNORE: 该语句会在插入记录时忽略那些因重复键而导致的插入错误。

选择哪种方法取决于具体的需求:

  • 如果需要保证全局唯一性,使用UNIQUE约束是最佳做法
  • 如果需要插入和更新结合可以使用 ON DUPLICATE KEY UPDATE
  • 对于快速忽略重复插入, INSERT IGNORE 是合适的选择

CHAR 和 VARCHAR有什么区别?

  • CHAR是固定长度的字符串类型,定义时需要指定固定长度,存储时会在末尾补足空格。CHAR适合存储长度固定的数据,如固定长度的代码、状态等,存储空间固定,对于短字符串效率较高。
  • VARCHAR是可变长度的字符串类型,定义时需要指定最大长度,实际存储时根据实际长度占用存储空间。VARCHAR适合存储长度可变的数据,如用户输入的文本、备注等,节约存储空间。

varchar后面代表字节还是字符?

VARCHAR 后面括号里的数字代表的是字符数,而不是字节数。
字符的字节长度取决于所使用的字符集

  • ASCII 字符集:每个字符占用 1 个字节
  • UTF - 8 字符集,它的每个字符可能占用 1 到 4 个字节

int(1)和int(10) 在mysql有什么不同?

  • 本质是显示宽度,不改变存储方式: INT 的存储固定为 4 字节,所有 INT 占用的存储空间 均为 4 字节。括号内的数值是显示宽度,用于在 特定场景下 控制数值的展示格式。
  • 唯一作用场景: ZEROFILL 补零显示(不加ZEROFILL无效果),当字段设置 ZEROFILL 时:数字显示时会用前导零填充至指定宽度。比如,字段类型为 INT(4) ZEROFILL ,实际存入 5 → 显示为 0005 ,实际存入 12345→ 显示仍为 12345 (宽度超限时不截断)

Text数据类型可以无限大吗?

MySQL 4 种text类型的最大长度如下:

  • TINYTEXT: 28 255 bytes
  • TEXT:216约64kb
  • MEDIUMTEXT:224bytes 约16Mb
  • LONGTEXT:232bytes 约4Gb

IP地址如何在数据库里存储?

IPv4 地址是一个 32 位的二进制数,通常以点分十进制表示法呈现

字符串类型的存储方式:直接将 IP 地址作为字符串存储在数据库中,比如可以用 VARCHAR(15) 来存储。

  • 优点:直观易懂,方便直接进行数据的插入、查询和显示,不需要进行额外的转换操作。
  • 缺点:占用存储空间较大,字符串比较操作的性能相对较低,不利于进行范围查询。

整数类型的存储方式:将 IPv4 地址转换为 32 位无符号整数进行存储,常用的数据类型有 INTUNSIGNED 。

  • 优点:占用存储空间小,整数比较操作的性能较高,便于进行范围查询。
  • 缺点:需要进行额外的转换操作,不够直观,增加了开发的复杂度。

说一下外键约束

外键约束是 关系型数据库 中用于维护 表与表之间关联关系 的核心机制,它能强制保证数据的引用完整性,避免出现无效的关联数据。

优点:

  • 保证数据完整性:强制关联合法,避免孤儿数据,让数据更可靠。
  • 简化业务逻辑:通过级联操作,减少手动同步关联数据的代码(如删除用户时无需手动删除订单)。
  • 明确表关系:外键是表之间关联关系的 “显式声明”,便于开发者理解数据库结构。

缺点:

  • 性能开销:外键约束会增加数据库的写入开销,大数据量、高并发场景下可能影响性能。
  • 灵活性降低:外键强制绑定表关系,若业务需求变更,修改外键结构会比较麻烦。
  • 分布式场景不适用:跨数据库、跨服务器的表无法建立外键。

MySQL的关键字in和exist

IN 用于检查左边的表达式是否存在于右边的列表或子查询的结果集中。如果存在,则 IN 返回 TRUE ,否则返回 FALSE 。
EXISTS 用于判断子查询是否至少能返回一行数据。它不关心子查询返回什么数据,只关心是否有结果。如果子查询有结果,则 EXISTS 返回 TRUE ,否则返回 FALSE 。

区别与选择:

  • 性能差异:在很多情况下, EXISTS 的性能优于 IN ,特别是当子查询的表很大时。这是因为EXISTS 一旦找到匹配项就会立即停止查询,而 IN 可能会扫描整个子查询结果集。
  • 使用场景:如果子查询结果集较小且不频繁变动, IN 可能更直观易懂。而当子查询涉及外部查询的每一行判断,并且子查询的效率较高时,EXISTS 更为合适。
  • NULL值处理: IN 能够正确处理子查询中包含NULL值的情况,而 EXISTS 不受子查询结果中NULL值的影响,因为它关注的是行的存在性,而不是具体值。

mysql中的一些基本函数,你知道哪些?

  • 字符串函数
    • CONCAT(str1, str2, …):连接多个字符串,返回一个合并后的字符串。
    • LENGTH(str):返回字符串的长度
    • SUBSTRING(str, pos, len):从指定位置开始,截取指定长度的子字符串
    • REPLACE(str, from_str, to_str):将字符串中的某部分替换为另一个字符串。
  • 数值函数
    • ABS(num):返回数字的绝对值。
    • POWER(num, exponent):返回指定数字的指定幂次方。
  • 日期和时间函数
    • NOW():返回当前日期和时间。
    • CURDATE():返回当前日期。
  • 聚合函数
    • COUNT(column):计算指定列中的非NULL值的个数。
    • SUM(column):计算指定列的总和。
    • AVG(column):计算指定列的平均值。
    • MAX(column):返回指定列的最大值。
    • MIN(column):返回指定列的最小值。

SQL查询语句的执行顺序是怎么样的?

SQL基础-2025-11-24-15-06-33

所有的查询语句都是从FROM开始执行,在执行过程中,每个步骤都会生成一个虚拟表,这个虚拟表将作为下一个执行步骤的输入,最后一个步骤产生的虚拟表即为输出结果。

如何用 MySQL 实现一个可重入的锁?

创建一个保存锁记录的表:

1
2
3
4
5
6
7
8
9
CREATE TABLE `lock_table` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
//该字段用于存储锁的名称,作为锁的唯一标识符。
`lock_name` VARCHAR(255) NOT NULL,
// holder_thread该字段存储当前持有锁的线程的名称,用于标识哪个线程持有该锁。
`holder_thread` VARCHAR(255),
// reentry_count 该字段存储锁的重入次数,用于实现锁的可重入性
`reentry_count` INT DEFAULT 0
);

加锁的实现逻辑:

  1. 开启事务
  2. 执行 SQL SELECT holder_thread, reentry_count FROM lock_table WHERE lock_name =? FOR UPDATE,查询是否存在该记录:
    • 如果记录不存在,则直接加锁,执行 INSERT INTO lock_table (lock_name, holder_thread, reentry_count) VALUES (?,?, 1)
    • 如果记录存在,且持有者是同一个线程,则可重入,增加重入次数,执行 UPDATE lock_table SET reentry_count = reentry_count + 1 WHERE lock_name =?
  3. 提交事务

解锁的逻辑

  1. 开启事务
  2. 执行 SQL SELECT holder_thread, reentry_count FROM lock_table WHERE lock_name =?,查询是否存在该记录:
    • 如果记录存在,且持有者是同一个线程,且可重入数大于 1 ,则减少重入次数 UPDATE lock_table SET reentry_count = reentry_count - 1 WHERE lock_name =?
    • 如果记录存在,且持有者是同一个线程,且可重入数小于等于 1 ,则完全释放锁,DELETE FROM lock_table WHERE lock_name =?
  3. 提交事务

什么是ddos攻击?怎么防范?

分布式拒绝服务(DDoS)攻击是通过大规模互联网流量淹没目标服务器或其周边基础设施,以破坏目标服务器、服务或网络正常流量的恶意行为。

DDoS 攻击是通过连接互联网的计算机网络进行的。这些网络由计算机和其他设备组成,它们感染了恶意软件,从而被攻击者远程控制。这些个体设备称为机器人(或僵尸),一组机器人则称为僵尸网络

一旦建立了僵尸网络,攻击者就可通过向每个机器人发送远程指令来发动攻击。当僵尸网络将受害者的服务器或网络作为目标时,每个机器人会将请求发送到目标的 IP 地址,这可能导致服务器或网络不堪重负,从而造成对正常流量的拒绝服务。由于每个机器人都是合法的互联网设备,因而可能很难区分攻击流量与正常流量

常见的DDoS攻击包括以下几类:

  • 网络层攻击:比较典型的攻击类型是UDP反射攻击,例如:NTP Flood攻击,这类攻击主要利用大流量拥塞被攻击者的网络带宽,导致被攻击者的业务无法正常响应客户访问。
  • 传输层攻击:比较典型的攻击类型包括SYN Flood攻击、连接数攻击等,这类攻击通过占用服务器的连接池资源从而达到拒绝服务的目的。
  • 会话层攻击:比较典型的攻击类型是SSL连接攻击,这类攻击占用服务器的SSL会话资源从而达到拒绝服务的目的。
  • 应用层攻击:比较典型的攻击类型包括DNS flood攻击、HTTP flood攻击、游戏假人攻击等,这类攻击占用服务器的应用处理资源极大的消耗服务器处理性能从而达到拒绝服务的目的。

为了防范DDoS攻击,可以采取以下措施:

  • 增强网络基础设施:提升网络带宽、增加服务器的处理能力和承载能力,通过增强基础设施的能力来抵御攻击。
  • 使用防火墙和入侵检测系统:配置防火墙规则,限制不必要的网络流量,阻止来自可疑IP地址的流量。入侵检测系统可以帮助及时发现并响应DDoS攻击。
  • 流量清洗和负载均衡:使用专业的DDoS防护服务提供商,通过流量清洗技术过滤掉恶意流量,将合法流量转发给目标服务器。负载均衡可以将流量均匀地分发到多台服务器上,减轻单一服务器的压力。
  • 配置访问控制策略:限制特定IP地址或IP段的访问,设置访问频率限制,防止过多请求集中在单个IP上。

CSRF攻击是什么?

CSRF(跨站请求伪造)是一种攻击手段,攻击者通过诱导用户执行恶意操作,从而获取用户数据或执行恶意代码。CSRF攻击通常通过伪造一个合法的HTTP请求来实现,这个请求看起来是合法的,但实际上是为了执行一个攻击者控制的操作。

解决CSRF攻击的方法主要有以下几种:

  1. 验证用户会话:在服务器端对用户会话进行验证,确保请求的会话标识符与当前会话标识符匹配。这样可以防止攻击者伪造会话标识符。
  2. 使用双重验证:除了会话验证,还可以使用其他验证方式,例如验证码、签名验证等。这些验证方式可以增加攻击的难度。
  3. 防止跨站请求:通过设置CSP(内容安全策略)来防止跨站请求,限制网页中可执行的脚本源,减少攻击者诱导用户执行恶意操作的可能性。
  4. 避免使用自动提交表单:禁用默认的自动提交功能,要求用户在提交表单前确认操作,防止攻击者诱导用户在未经授权的情况下提交表单。
  5. 强制Referer头部:在服务器端检查请求的Referer头部,确保请求来自可信来源。

SQL注入问题是什么?

SQL注入发生在当应用程序直接使用用户提供的输入作为SQL查询的一部分时。当用户输入被错误地用作数据库查询的一部分,而应用程序没有对其进行适当的验证和转义,就可能会发生SQL注入。

解决SQL注入问题的方法主要有以下几种:

  1. 输入验证和转义:在将用户输入用作SQL查询的一部分之前,对输入进行验证和转义。确保输入符合预期格式,并防止任何可能导致SQL注入的特殊字符
  2. 使用参数化查询:使用参数化查询可以避免直接将用户输入嵌入到SQL查询中。参数化查询使用预定义的变量来接收用户输入,并将其传递给数据库引擎,而不是直接将其用作查询的一部分。这样可以防止SQL注入攻击
  3. 限制数据库权限:限制数据库用户的权限,只授予他们执行所需操作所需的最低权限。攻击者可能具有比预期更多的权限,这可能会使攻击更加容易
  4. 实施输入过滤:在某些情况下,实施输入过滤可以进一步减少SQL注入的风险。这可能涉及检查和过滤用户输入中的特殊字符和词汇,以排除可能的恶意输入

XSS攻击是什么?

XSS是跨站脚本攻击,攻击者通过在Web页面中插入恶意脚本代码,然后诱使用户访问该页面,从而使得恶意脚本在用户浏览器中执行,从而盗取用户信息、会话信息等敏感数据,甚至控制用户账户。

XSS 攻击可以分为 3 类:

  • 存储型 XSS:注入型脚本永久存储在目标服务器上。当浏览器请求数据时,脚本从服务器上传回并执行。
  • 反射型 XSS :当用户点击一个恶意链接,或者提交一个表单,或者进入一个恶意网站时,注入脚本进入被攻击者的网站。Web 服务器将注入脚本,比如一个错误信息,搜索结果等 返回到用户的浏览器上。由于浏览器认为这个响应来自”可信任”的服务器,所以会执行这段脚本。
  • 基于 DOM 的 XSS :通过修改原始的客户端代码,受害者浏览器的 DOM 环境改变,导致有效载荷的执行。也就是说,页面本身并没有变化,但由于 DOM 环境被恶意修改,有客户端代码被包含进了页面,并且意外执行。

预防XSS攻击的方法主要包括以下几点:

  • 输入验证:对所有用户输入的数据进行有效性检验,过滤或转义特殊字符。例如,禁止用户输入HTML标签和JavaScript代码。
  • 输出编码:在网页输出用户输入内容时,使用合适的编码方式,如HTML转义、URL编码等,防止恶意脚本注入。
  • CSP:通过设置CSP策略,限制网页中可执行的脚本源,有效防范XSS
    攻击。使用HttpOnly标记:在设置Cookie时,设置HttpOnly属性,使得Cookie无法被JavaScript代码读取,减少受到XSS攻击的可能。

什么是DNS劫持

DNS劫持的原理是攻击者在用户查询DNS服务器时篡改响应,将用户请求的域名映射到攻击者控制的虚假IP地址上,使用户误以为访问的是正常网站,实际上被重定向到攻击者操控的恶意网站。这种劫持可以通过植入恶意的DNS记录或劫持用户的DNS流量来实现。

如何防范 DNS 劫持?

  • 使用加密 DNS 协议,避免 DNS 查询被中间人篡改
  • 手动指定可靠的公共 DNS 服务器,减少对本地不可信 DNS 的依赖。
  • 检查设备的hosts文件和 DNS 配置,确保未被恶意修改
  • 访问网站时优先使用 HTTPS

描述一下打开百度首页后发生的网络过程

  • 解析URL:分析 URL 所需要使用的传输协议和请求的资源路径。如果输入的 URL 中的协议或者主机名不合法,将会把地址栏中输入的内容传递给搜索引擎。如果没有问题,浏览器会检查 URL 中是否出现了非法字符,则对非法字符进行转义后在进行下一过程。
  • 缓存判断:浏览器缓存 → 系统缓存(hosts 文件) → 路由器缓存 → ISP 的 DNS 缓存,如果其中某个缓存存在,直接返回服务器的IP地址。
  • DNS解析:如果缓存未命中,浏览器向本地 DNS 服务器发起请求,最终可能通过根域名服务器、顶级域名服务器(.com)、权威域名服务器逐级查询,直到获取目标域名的 IP 地址。
  • 获取MAC地址:当浏览器得到 IP 地址后,数据传输还需要知道目的主机 MAC 地址,因为应用层下发 数据给传输层,TCP 协议会指定源端口号和目的端口号,然后下发给网络层。网络层会将本机地址作为源地址,获取的 IP 地址作为目的地址。然后将下发给数据链路层,数据链路层的发送需要加入通信双方的 MAC 地址,本机的 MAC 地址作为源 MAC 地址,目的 MAC 地址需要分情况处理。通过将 IP 地址与本机的子网掩码相结合,可以判断是否与请求主机在同一个子网里,如果在同一个子网里,可以使用 ARP 协议获取到目的主机的 MAC 地址,如果不在一个子网里,那么请求应该转发给网关,由它代为转发,此时同样可以通过 ARP 协议来获取网关的 MAC 地址,此时目的主机的MAC 地址应该为网关的地址。
  • 建立TCP连接:主机将使用目标 IP地址和目标MAC地址发送一个TCP SYN包,请求建立一个TCP连接,然后交给路由器转发,等路由器转到目标服务器后,服务器回复一个SYN-ACK包,确认连接请求。然后,主机发送一个ACK包,确认已收到服务器的确认,然后 TCP 连接建立完成。
  • HTTPS 的 TLS 四次握手:如果使用的是 HTTPS 协议,在通信前还存在 TLS 的四次握手
  • 发送HTTP请求:连接建立后,浏览器会向服务器发送HTTP请求。请求中包含了用户需要获取的资源的信息,例如网页的URL、请求方法(GET、POST等)等
  • 服务器处理请求并返回响应:服务器收到请求后,会根据请求的内容进行相应的处理

网页非常慢转圈圈的时候,要定位问题需要从哪些角度?

最直接的办法就是抓包,排查的思路大概有:

  1. 先确定是服务端的问题,还是客户端的问题。先确认浏览器是否可以访问其他网站,如果不可以,说明客户端网络自身的问题,然后检查客户端网络配置

  2. 如果客户端网络没问题,就抓包确认 DNS 是否解析出了 IP 地址,如果没有解析出来,说明域名写错了,如果解析出了 IP 地址,抓包确认有没有和服务端建立三次握手,如果能成功建立三次握手,并且发出了 HTTP 请求,但是就是没有显示页面,可以查看服务端返回的响应码:

    • 如果是404错误码,检查输入的url是否正确
    • 如果是500,说明服务器此时有问题
    • 如果是200,F12看看前端代码有问题导致浏览器有渲染出页面
  3. 如果客户端网络是正常的,但是访问速度很慢,导致很久才显示出来。这时候要看客户端的网口流量是否太大的了,导致tcp发生丢包之类的问题。
    总之就是一层一层有没有插网线,网络配置是否正确、DNS有没有解析出 IP地址、TCP有没有三次握手、HTTP返回的响应码是什么

server a和server b,如何判断两个服务器正常连接?出错怎么办

如果一直不发送数据给客户端,那么服务端是永远无法感知到客户端宕机这个事件的,也就是服务端的 TCP连接将一直处于 ESTABLISH 状态,占用着系统资源。

TCP 保活机制:定义一个时间段,在这个时间段内,如果没有任何连接相关的活动,TCP 保活机制会开始作用,每隔一个时间间隔,发送一个探测报文,该探测报文包含的数据非常少,如果连续几个探测报文都没有得到响应,则认为当前的 TCP 连接已经死亡,系统内核将错误信息通知给上层应用程序。

如果开启了 TCP 保活,需要考虑以下几种情况:

  • 对端程序是正常工作的。当 TCP 保活的探测报文发送给对端, 对端会正常响应,这样 TCP保活时间会被重置,等待下一个 TCP 保活时间的到来。
  • 对端主机宕机并重启。当 TCP 保活的探测报文发送给对端后,对端是可以响应的,但由于没有该连接的有效信息,会产生一个 RST 报文,这样很快就会发现 TCP 连接已经被重置。
  • 对端主机宕机(注意不是进程崩溃,进程崩溃后操作系统在回收进程资源的时候,会发送 FIN 报文,而主机宕机则是无法感知的,所以需要 TCP 保活机制来探测对方是不是发生了主机宕机),或对端由于其他原因导致报文不可达。当 TCP 保活的探测报文发送给对端后,石沉大海,没有响应,连续几次,达到保活探测次数后,TCP 会报告该 TCP 连接已经死亡。

TCP 保活机制检测的时间有点长,可以自己在应用层实现一个心跳机制。

比如,web 服务软件一般都会提供 keepalive_timeout 参数,用来指定 HTTP 长连接的超时时间。如果设置了 HTTP 长连接的超时时间是 60 秒,web 服务软件就会启动一个定时器,如果客户端在完成一个HTTP 请求后,在 60 秒内都没有再发起新的请求,定时器的时间一到,就会触发回调函数来释放该连接。

服务端正常启动了,但是客户端请求不到有哪些原因?如何排查?

如果客户端请求的接口没有响应,排查的方式:

  • 检查接口IP地址是否正确,ping一下接口地址。
  • 检查被测接口端口号是否正确,可以在本机Telnet接口的IP和端口号,检查端口号能否连通
  • 检查服务器的防火墙是否关闭,如果是以为安全或者权限问题不能关闭,需要找运维进行策略配置,开放对应的IP和端口。
  • 检查你的客户端,是否设置了网络代理,网络代理可能造成请求失败。
  • 如果客户端的请求有响应,但是返回了错误状态码,那么根据错误码做对应的排查

服务器ping不通但是http能请求成功,会出现这种情况吗?什么原因造成的?

ping 走的是 icmp 协议,http 走的是 tcp 协议。有可能服务器的防火墙禁止 icmp 协议,但是 tcp 协议没有禁止,就会出现服务器 ping 不通,但是 http能请求成功。

讲一下tcp头部

传输层-2025-11-07-19-46-50

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

讲一下TCP三次握手

TCP是面向连接的协议,所以使用TCP前必须建立连接,建立连接是通过三次握手进行的

一开始,客户端和服务端都处于close状态,服务端主动监听某个端口,处于LISTEN状态

第一次握手

客户端随机初始化序列号,将此序号置于TCP首部的序列号字段,同时把SYN标记为1,表示SYN报文,接着把第一个SYN报文发送给服务器,表示向服务器请求连接,该报文不含应用层数据,接下来客户端处于SYN-SENT状态

第二次握手

服务端收到客户端的SYN报文后,服务端也随机初始化自己的序列号,将此序列号填入TCP首部的序号字段,其次把TCP首部的确认应答号字段填入client_isn+1,接着把SYN和ACK置为1。最后把该报文发送给客户端,该报文不包含应用层数据,之后服务端处于SYN-RCVD状态

第三次握手

客户端收到服务端报文后,向服务器回应应答报文,该应答报文的ACK位置为1,确认应答号填入server_isn+1,最后把报文发送给服务器,这次报文可以携带客户到服务端的数据,之后客户端处于ESTABLISHED状态

服务端收到客户端应答报文后,也处于ESTABLISHED状态

三次握手完成,连接建立,客户端和服务端就能互相发送数据了

TCP为什么需要三次握手建立连接

三次握手原因:

  • 阻止重复历史连接的初始化(主要原因)
  • 同步双方的初始序列号
  • 避免资源浪费

阻止重复历史连接的初始化

为什么两次握手不能避免这一问题?

两次握手情况下,服务器收到SYN报文后就进入ESTABLISHED状态,意味着这时候可以给客户端发送数据,但客户端没有进入ESTABLISHED状态,客户端识别到此次为历史连接,返回RST报文来中断连接,但服务器已经进入了连接状态,浪费了服务器资源

同步双方初始序列号

序列号是可靠传输的关键因素:

  • 接收方可以去除重复数据
  • 接收方可以根据数据包的序列号按序接收
  • 可以标识发送出去的数据包中,哪些已经被对方接收

两次握手只能保证一方的序列号被对方成功接收

避免资源浪费

如果没有三次握手,客户端发送的SYN报文在网络中阻塞了,客户端没有收到报文,就会重新发送SYN,由于没有第三次握手,服务端不清楚客户端是否收到了自己回复的ACK报文,所以服务器每收到一个SYN就建立一个连接,建立不必要的冗余连接,造成资源浪费

TCP三次握手,客户端第三次发送的确认包丢失了会发生什么

客户端收到服务端的SYN-ACK报文后,就会给服务器回一个ACK,此时客户端进入ESTABLISHED状态

如果服务器长时间没有收到确认报文,就会触发超时重传机制,重新发送SYN-ACK报文,直到收到收到第三次握手或者达到重传最大次数

ACK报文是不会有重传的,当ACK丢失了,就由对方重传对应的报文

三次握手和accept的关系

tcp完成三次握手后,连接会被保存到内核的全连接队列,调用accept就是把连接取出来给用户程序使用

服务器没有收到客户端发送的SYN报文怎么办

客户端发送SYN报文后,迟迟收不到服务器的SYN+ACK报文,就会触发超时重传机制,重传SYN报文,而且重传的SYN报文都是一样的

在linux,客户端的SYN报文重传最大次数有tcp_syn_retries内核参数控制,每一次超时的时间是上一次的两倍

达到最大重传次数后,等待一段时间,如果还是没有收到服务端的第二次握手,客户端就会断开连接

第二次握手的SYN+ACK报文丢失会发生什么

客户端接收ACK超时会发生重传,服务端超时未接收到第二次握手SYN报文的ACK也会触发重传机制,直到重传最大次数,若客户端在重传次数耗尽前,服务器的SYN+ACK重传成功到达,客户端会发送第三次ACK,握手完成。

假如客户端重传SYN报文,服务端收到了重复的SYN报文怎么办

不新建连接,仅重传 SYN+ACK,本质是配合客户端的重试机制,确保握手能在网络丢包场景下完成

第一次握手,客户端发送SYN报文后,服务端回复ACK报文,那这个过程中服务端进行了哪些工作

服务端收到客户端发送的SYN请求后,内核会把连接存储到半连接队列,并向服务端响应SYN+ACK报文,接着客户端发送ACK报文,服务端收到第三次握手的ACK报文后,内核会把连接从半连接队列移除,然后创建新的完全的连接,并将其添加到accept队列,等待进程调用accept函数取出连接

大量SYN包发给服务端会发生什么

可能会导致TCP半连接队列打满,TCP半连接队列满后,后续再收到SYN报文会丢弃,导致客户端无法和服务端建立连接

避免SYN攻击的方式:

  • 调大netdev_max_log(增大内核接收队列的最大长度)
  • 增大TCP半连接队列
  • 开启net.ipv4.tcp_syncookies(在不使用半连接队列的情况下建立连接)
  • 减少SYN+ACK重传次数(加快处理时间)

在不使用半连接队列的情况下建立连接:

  • 当SYN队列满后,后续的服务端收到SYN包不再丢弃,而是计算出一个cookie
  • 将cookie值放到第二次握手报文的序列号里,然后服务端返回ACK+SYN
  • 服务端接收到客户端的应答报文,服务端检查ACK的合法性。如果合法,将连接对象放入accept队列

讲一下TCP四次挥手

第一次挥手

客户端主动调用关闭连接的函数,于是发送FIN报文,这个FIN报文代表客户端不会再发送数据

第二次挥手

服务端收到FIN报文,马上回复ACK确认报文,此时服务器进入CLOSE_WAIT状态。收到FIN报文后,TCP协议栈会为FIN包插入一个文件结束符EOF到接收缓冲区中,服务端应用程序通过read调用来感知这个FIN包,这个EOF会被**放在已排队等待的其他已接收数据后,所以要继续read接收缓冲区已接受的数据

第三次挥手

接着服务器read数据读到EOF后,read会返回0,这时服务端应用程序如果有数据要发送,就发完数据后调用关闭连接的函数,否则直接调用关闭连接函数。服务端发一个FIN包,表示服务器不再发送数据,之后处于LAST_ACK状态

第四次挥手

客户端接收到服务器的FIN包,发送ACK给服务端,此时客户端进入TIME_WAIT状态
服务端收到ACK后进入CLOSE状态
客户端经过2MSL(两倍的最长报文段寿命)后进入CLOSE状态

为什么四次握手中间两次不能变成一次

服务器收到客户端的FIN报文,内核会立即返回一个ACK应答,但服务端应用程序可能还有数据要发送,所以不能马上发送FIN报文,而是发送将FIN报文的控制权交给服务端应用程序

  • 如果服务端应用程序没有数据要发送,就直接调用关闭连接的函数
  • 否则发送发送完数据后调用关闭连接函数

第二次挥手和第三次挥手能合并吗

当被动关闭方在TCP挥手过程中,没有数据要发送开启了TCP延迟确认机制,那么第二次和第三次挥手就会合并,这样就出现了三次挥手

第三次挥手一致没发,会发生什么

当主动方收到ACK报文后。会进入FIN_WAIT2状态,就表示主动方的发送通道已经关闭,接下来将等待对方发送FIN报文,关闭对方的连接通道。
这是,如果连接是用shundown函数关闭的,连接可以一直处于FIN_WAIT2状态,因为他可能还可以接收数据。但对于close关闭的孤儿连接,由于无法接收或发送数据,所以这个状态可能无法持续太久(默认60s)
这意味着对于孤儿连接,如果60s后没有收到FIN报文,连接会直接关闭

第二次挥手和第三次挥手之间,主动断开的一方能干什么

如果主动关闭的一方是调用shutdown 函数来关闭连接,并且只选择了关闭发送能力而没有关闭接收能力,那么主动断开的一方还能接收数据

断开连接时客户端FIN包丢失,服务端的状态是什么

客户端调用close函数后,就会向服务端发送FIN报文,试图与服务端断开连接,此时客户端进入FIN_WAIT1状态

如果第一次挥手丢失,客户端迟迟收不到服务端的ACK,就会出现超时重传机制,重传FIN报文直到最大重传次数

当重传次数超过最大重传次数后,就不会再发送FIN报文,而是等待一段时间,如果还是没有收到第二次挥手,客户端直接进入close状态,服务端还是established状态

为什么四次挥手之后要等2MSL?

MSL:最长报文段寿命,任何报文在网络上存在的最长时间,超
过这个时间报文将被丢弃。

网络中可能存在来自发送方的数据包,当这些发送
方的数据包被接收方处理后又会向对方发送响应,所以一来一回需要等待 2 倍的时间。

比如,如果被动关闭方没有收到断开连接的最后的 ACK 报文,就会触发超时重发 FIN 报文,另一方接收到 FIN 后,会重发 ACK 给被动关闭方, 一来一去正好 2 个 MSL。
可以看到 2MSL时长 这其实是相当于至少允许报文丢失一次。比如,若 ACK 在一个 MSL 内丢失,这样被动方重发的 FIN 会在第 2 个 MSL 内到达,TIME_WAIT 状态的连接可以应对。

服务端出现大量的timewait有哪些原因?

什么场景下服务端会主动断开连接呢?

  • HTTP 没有使用长连接
  • HTTP 长连接超时
  • HTTP 长连接的请求数量达到上限

HTTP 没有使用长连接

HTTP/1.0 中默认是关闭的,如果浏览器要开启 Keep-Alive,它必须在请求的 header 中添加:Connection: Keep-Alive,后当服务器收到请求,作出回应的时候,它也被添加到响应中 header 里

TCP 连接就不会中断,而是保持连接。当客户端发送另一个请求时,它会使用同一个 TCP 连接。这一直继续到客户端或服务器端提出断开连接。

HTTP/1.1 开始, 就默认是开启了 Keep-Alive,如果要关闭 HTTP Keep-Alive,需要在 HTTP 请求或者响应的 header 里添加 Connection:close 信息

根据大多数 Web 服务的实现,不管哪一方禁用了 HTTP Keep-Alive,都是由服务端主动关闭连接,那么此时服务端上就会出现 TIME_WAIT 状态的连接。

HTTP 长连接超时

HTTP 长连接的特点是,只要任意一端没有明确提出断开连接,则保持 TCP 连接状态。

如果客户端在完后一个HTTP 请求后,在最大超时时间内都没有再发起新的请求,定时器的时间一到,服务器就会触发回调函数来关闭该连接,那么此时服务端上就会出现 TIME_WAIT 状态的连接。

可以往网络问题的方向排查,比如是否是因为网络问题,导致客户端发送的数据一直没有被服务端接收到,以至于 HTTP 长连接超时。

HTTP 长连接的请求数量达到上限

Web 服务端通常会有个参数,来定义一条 HTTP 长连接上最大能处理的请求数量,当超过最大限制时,就会主动关闭连接。

在高QPS,keepalive-request不高的情况下,就会频繁关闭连接,导致大量的time_wait

TCP和UDP的区别

  • 连接:TCP 是面向连接的传输层协议,传输数据前先要建立连接;UDP 是不需要连接,即刻传输数据
  • 服务对象:TCP 是一对一的两点服务,即一条连接只有两个端点。UDP 支持一对一、一对多、多对多的交互通信
  • 可靠性:TCP 是可靠交付数据的,数据可以无差错、不丢失、不重复、按序到达。UDP 是尽最大努力交付,不保证可靠交付数据
  • 拥塞控制、流量控制:TCP 有拥塞控制和流量控制机制,保证数据传输的安全性。UDP 则没有,即使网络非常拥堵了,也不会影响 UDP 的发送速率
  • 首部开销:TCP 首部长度较长,会有一定的开销,首部在没有使用「选项」字段时是 20 个字节,如果使用了「选项」字段则会变长的。UDP 首部只有 8 个字节,并且是固定不变的,开销较小
  • 传输方式:TCP 是流式传输,没有边界,但保证顺序和可靠。UDP 是一个包一个包的发送,是有边界的,但可能会丢包和乱序

TCP为什么是可靠传输

  • 连接管理:即三次握手和四次挥手。连接管理机制能够建立起可靠的连接,这是保证传输可靠性的前提。
  • 序列号:TCP将每个字节的数据都进行了编号,这就是序列号。序列号能够保证可靠性,既能防止数据丢失,又能避免数据重复。能够保证有序性,按照序列号顺序进行数据包还原。能够提高效率,基于序列号可实现多次发送,一次确认。
  • 确认应答:接收方接收数据之后,会回传ACK报文,报文中带有此次确认的序列号,用于告知发送方此次接收数据的情况。在指定时间后,若发送端仍未收到确认应答,就会启动超时重传。
  • 超时重传:超时重传主要有两种场景:数据包丢失:在指定时间后,若发送端仍未收到确认应答,就会启动超时重传,向接收端重新发送数据包。确认包丢失:当接收端收到重复数据(通过序列号进行识别)时将其丢弃,并重新回传ACK报文。
  • 流量控制:接收端处理数据的速度是有限的,如果发送方发送数据的速度过快,就会导致接收端的缓冲区溢出,进而导致丢包。为了避免上述情况的发生,TCP支持根据接收端的处理能力,来决定发送端的发送速度。这就是流量控制。流量控制是通过在TCP报文段首部维护一个滑动窗口来实现的。
  • 拥塞控制:拥塞控制就是当网络拥堵严重时,发送端减少数据发送。拥塞控制是通过发送端维护一个拥塞窗口来实现的。可以得出,发送端的发送速度,受限于滑动窗口和拥塞窗口中的最小值。

怎么用udp实现http

UDP 是不可靠传输的,但基于 UDP 的 QUIC 协议 可以实现类似 TCP 的可靠性传输,在http3 就用了 quic 协议。

  • 连接迁移:QUIC支持在网络变化时快速迁移连接,例如从WiFi切换到移动数据网络,以保持连接的
    可靠性。
  • 重传机制:QUIC使用重传机制来确保丢失的数据包能够被重新发送,从而提高数据传输的可靠性。
  • 前向纠错:QUIC可以使用前向纠错技术,在接收端修复部分丢失的数据,降低重传的需求,提高可
    靠性和传输效率。
  • 拥塞控制:QUIC内置了拥塞控制机制,可以根据网络状况动态调整数据传输速率,以避免网络拥塞和丢包,提高可靠性

tcp粘包怎么解决

粘包的问题出现是因为不知道一个用户消息的边界在哪

固定长度的消息

这种方式灵活性不高,实际中很少用。

特殊字符作为边界

HTTP 通过设置回车符、换行符作为 HTTP 报文协议的边界。
有一点要注意,这个作为边界点的特殊字符,如果刚好消息内容里有这个特殊字符,我们要对这个字符
转义,避免被接收方当作消息的边界点而解析到无效的数据。

自定义消息结构

我们可以自定义一个消息结构,由包头和数据组成,其中包头包是固定大小的,而且包头里有一个字段来说明紧随其后的数据有多大。

TCP的拥塞控制介绍一下

拥塞控制的目的就是避免「发送方」的数据填满整个网络

为了在「发送方」调节所要发送数据的量,定义了一个叫做「拥塞窗口」的概念

拥塞窗口cwnd是发送方维护的一个的状态变量,它会根据网络的拥塞程度动态变化的。发送窗口 swnd和接收窗口 rwnd 是约等于的关系,那么由于加入了拥塞窗口的概念后,此时发送窗口的值是swnd =min(cwnd, rwnd),也就是拥塞窗口和接收窗口中的最小值。

拥塞窗口 cwnd 变化的规则:

  • 只要网络中没有出现拥塞,cwnd 就会增大
  • 但网络中出现了拥塞,cwnd 就减少

那么怎么知道当前网络是否出现了拥塞呢?

只要「发送方」没有在规定时间内接收到 ACK 应答报文,也就是发生了超时重传,就会认为网络出现了拥塞。

慢启动

TCP 在刚建立连接完成后,首先是有个慢启动的过程,这个慢启动的意思就是一点一点的提高发送数据包的数量

慢启动的算法记住一个规则就行:当发送方每收到一个 ACK,拥塞窗口 cwnd 的大小就会加1

可以看出慢启动算法,发包的个数是指数性的增长。

那慢启动涨到什么时候是个头呢?

有一个叫慢启动门限 ssthresh (slow start threshold)状态变量。

  • 当 cwnd < ssthresh 时,使用慢启动算法
  • 当 cwnd >= ssthresh 时,就会使用「拥塞避免算法」

拥塞避免算法

拥塞避免算法后,它的规则是:每当收到一个 ACK 时,cwnd 增加 1/cwnd

拥塞避免算法就是将原本慢启动算法的指数增长变成了线性增长,还是增长阶
段,但是增长速度缓慢了一些

就这么一直增长着后,网络就会慢慢进入了拥塞的状况了,于是就会出现丢包现象,这时就需要对丢失的数据包进行重传。

当触发了重传机制,也就进入了「拥塞发生算法」。

拥塞发生

当网络出现拥塞,也就是会发生数据包重传,重传机制主要有两种:

  • 超时重传
  • 快速重传

超时重传

当发生了「超时重传」,则就会使用拥塞发生算法。
这个时候,ssthresh 和 cwnd 的值会发生变化:

  • ssthresh 设为 cwnd/2,
  • cwnd 恢复初始值

重新开始慢启动

快速重传

当接收方发现丢了一个中间包的时候,发送三次前一个包的 ACK,于是发送端就会快速地重传,不必等待超时再重传。
TCP 认为这种情况不严重,因为大部分没丢,只丢了一小部分,则 ssthresh 和 cwnd 变化如下:

  • cwnd = cwnd/2 ,也就是设置为原来的一半;
  • ssthresh = cwnd;
  • 进入快速恢复算法

快速恢复算法

  • 拥塞窗口 cwnd = ssthresh + 3 (3的意思是确认有3个数据包被收到了);
  • 重传丢失的数据包;
  • 如果再收到重复的 ACK,那么 cwnd 增加 1;
  • 如果收到新数据的 ACK 后,把 cwnd 设置为第一步中的 ssthresh 的值,原因是该 ACK 确认了新的数据,说明从 duplicated ACK 时的数据都已收到,该恢复过程已经结束,可以回到恢复之前的状态了,也即再次进入拥塞避免状态

返回指令ret和retf

格式:ret ;实现近转移,相当于pop ip
格式:retf; 实现远转移,相当于pop ip ,pop cs

例10-1.补全程序,实现从内存1000:0处开始执行指令。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
assume cs:code
stack segment
db 16 dup(0)
stack ends
code segment
start:
mov ax,stack
mov ss,ax
mov sp,16
mov ax,---
push ax
mov ax,---
push ax
retf
code ends
end start
1
2
mov ax,0
mov ax,1000

call指令

执行call指令的功能相当于:
1、push ip或push cs、push ip;
2、修改当前ip或ip和cs指向目的地址。

依据位移进行转移的call指令

格式:call 标号
功能:将当前IP压栈,IP=IP+16位的位移量,转移到标号处执行。

应用层有哪些协议

HTTP、FTP、HTTPS、SMTP、DNS协议

HTTP报文有哪些部分

请求报文:

  • 请求行:请求方法,请求目标,HTTP版本
  • 请求头:请求的附加信息,如User-Agent,Content-Type,Host等
  • 空行:请求头和请求体之间的分隔
  • 请求体:可选,请求的数据

响应报文:

  • 状态行:HTTP版本,状态码,状态信息
  • 响应头:响应的附加信息,如Content-Type,Content-Length
  • 空行:响应头和响应体之间的分隔
  • 响应体:响应的数据,通常是HTML,JSON等内容

HTTP常用状态码

  • 1xx属于提示信息,是协议处理的一种中间状态,实际用到的较少
  • 2xx表示成功处理了客户端请求
  • 3xx表示客户端请求的资源发生了变动,客户端需要用新的URL发送请求获取资源,也就是重定向
  • 4xx表示客户端发送的报文有问题,服务端无法处理,也就是错误码
  • 5xx表示客户端请求正确,服务端内部出现问题,属于服务器错误码

常见的具体状态码:

  • 200:请求成功
  • 301:永久重定向
  • 302:临时重定向
  • 404:无法找到请求的资源
  • 405:请求的方法不支持
  • 500:服务器内部错误

HTTP返回状态301,302分别是什么

  • 301:表示永久重定向,请求的资源已经不存在了,需要改用新的URL再次访问
  • 302:临时重定向,表示请求的资源还在,但临时需要用另一个URL访问

301和302都会在响应头的location字段指明要跳转的URL

HTTP 502和504的区别是什么

  • 502:bad gateway,作为网关或者代理工作的服务器尝试执行请求时,从上游服务器接收到无效的响应
  • 504:gateway time-out,网关或代理服务器尝试执行请求时,未能及时从上有服务器接收到响应

HTTP请求的类型有哪些

  • GET:用于请求获取指定资源,通常用于获取指定数据
  • POST:用于向服务器提供数据,通常用于提交表单数据或资源创建
  • PUT:用于向服务器更新指定资源,通常用于更新已存在的资源
  • DELETE:用于请求服务器删除指定资源
  • HEAD:类似于GET请求,只返回头部信息,用于获取资源的元数据而不获取实际内容

HTTP长连接是什么

HTTP采用的[请求-应答]模式,也就是客户端发送请求,服务器返回响应
由于HTTP是基于TCP协议实现的,客户端与服务器通信前,要先建立TCP连接,需要经历:建立TCP->请求资源->响应资源->释放连接(HTTP短连接)

HTTP的keey-alive实现了HTTP长连接,可以使用同一TCP连接来接受多个HTTP请求/应答,避免连接的建立和释放的开销

长连接的特点是:只要任意一端没有提出断开连接,则保持TCP连接状态

HTTP默认端口是什么

http是80,https是443

HTTP1.1怎么对请求拆包

HTTP 请求的结构是:请求行 → 头部字段 → 空行 → 请求体(可选)。

  • 首先读取请求行,读取到空行表示请求头读取结束。
  • 根据请求头的content-length,该字段指示了请求体的长度,服务器根据该长度正确接受和解析请求。

HTTP断点重传是什么

HTTP协议中实现 “下载中断后无需重新下载整个文件,仅续传未完成部分”,主要用于优化大文件下载体验,减少带宽浪费。

  • 客户端记录断点:当下载中断时,客户端会记录已成功下载的文件字节位置。
  • 发起范围请求:再次下载时,客户端通过请求头的Range字段告知服务器续传起点
  • 服务器部分响应:若服务器支持断点重传,会返回206状态码,同时通过Content-Range响应头明确本次返回的字节范围,并仅传输该范围的数据。
  • 客户端拼接数据:客户端将新接收的部分数据与本地已下载的部分拼接,最终组成完整文件。

实现断点重传有两个关键前提:

  • 一是服务器需开启对Range请求的支持(静态文件服务器通常默认支持,动态内容需额外配置);
  • 二是文件未被修改,客户端会通过Last-Modified或ETag验证文件完整性,若文件已变则需重新下载。

HTTP为什么不安全

HTTP是明文传输,因此存在以下三个风险:

  • 窃听风险:通信链路上可以获取通信内容
  • 篡改风险:强制植入广告
  • 冒充风险:冒充网站

HTTPS在TCP层添加了SSL/TLS协议,很好的解决了上述风险:

  • 信息加密:对称加密 + 非对称加密结合
  • 校验机制:无法篡改信息内容,篡改了就不能正常显示
  • 身份证书:由权威机构背书,避免中间人伪装服务器

HTTP与HTTPS区别

  • HTTP是超文本传输协议,信息是明文传输,存在安全风险问题。HTTPS则解决HTTP不安全的特点,在TCP和HTTP层之间加入SSL/TLS协议,报文加密传输
  • HTTP连接建立相对简单,TCP三次握手后即可进行HTTP报文传输。而HTTPS在三次握手后还要进行SSL/TLS握手,才能进行报文加密传输
  • HTTP默认端口80,HTTPS443
  • HTTPS需要向CA申请数字证书,来保证服务器的身份是可信的

讲一下HTTPS握手过程

TLS第一次握手

客户端向服务器发送加密通信请求:

  • 客户端支持的TLS版本
  • 客户端产生的随机数,后续用于生成密钥
  • 客户端支持的密码套件列表,如RSA

TLS第二次握手

服务器接收到客户端请求后,向客户端发出响应:

  • 确认TLS协议版本
  • 服务器产生的随机数,后续用于生成密钥
  • 确认的密码套件列表
  • 服务器的数字证书

TLS第三次握手

客户端收到服务器响应,首先通过浏览器或操作系统中的CA公钥,确认服务器数字证书的真实性

如果没有问题,客户端从数字证书中取出服务器的公钥,然后使用它加密报文(只加密随机数),向服务器发送信息:

  • 一个随机数
  • 加密通信算法改变通知
  • 客户端握手结束通知

客户端和服务器有了这三个随机数,接着就用双方协商的加密算法,各自生成本次通话的会话密钥

TLS第四次握手

服务器收到客户端的第三个随机数后,计算出通信密钥

然后向客户端发送信息:

  • 加密算法改变通知
  • 服务器握手结束通知

接下来服务器与客户端进行加密通信

HTTPS如何防止中间人攻击

  • 加密:通过非对称加密协商对称加密密钥
  • 身份校验:服务器向证书权威机构申请证书,证书包含服务器公钥等其他信息。客户端与服务器建立连接时,服务器会将证书发送给客户端。客户端校验证书的合法性,如果验证通过,客户端使用证书中的公钥加密通信数据发送给服务器,服务器用私钥解密

由于攻击者无法获取服务器的私钥,因此无法正确解密客户端发送的加密数据。客户端会验证服务器的证书,避免中间人伪装服务器

HTTP1.1和2.0区别

  • 头部压缩:如果同时发送多个请求,他们的头是一样的或相似的,HTTP2会消除重复部分。即HPACK算法:客户端和服务器同时维护一张头信息表,所有字段都会存入这张表,生成索引号,以后只需要发送索引号,这样就提高速度了
  • 二进制格式:对计算机友好,提高传输效率
  • 并发传输:提出Stream,多个Stream复用TCP连接,解决队头阻塞问题(HTTP3Quick协议基于UDP彻底解决队头阻塞)
  • 服务器主动推送资源:服务器可以主动向客户端发送消息

HTTP进行TCP连接后,什么情况会中断

  • 当服务器或客户端执行close系统调用时会发送FIN报文,就会进行四次挥手
  • 当发送方发送数据后,接收方超过一段时间没有响应ACK报文,发送方重传次数达到最大次数时就会断开TCP连接
  • 当HTTP长时间没有进行请求和响应的时候,超过一定时间,就会释放

HTTP,SOCKET和TCP的区别

  • HTTP是用于传输超文本数据的应用层协议,用于在客户端和服务端之间传输和显示web数据
  • SOCKET是是计算机网络的一种抽象,用于描述通信链路的一端,提供了底层的通信接口,可以实现不同计算机之间的数据交换
  • TCP是一种面向连接的、可靠的传输层协议,负责在通信的两端之间建立可靠的数据传输连接

DNS域名解析的工作流程

  1. 客户端先查本地hosts 文件,若有域名-IP映射,直接返回,解析结束;否则进入下一步。
  2. 客户端发出一个DNS请求,询问域名的ip,并发给本地DNS服务器
  3. 本地DNS收到客户端的请求后,如果缓存里能找到,就直接返回,否则询问他的根域名服务器
  4. 根DNS收到本地DNS请求后,返回顶级域名服务器地址
  5. 本地DNS询问顶级域名服务器
  6. 顶级域名服务器返回权威DNS服务器地址
  7. 本地DNS询问权威DNS服务器
  8. 权威DNS服务器查询后返回对应的ip地址
  9. 本地DNS服务器将ip返回给客户端,同时存入自身缓存,客户端与目标建立连接

DNS的默认端口是多少

53

DNS底层是UDP还是TCP

DNS是基于UDP实现的,原因:

  • 低延迟:UDP是一种无连接的协议,不需要在数据传输前建立连接,因此可以减少传输延迟
  • 简单快速:UDP无连接管理和流量控制机制,传输效率更高
  • 轻量级:UDP头部较小,占用较少的网络资源

DNS使用一些机制来提高可靠性,如超时重传,请求重试,缓存等,以确保数据传输的可靠性和正确性

HTTT是不是无状态的

HTTP是无状态的,这意味着每个请求都是独立的,服务器不会在多个请求之间保留客户端的状态信息。
虽然HTTP本身是无状态的,但可以通过一些机制来实现状态保持,如cookie和session。通过在客户端存储会话信息和状态信息,服务器可以识别和跟踪特定用户的状态,以提供一定程度的状态保持功能

Cookie是HTTP协议簇的一部分,那为什么说HTTP是无状态的

HTTP 协议在设计初衷上保持无状态特性,即每个请求都是相互独立的。使用 Cookie 只是在无状态协议下的一种补充机制,用于在客户端存储状态信息以实现状态保持。

cookie和session的区别

  • 存储位置:cookie存储在客户端。当浏览器向服务器发送请求时,会自动附带cookie中的数据。session的数据存储在服务器端。服务器为每个用户分配一个独立的sessionID,这个sessionID通过cookie或url重写的方式发送给客户端,客户端后续请求都会带上这个sessionID,服务器根据id查找对应的session数据
  • 数据容量:单个cookie大小限制在4kb左右,而且大多数浏览器对每个域名的总cookie数量也有限制。由于session存储在服务器上,理论上不受数据大小限制
  • 安全性:cookie相对不安全,因为数据存储在客户端,容易受到XSS攻击,不过可以通过设置HttpOnly属性阻止javaScript访问,但仍可能受到CSRF攻击。Session通常认为比cookie更安全,因为敏感数据存储在服务器端,但仍然需要防范session劫持
  • 生命周期:cookie可以设置过期时间,过期后自动删除,也可以设置为会话cookie,即浏览器关闭后自动删除。session默认情况下,当用户关闭浏览器,session结束,服务器也可以设置session的超时时间
  • 性能:cookie因为数据随每次请求发送到服务器,影响网络传输速度。session因为存储在服务器,每次请求查询服务器数据,这会增大服务器压力

token,session,cookie的区别

  • token:类似令牌,无状态,信息都被加密到token里,服务端收到token解密后就可以知道是哪个用户,需要开发者手动添加
  • cookie:也类似令牌,当浏览器向服务器发送请求时,会自动附带cookie中的数据。
  • session:存储在服务器,服务器为每个用户分配一个独立的sessionID,这个sessionID通过cookie或url重写的方式发送给客户端,客户端后续请求都会带上这个sessionID,服务器根据id查找对应的session数据

如果客户端禁用了cookie,session还能用吗

默认不能。大多数浏览器都是依靠cookie来传递会话id的
禁用cookie后,浏览器无法把会话id发给客户端,客户端也无法在后续请求中携带会话id,导致服务器无法识别用户会话

但是可以通过其他方法绕过:

  • URL重写:每当服务器响应需要保存状态的请求时,将session id拼接到url中,服务器解析url来获取sessionId,这样的方法一是url不整洁,而是容易造成sessionID外泄
  • 隐藏表单字段:在每个需要session信息的HTML表单中包含一个隐藏字段,用来存储sessionID,当表单提交时,session id随表单数据一起发送回服务器,服务器通过解析表单中的sessionId来获取用户状态。这种方法仅适用于通过表单提交的交互模式,不适合链接点击和ajax请求

如果把数据存到localStorage,和cookie有什么区别

  • 存储容量:cookie大小一般几kb,localStorage可以存放几mb
  • 数据发送:cookie在每次http请求都会自动发送到服务器,localStorage不会自动发送到服务器,他只在浏览器存储数据,因此适用于同一域名下不用页面的共享数据
  • 生命周期:cookie可以设置过期时间,localStorage只能手动删除
  • 安全性:cookie的安全性较低,因为每次http请求都会发给服务器,localStrage只存在浏览器,相对安全一些

什么数据应该存在cookie,什么数据存在localStorage

  • cookie适用于在客户端和服务器传递信息,跨域访问和设置过期时间
  • localStorage适用于在同一域名下的不同页面共享数据,存储大量数据和永久存储数据

JWT令牌与传统方式有什么区别

  • 无状态性:jwt是无状态令牌,不需要在服务器端存储会话信息,相反.jwt令牌包含了所有必要的信息,如用户身份,权限等
  • 安全性:jwt使用密钥对令牌进行签名,确保令牌的真实性和完整性,只有持有正确的密钥才能对令牌验证和解析,有效防止了CSRF等攻击
  • 跨域支持:jwt令牌可以在不用域之间传递,适用于跨域访问场景。通过在请求头中携带jwt令牌,实现无需cookie的跨域身份验证

jwt令牌有哪些字段

jwt令牌由三部分组成:

  • 头部
  • 载荷
  • 签名

头部和载荷都是json格式,使用base64编码进行序列化,签名部分是对头部、载荷和密钥进行签名

jwt为什么能解决集群部署问题

在传统的基于session和cookie的身份验证方式中,session信息通常存储在服务器内存或数据库中,但在集群部署中,不同的服务器没有共享的会话信息,这导致用户在不同的服务器之间切换时需要重新登陆,或者引入额外的共享机制(如redis),增加了开销的复杂性

而jwt令牌在令牌中包含所需的身份验证和会话信息,使得服务器无需存储会话信息,解决了集群部署中身份验证和会话管理的问题。

由于jwt令牌是自包含的,服务器可以独立的对令牌进行验证,而不需要依赖其他服务器或共享存储,这使得集群中的每个服务器都可以独立处理请求,提高了系统的可伸缩性和可容错性

jwt的缺点,令牌如果泄漏了,怎么解决

jwt一旦配发出去,在失效之前都是有效的,无法撤销
要解决这个问题,可以在业务层添加逻辑判断,如黑名单机制,使用内存数据库维护一个黑名单,将要失效的jwt加入黑名单即可

前端如何存储JWT

  • 本地存储(Local Storage)
    • 优点:LocalStorage存储空间大,且不会随http请求发送到服务器,因此不会出现在http缓存或日志中
    • 缺点:存在 XSS(跨站脚本攻击)的风险,恶意脚本可以通过 JavaScript 访问到存储在 Local Storage 中的 JWT,从而盗取用户凭证
  • Session Storage(会话存储)
    • 优点:与 Local Storage 类似,但仅限于当前浏览器窗口或标签页,当窗口关闭后数据会被清除,这在一定程度上减少了数据泄露的风险。
    • 缺点:用户体验可能受影响,因为刷新页面或在新标签页打开相同应用时需要重新认证。
  • Cookie
    • 优点:可以设置 HttpOnly 标志来防止通过 JavaScript 访问,减少 XSS 攻击的风险;可以利用 Secure 标志确保仅通过 HTTPS 发送,增加安全性。
    • 缺点:大小限制较小,并且每次 HTTP 请求都会携带 Cookie,可能影响性能;设置不当可能会受到 CSRF(跨站请求伪造)攻击。

为什么有了HTTP还需要RPC

  • 设计目标不同:HTTP是通用的应用层协议,强调跨平台、易扩展,但协议本身较冗余,更适合松散耦合场景,而RPC的核心是”让远程调用像本地函数一样简单”,目标是高效、低延迟、更侧重内部服务之间的通信
  • 性能差异:HTTP常用JSON等文本格式,序列化慢、数据量大,且协议头冗余;RPC 多采用二进制协议,序列化效率高、数据紧凑,加上连接复用、多路复用等优化,更适合高频、大数据量的内部调用,能显著降低延迟。

HTTP长连接和websocket有什么区别

  • 全双工与半双工:TCP本身时全双工的,但HTTP1.1虽然基于TCP,但他是半双工的,对于大部分服务器主动推送数据到客户端的场景都不太友好,因此需要支持全双工的websocket
  • 应用场景区别:HTTP长连接适合 “客户端需频繁向服务器请求数据” 的场景,通过复用连接减少 TCP 握手开销,但无法解决 “服务器主动推送” 需求。websocket适合 “双向实时通信” 场景,优势是低延迟、少开销,服务器可主动推送数据,无需客户端频繁轮询。

nginx有哪些负载均衡算法

  • 轮询
  • ip哈希:根据ip的哈希值确定分配请求的服务器
  • url哈希
  • 最短响应时间:优先分配响应时间最短的服务器,适合服务器性能不均的场景
  • 加权轮询:按照权重分配请求给服务器,权重越高的服务器分配的请求越多,适合服务器性能不均的场景

nginx位于七层网络结构的哪一层

第七层应用层

讲一下OSI模型

OSI模型分为七层:

  • 应用层:负责给应用程序提供统一的接口
  • 表示层:负责把数据转换成兼容另一个系统能识别的格式
  • 会话层:负责建立、管理和终止表示层实体之间的通信会话
  • 传输层:负责端到端的数据传输
  • 网络层:负责数据的路由、转发、分片
  • 数据链路层:负责数据的封帧和差错检测和mac寻址
  • 物理层:负责在物理网络中传输数据帧

OSI过于复杂,提出的也只是理论上的分层,并没有具体的实现方案

讲一下TCP/IP模型

TCP/IP模型分为四层,不包含物理层和数据链路层,因此不能独立完成计算机网络的功能,必须与其他协议协同工作

  • 应用层:支持HTTP,SFTP等最终用户进程
  • 传输层:支持主机到主机的通信(TCP/UDP)
  • 网络层:寻址和路由数据包(IP)
  • 网络接口层:数据的物理传输,链路控制

什么是消息队列

消息队列是一种基于 “生产者-消费者” 模式的中间件,核心作用是在不同系统或组件间暂存、传递消息,实现异步通信和解耦,避免因系统间直接调用导致的依赖和性能问题。

消息队列怎么选型

特性 RabbitMQ RocketMQ Kafka
单机吞吐量 万级 10 万级 10 万级
时效性 微秒级 毫秒级 毫秒级
可用性 高(主从) 非常高(分布式) 非常高(分布式)
消息重复 至少一次 一次 一次
消息顺序性 有序 有序 分区有序
支持主题数 百万级 千级 百级
消息回溯 不支持 支持 支持
  • 对于秒杀活动,应当选择Kafka或RocketMQ这类高吞吐量
  • 对于金融业务,应重点考虑稳定性、安全性,分布式部署的Kafka和RocketMQ比较适合
  • 对于公司中台,对外提供服务,需要较多的主题接入,考虑RocketMQ或者RabbitMQ

消息队列的使用场景有哪些

  • 解耦:在多个系统之间解耦,将原本通过网络之间的调用方式改为使用mq进行异步通信,只要该操作不需要同步,就可以改为MQ进行多个系统之间的联系,这样项目之间不会存在耦合,就算一个系统挂了,也只是消息积压在mq里没人处理,不会对其他系统造成影响
  • 异步:主流程发完消息即返回,用户无需等待非核心步骤,大幅降低感知延迟,提升体验
  • 削峰:将用户的消息放到mq里,系统按自己最大的消费能力去消费这些消息,保证系统的稳定

如何解决消息重复消费问题

首先要明确,MQ 无法彻底杜绝消息重复,因为网络波动、集群主从切换等不可抗因素,消息重复是必然会发生的。所以解决思路不是‘避免重复’,而是‘让重复消息不影响业务正确性’,也就是实现消费端的幂等性处理

主要有三种常用方案:

  • 基于消息唯一ID去重:生产者发送消息时,给每个消息带一个全局唯一 ID,消费者拿到消息后,先去 Redis 或数据库的‘已消费消息表’查这个 ID 是否存在。如果不存在,就处理业务,同时把 ID 存进去;如果存在,直接跳过。
  • 基于业务唯一键去重:如果业务本身就有天然的唯一标识,不用额外生成消息ID。比如扣库存场景,用‘商品ID+订单ID’作为唯一键
  • 基于状态机去重,适合有严格状态流转的业务。比如订单状态只能从‘待支付’到‘已支付’再到‘已发货’,不能反向。

如何解决消息丢失问题

  • 消息生产阶段:保障生产者到MQ不丢消息,一是开启生产者确认机制,MQ 收到消息后会给生产者返回确认,没收到确认就重试;二是关键消息落库,生产者发送前先把消息存到本地数据库,等收到 MQ 确认后再标记为 “已发送”,若重试失败,后续通过定时任务重新发送,彻底避免 “发了没收到” 的问题。
  • 消息存储阶段:一是开启消息持久化,不管是RabbitMQ还是Kafka,都要配置持久化参数,避免内存中的消息因宕机丢失;二是MQ集群部署,用主从架构或分布式集群,主节点故障时,从节点能切换成新主,且从节点已同步了消息,不会导致数据丢失。
  • 消息消费阶段:关闭消费者自动确认,改用手动确认。消费者拿到消息后,先执行业务逻辑,只有确认业务处理成功,再手动给 MQ 发送 ACK;如果处理失败,不发送 ACK,MQ 会认为消息没处理,等消费者恢复后重新推送。

如何处理消息队列的消息积压问题

消息积压是因为生产者的速度大于消费者。
,核心思路是 “先止损(快速消费掉积压消息),再根治(找到积压根源并优化)”,需分 “紧急处理” 和 “长期优化” 两步走,同时避免处理过程中引发新问题(如下游服务被压垮)。

  • 紧急处理:快速消化已积压的消息
    • 临时扩容消费者:快速扩容消费者实例,提高并发处理能力
    • 优化消费逻辑:减少单条消息处理耗时,同步改异步,批量处理
    • 临时分流:避免新消息加剧积压。若上游生产者仍在持续发消息,可临时分流部分消息到 “备用队列”,优先处理主队列积压,待主队列清完后再处理备用队列。
  • 长期优化:找到积压根源,避免再次发生
    • 消费端容错优化
    • 下游服务优化

如何保证数据一致性,事务消息如何实现

  1. 生产者产生消息,发送一条半事务消息到mq
  2. mq收到消息,将消息持久化到存储系统,这条消息的状态是待发送
  3. mq返回ack给生产者
  4. 生产者执行本地事务
  5. 如果本地事务执行成功,则commit执行结果到mq,否则发送rollback
  6. 如果是正常的commit,mq修改消息状态为可发送,如果是rollback则删除消息
  7. 如果消息状态更新为可发送,mq会push消息给消费者,消费者消费完成返回ack
  8. 如果mq长时间没受到commit,会反查生产者,根据查询结果执行最终状态

消息队列是参考哪种设计模式

  • 发布-订阅模式:这是消息队列的核心模式。生产者发送消息到队列,多个消费者同时接收消息(根据主题或队列分组)。
  • 观察者模式:消息队列可视为 “被观察者”,消费者是 “观察者”。当队列中有新消息时,会通知订阅的消费者处理,本质是一种松耦合的通知机制
  • 生产者-消费者模式:生产者生成消息并放入队列,消费者从队列中获取消息并处理,队列作为缓冲区隔离两者,避免直接交互,实现异步通信和削峰填谷。

你了解过哪些I/O模型

  • 阻塞I/O模型:应用程序发起I/O操作后会被阻塞,直到操作完成后才会返回结果。适用于对实时性不高的场景
  • 非阻塞I/O模型:应用程序发起I/O操作后立即返回,不会被阻塞,但是需要不断轮询或者使用select/poll/epoll等系统调用来检查I/O操作是否完成。适用于需要多路复用的程序,例如需要处理多个socket连接的服务器程序
  • I/O复用模型:通过select/poll/epoll等系统调用,应用程序可以同时等待多个I/O操作,当其中任何一个I/O操作准备就绪时,应用程序会被通知。适用于需要同时处理多个I/O操作的场景,比如高并发的服务端程序
  • 信号驱动I/O模型:应用程序发起I/O操作后继续做其他事情,当I/O操作完成时,操作系统会向应用程序发送信号通知其完成。适用于需要异步I/O的场景,提高系统的并发能力
  • 异步I/O模型:应用程序发起操作后立即去做其他事情,当I/O操作完成时,应用程序得到通知。异步I/O操作通过操作系统内核完成I/O操作,应用程序只需等待通知即可。适用于需要大量并发连接和高性能的场景,减少系统调用次数,提高调用效率

服务器处理并发请求有哪几种方式

  • 单线程web服务器方式:web服务器一次处理一个请求,结束后读取并处理下一个请求,性能较低
  • 多进程/多线程服务器:web服务器生成多个进程或线程并行处理用户请求,进程或线程可以按需或事先生成。有的web服务器为每个用户请求生成一个线程,进行响应,不过并发请求达到成千上万时,多个同时运行的线程会消耗大量的系统资源,
  • I/O多路复用web服务器:web服务器可以I/O多路复用,达到一个线程就能监听多个客户端的I/O事件
  • 多路复用多线程web服务器:将多线程和多路复用结合起来的web服务器,避免让一个线程服务于过多的用户请求,并能充分利用多CPU所提供的计算能力

讲一下I/O多路复用

I/O多路复用是一种多线程IO处理方式,指的是复用一个线程,处理多个socket中的事件。能够实现资源复用,防止创建过多线程导致的上下文切换开销

select,poll,epoll的区别是什么

select,poll,epoll都是用于I/O多路复用的机制

select

select的实现方式是将已连接的socket放入文件描述符集合,然后调用select函数将文件描述符集合拷贝到内核里,让内核来检查是否有网络事件产生(遍历),当检测到网络事件,将此socket标记为可读/可写,接着把整个文件描述符集合拷贝回用户态,用户态找到可读/可写socket(遍历)对其进行处理

对于select需要遍历两次文件描述符集合,一次是在用户态,一次是在内核态,还会发生两次拷贝文件描述符集合

select使用定长的bitmap表示文件描述符集合,而且所支持的文件描述符个数是有限的,在linux中有FD_SETSIZE限制,默认1024

poll

poll不再用bitmap存储所关注的文件描述符,而是采用动态数组,采用链表形式组织,突破了文件描述符的个数,还会受到系统描述符的限制

其余poll与select差别不大

epoll

  • epoll在内核中使用红黑树来跟踪进程所用待检测的文件描述符,把需要监控的socket通过epoll_ctl()函数加入到内核的红黑树中。epoll因为在内核维护了红黑树,可以保存所有待检测的socket,所以只需要传入一个socket,减少了内核和数据空间大量的数据拷贝和内存分配
  • epoll使用事件驱动机制,内核里维护一个链表来记录就绪事件,当某个socket有事件发生时,内核通过回调函数将其加入到这个就绪队列中,当用户调用epoll_wait()时,只会返回有事件发生的文件描述符的个数,而不需要返回整个epoll集合

epoll监听线程的个数上限为系统描述符的个数,且监听线程数很多时性能不会大幅降低,是解决C10K问题的核心技术

C10K问题:同时处理 10,000 个并发连接

epoll的边缘触发和水平触发有什么区别

epoll支持两种事件触发机制:边缘触发和水平触发

  • 边缘触发:当被监控的socket描述符上有可读事件发生时,服务器端只会从epoll_wait()苏醒一次,即使进程没有调用read函数从内核读取数据,也依然只苏醒一次,因此程序要保证一次性把内核缓冲区的数据读取完毕
  • 水平触发:当被监控的socket描述符上有可读事件发生时,服务器不断从epoll_wait中苏醒,直到内核缓冲区数据被read函数读完才结束,目的是告诉我们有数据需要读取

如果使用边缘触发,I/O事件发生时只会通知一次,因此我们会循环从文件描述符读写数据,如果文件描述符是阻塞的,没有数据可读写时,进程会阻塞在读写函数那里,程序没办法往下继续执行,因此边缘触发通常与非阻塞式I/O一起使用

如果使用水平触发,当内核通知文件描述符可读写时,接下来还会检测他的状态,看他是否还是可读写。

一般边缘触发比水平触发效率高,因为边缘触发可以减少epoll_wait的系统调用次数

零拷贝是什么

传统的I/O工作方式,从硬盘读写数据,然后通过网卡向外发送,需要进行四次数据拷贝(磁盘->内核态内存->用户态内存->内核态内存->网卡),为了提高文件传输的性能,出现了零拷贝技术

通过一次系统调用合并了磁盘读取和网络发送两个操作(磁盘->内核态->网卡),将4次拷贝减少到2次,同时避免CPU拷贝和用户态->内核态切换,大幅提升I/O效率。

redis、nignx、netty是依赖什么实现的高性能

主要依赖Reactor模式实现的高性能,这是在I/O多路复用的基础上实现的基于事件驱动的网络模型

Reactor模式是灵活多变的,可以应对不同的业务场景:

  • Reactor的数量可以有一个也可以有多个
  • 处理资源池可以是单线程也可以是多线程

Redis

redis 6.0之前使用单Reactor单线程模式(6.0之后单 Reactor + 多 I/O 线程)。因为全部工作都在一个线程内完成,不需要考虑多线程竞争问题。

这种方案有两个缺点:

  • 只有一个线程,无法充分利用多核CPU性能
  • Handler对象在业务处理时,整个线程是无法链接其他事件的,如果业务处理耗时比较长,那就造成了响应延迟

因此单线程Reactor不适合计算密集型的场景,只适用于业务处理非常快的场景

netty

多Reactor多线程模式

优势是:

  • 主线程和子线程分工明确,主线程只负责接收新连接,子线程负责完成后续的业务处理
  • 主线程和子线程的交互很简单,主线程只需要把新连接传给子线程,子线程无需返回数据,直接就可以在子线程将处理结果发给客户端

nginx

nginx是多Reactor多进程模式,不过与标准情况有些差异

主进程仅仅用来初始化socket,并没有创建mainReactor来accept连接,而是子进程的Reactor来accept连接,通过锁(同一时间只允许一个 Worker进程监听端口)来控制一次只有一个子进程进行accept(防止惊群效应),子进程accept新连接后就放到自己的Reactor里进行处理,不会再非配给其他的子进程

惊群效应:多个等待者同时争抢同一个资源,导致无效竞争和资源浪费

什么是中断

CPU停下当前的工作任务,去处理其他事情,处理完成后继续执行刚才的任务,这一过程就是中断

中断分为内部中断和外部中断:

  • 外部中断来自于CPU外部,由硬件产生,分为可屏蔽中断和不可屏蔽中断
    • 可屏蔽中断:通过INTR线向CPU请求的中断,主要来自外部设备如硬盘、打印机等。此类中断不影响系统运行,可以随时处理甚至不处理
    • 不可屏蔽中断:通过NMI线向CPU请求的中断,如电源掉电,线路故障。不可屏蔽是说问题太大无法屏蔽
  • 内部中断来自于处理器内部,分为陷阱、故障、终止
    • 陷阱:有意的、预先安排的异常事件,一般是写程序时故意设下的陷阱指令,然后执行到陷阱时,CPU会调用特定程序进行相应的处理,**处理结束后返回到陷阱指令的下一条指令。
    • 故障:故障是在引起故障的指令被执行但还没执行结束时,CPU检测到的一类意外事件。出错时交由故障处理程序处理,如果能正确处理这个错误,就将控制返回引起故障的指令即CPU重新执行这条指令,如果不能处理就报错。常见的故障如缺页异常
    • 终止:执行指令的过程中发生了致命错误,不可修复,程序无法继续运行,只能终止,通常是一些硬件错误。终止程序不会将控制返回原程序,而是直接终止原程序

中断的流程

  • 发生中断:当外部设备或软件程序需要处理器注意或响应时,会发出中断信号。处理器接收到中断信号后,会停止执行当前指令,保存当前执行现场,并跳转到中断处理程序执行
  • 中断响应:处理器接收到中断信号后,会根据中断向量表找到对应的中断处理程序的入口地址,处理器会保存当前执行现场,以便处理完成后能够继续执行
  • 中断处理:处理器跳转到中断处理程序的入口地址开始执行中断处理程序。中断处理程序会根据中断类型进行相应的处理,可能涉及到保存现场、处理中断事件、执行特定任务等

中断的作用是什么

中断使得计算机系统具备应对处理突发事件的能力,提高CPU的工作效率,如果没有中断系统,CPU就只能按照原来程序编写的先后顺序,对各个外设进行查询和处理,即轮询工作方式,工作效率低,不能即使响应紧急事件