共 19 道 计算机基础 面试题。答案默认折叠,便于先自行作答。

1. 进程、线程、协程分别是什么概念?

难度:1 · 类型:QA

题目要点

  • 进程 是独立的资源分配单位,每个进程有自己的内存和资源。
  • 线程 是进程中的执行单元,线程之间共享进程的资源,但每个线程有自己的执行栈。
  • 协程 是一种用户级的轻量级线程,通过程序控制的方式在任务之间进行切换,适合需要高效并发的场景。
参考答案

进程、线程和协程是计算机程序设计中不同层次的执行单元,各自有不同的概念和特点。以下是它们的详细解释:

1. 进程(Process)

概念:进程是操作系统分配资源的基本单位,是正在执行的程序的实例。每个进程都有自己的地址空间、内存、文件描述符等资源。

特点

  • 独立性:进程是相互独立的,互不干扰。一个进程的崩溃不会直接影响到其他进程。
  • 资源分配:每个进程有独立的内存空间和系统资源。
  • 开销大:由于需要独立的资源和内存,进程之间的切换(上下文切换)开销相对较大。

应用:常用于需要高隔离性和独立性的场景,如多进程服务器、操作系统服务等。

2. 线程(Thread)

概念:线程是进程中的执行单元,是程序执行的最小单位。一个进程可以包含多个线程,这些线程共享进程的资源(如内存)。

特点

  • 共享资源:线程之间共享进程的内存和资源,这使得线程间通信更加高效,但也带来了同步和竞争的问题。
  • 开销小:线程的创建和销毁比进程要快,线程之间的切换也比进程切换更高效。
  • 协作:线程之间可以进行协作,适合进行多任务处理。

应用:适用于需要并发执行的场景,如多线程应用程序、并行计算等。

3. 协程(Coroutine)

概念:协程是一种轻量级的线程,允许在执行过程中挂起和恢复,支持非抢占式的任务切换。协程可以在单线程中并发执行多个任务,但它们之间的切换由程序控制而不是操作系统。

特点

  • 协作式切换:协程通过显式的挂起和恢复操作进行切换,不需要操作系统的调度。
  • 轻量级:协程的创建和切换开销非常小,通常比线程更高效。
  • 适用场景:适用于需要大量并发操作但不需要多线程资源的场景,如异步编程、事件驱动编程等。

应用:广泛用于异步编程、游戏开发、网络编程等领域。许多现代编程语言(如 Python 的 asyncio、JavaScript 的 async/await)都支持协程。

2. 解释性语言和编译型语言有什么区别?

难度:2 · 类型:QA

题目要点

  • 解释性语言:逐行解释执行,适合快速开发和跨平台,但执行速度较慢。
  • 编译型语言:预先编译成机器码,执行速度较快,适合性能要求高的应用,但开发周期较长。

现代编程语言和环境往往结合这两种方式,以兼顾开发效率和执行性能。

参考答案

解释性语言和编译型语言是两种不同的编程语言执行方式,它们在代码执行、编译过程、执行效率等方面有显著差异。以下是它们的主要区别:

1. 解释性语言(Interpreted Languages)

  • 定义:解释性语言的代码在运行时由解释器逐行解释和执行。解释器将源代码逐步翻译成机器码或中间代码,然后立即执行。

  • 执行方式

    • 代码在每次执行时都会被解释器逐行翻译。
    • 不需要预先编译成机器码。
  • 优点

    • 开发和测试灵活性:支持即时运行和调试,便于快速开发和修改。
    • 跨平台性:代码可以在不同平台上运行,只要有相应的解释器。
  • 缺点

    • 执行速度较慢:因为每次运行时都需要解释器进行翻译。
    • 运行时开销:解释器在运行时会消耗额外的资源。
  • 示例:JavaScript、Python、Ruby、PHP。

2. 编译型语言(Compiled Languages)

  • 定义:编译型语言的代码在执行之前通过编译器转换成机器码或中间代码。编译过程在运行之前完成。

  • 执行方式

    • 代码被预先编译成机器码或中间代码,然后生成可执行文件。
    • 程序运行时直接执行编译后的机器码,无需再次翻译。
  • 优点

    • 执行速度较快:编译后的机器码直接执行,通常比解释性语言更快。
    • 优化:编译器可以进行各种优化,提高代码性能。
  • 缺点

    • 开发和测试周期较长:需要编译过程,修改代码后必须重新编译。
    • 平台依赖:生成的机器码通常与特定平台相关,需要针对不同平台编译。
  • 示例:C、C++、Rust、Go。

3. 混合模式

一些现代语言结合了解释型和编译型的特点:

  • Java

    • 使用 字节码(中间代码),由 Java 编译器生成。
    • 字节码在 Java 虚拟机(JVM)上运行,JVM 解释或即时编译(JIT)字节码为机器码。
  • C#

    • 使用 中间语言(IL),由 C# 编译器生成。
    • 运行时由 .NET 运行时(CLR)解释或即时编译(JIT)IL 为机器码。

3. V8 里面的 JIT 是什么?

难度:2 · 类型:QA

题目要点

V8 引擎中的 JIT 编译 是一种动态编译技术,它能够在 JavaScript 执行时实时将代码编译成机器码并优化执行,从而提升性能。通过结合 Ignition 解释器和 TurboFan 优化编译器,V8 能够在提供较快启动速度的同时,不断优化热点代码的执行效率。JIT 编译广泛应用于 Web 和 Node.js 开发中,对于性能要求较高的应用,能够带来显著的加速效果。

参考答案

V8 引擎中的 JIT(Just-In-Time)编译 是一种在程序执行时将高层的源代码(例如 JavaScript)动态编译成机器码的技术。与提前编译(AOT,Ahead-Of-Time)不同,JIT 编译是在程序运行时进行的,即代码执行到某个部分时,V8 引擎会将其转换为优化后的机器码,然后直接执行,而不需要再进行解释。

JIT 编译的工作流程

  1. 解析:当 JavaScript 代码首次执行时,V8 会将其解析为 抽象语法树(AST)
  2. 解释执行:V8 会将代码转换为字节码并进行解释执行,速度较慢,但可以让代码快速开始执行。
  3. 发现热点代码:在执行过程中,V8 会监控哪些代码频繁执行(也称为 热点代码)。一旦发现某段代码被多次执行,V8 就会认为该代码是 热路径,并将其提交给 JIT 编译器进行优化。
  4. JIT 编译:V8 会对这些热点代码进行 JIT 编译,生成优化后的机器码,并将其缓存起来。下一次执行该代码时,直接使用编译后的机器码而不再解释执行。
  5. 优化:V8 使用多个优化阶段(如内联缓存、死代码消除、函数内联等)来对代码进行进一步优化。通过不断执行和分析代码,V8 能够逐步优化执行的速度。

V8 中的 JIT 类型

V8 引擎采用了多种 JIT 技术来提高 JavaScript 的执行效率:

  1. Ignition(解释器):V8 引擎的解释器,负责将 JavaScript 源代码转换为字节码并执行。对于短期执行或不频繁的代码,V8 会使用 Ignition 来快速启动,避免编译过程带来的开销。

  2. TurboFan(优化编译器):一旦代码被多次执行,V8 会将热点代码传递给 TurboFan,这是一种优化编译器,它将字节码转换为机器码,并进行一系列优化,如内联、循环展开、类型分析等,从而使代码执行更加高效。

JIT 的优点

  • 性能提升:JIT 编译能够根据代码的实际运行情况进行优化,生成更高效的机器码,通常比纯解释执行要快得多。
  • 适应性:JIT 编译器根据程序的执行情况实时优化,能够在运行时动态调整代码优化策略,适应不同的执行环境。
  • 启动速度:虽然 JIT 编译器需要一些额外的时间来进行优化,但它能够通过先执行解释模式代码来快速启动程序,而后再优化热代码。

JIT 的缺点

  • 内存开销:JIT 编译需要存储中间的字节码和机器码,这可能导致较高的内存消耗。
  • 编译开销:JIT 编译需要额外的时间来编译代码,虽然它是在运行时进行的,但对于某些应用程序,特别是短小和一次性的脚本,这种编译开销可能不划算。
  • 延迟执行:由于 JIT 编译是基于代码的执行路径来进行的,在某些情况下,JIT 编译可能导致初次执行时的性能下降,因为需要经过解释执行到一定的执行量后,才会触发优化。

典型使用场景

  • Web 应用和 Node.js 应用:由于 JavaScript 是 Web 应用和 Node.js 应用的主要编程语言,V8 引擎的 JIT 编译使得这些应用在执行时能够享受高度优化的性能,尤其是在处理复杂计算或大量请求时。
  • 大规模 JavaScript 应用:对于需要执行大量循环和函数调用的应用,JIT 编译能够显著提高执行效率。

4. 说说你对计算机网络模型的理解

难度:2 · 类型:QA

题目要点

计算机网络的各层及其协议的集合被称为网络的体系结构,按照不同的维度,其常被分为七层、五层、四层网络结构:

参考答案

一、体系结构

计算机网络的各层及其协议的集合被称为网络的体系结构,按照不同的维度,其常被分为七层、五层、四层网络结构:

1.1 七层网络模型

开放式系统互联模型(Open System Interconnection Model,简称为 OSI 模型)是一种概念模型,由国际标准化组织提出,并试图成为计算机在世界范围内互连为网络的标准框架,它具有七层网络结构。

1.2 四层网络模型

互联网协议套件(Internet Protocol Suite,IPS)是多个网络传输协议的集合,它为网际网络的基础通信提供架构支撑。由于该协议族中最核心的两个协议分别为 TCP(传输控制协议)和 IP(网际协议),因此它也被称为 TCP/IP 协议族(TCP/IP Protocol Suite 或 TCP/IP Protocols),简称 TCP/IP,它具有四层网络结构 。

1.3 五层网络模型

OSI 七层网络模型由国际标准化组织进行制定,它是正统意义上的国际标准。但其实现过于复杂,且制定周期过长,在其整套标准推出之前,TCP/IP 模型已经在全球范围内被广泛使用,所以 TCP/IP 模型才是事实上的国际标准。TCP/IP 模型定义了应用层、传输层、网际层、网络接口层这四层网络结构,但并没有给出网络接口层的具体内容,因此在学习和开发中,通常将网络接口层替换为 OSI 七层模型中的数据链路层和物理层来进行理解,这就是五层网络模型:

  1. 应用层 (application layer):直接为应用进程提供服务。应用层协议定义的是应用进程间通讯和交互的规则,不同的应用有着不同的应用层协议,如 HTTP协议(万维网服务)、FTP协议(文件传输)、SMTP协议(电子邮件)、DNS(域名查询)等。
  2. 传输层 (transport layer):有时也译为运输层,它负责为两台主机中的进程提供通信服务。该层主要有以下两种协议:
    • 传输控制协议 (Transmission Control Protocol,TCP):提供面向连接的、可靠的数据传输服务,数据传输的基本单位是报文段(segment);
    • 用户数据报协议 (User Datagram Protocol,UDP):提供无连接的、尽最大努力的数据传输服务,但不保证数据传输的可靠性,数据传输的基本单位是用户数据报。
  3. 网络层 (internet layer):有时也译为网际层,它负责为两台主机提供通信服务,并通过选择合适的路由将数据传递到目标主机。
  4. 数据链路层 (data link layer):负责将网络层交下来的 IP 数据报封装成帧,并在链路的两个相邻节点间传送帧,每一帧都包含数据和必要的控制信息(如同步信息、地址信息、差错控制等)。
  5. 物理层 (physical Layer):确保数据可以在各种物理媒介上进行传输,为数据的传输提供可靠的环境。

二、物理层

物理层考虑的是如何在各种媒介上传输数据,它定义了与传输媒介相关的接口特性,如:

  • 机械特性:指明接口所用的接线器的形状和尺寸、引线数目和排列、固定和锁定装置等。
  • 电气特性:指明在接口电缆的各条线上出现的电压的范围。
  • 功能特性:指明某条线上出现的某一电平的电压的意义。
  • 规程特性:指明对于不同功能的各种可能事件的出现顺序。

2.1 传输媒介

物理层并不指具体的传输媒介,相反物理层希望能够尽量屏蔽不同媒介间的差异。这些传输媒介可以分为以下两类:

  • 导引型传输媒介:信号被导引沿着固体媒介进行传播,如双绞线、同轴电缆、光缆。
  • 非导引型传输媒介:信号在自由空间内进行传播,如短波通信、微波通信。

2.2 信道分类

信道是指信息传输的基本通道,它可以分为以下三类:

  • 单工信道:只能有一个方向的通信而没有反方向的通信;
  • 半双工信道:通信的双方都能发送信息,但双方不能同时发送或接收信息。
  • 全双工信道:通信的双方可以同时发送和接收信息。

2.3 信道复用

信道复用是信息传输当中最常使用的技术,用于提高信息传输的效率,根据采用技术的不同,可以分为以下几类:

1. 频分复用

频分复用(FDM,Frequency Division Multiplexing)是将用于传输信道的总带宽划分成若干个子频带(或称子信道),每个子信道传输一路信号:

2. 时分复用

时分复用(TDM,Time Division Multiplexing) 是指采用同一物理连接的不同时段来传输不同的信号:

如上图所示,在一个时分复用帧中,不同用户的信号周期性出现,如果某个用户处于闲置状态,则其对应的帧上也会出现空闲:

为了解决时分复用的这个缺点就产生了统计时分复用。

3. 统计时分复用

在统计时分复用(Statistic TDM)模式下,各用户将数据发送到集中器的输入缓存中,然后由集中器进行顺序扫描并放入到 STDM 帧中:

4. 波分复用

波分复用(WDM,Wavelength Division Multiplexing)是将两种或多种不同波长的光载波信号在发送端经复用器汇合在一起,并耦合到光线路的同一根光纤中进行传输;在接收端,经分用器将各种波长的光载波分离,然后由光解调器作进一步处理以恢复原信号:

5.码分复用

码分复用(CDM,Code Division Multiplexing)是靠不同的编码来区分各路原始信号的一种复用方式。

三、数据链路层

3.1 基本功能

1. 封装成帧

数据链路层会将网络层传递下来的数据拆分为多段,并在每段数据前后分别添加首部和尾部,以构成一个完成的帧,帧是链路层传输的基本数据单元。帧首部用控制字符 SOH 表示,帧尾部用控制字符 EOT 表示:

2. 透明传输

透明传输是指不论何种数据都应当能够在链路上进行安全地传输。由于我们采用控制字符来封装帧,当传输数据中出现了控制字符时,就会导致无法正确区分出帧头帧尾,此时需要使用转移字符 ESC 来进行转义:

3. 差错检测

由于现实环境中的通信链路都是不理想的,因此比特在传输过程中可能会产生差错:1 可能会变成 0,而 0 也可能变成 1,这称为比特差错。在一段时间内,传输错误的比特占所传输比特总数的比率称为误码率。为了解决这个问题,数据链路层将待发送的数据分为多组,并采用循环冗余校验(CRC,Cyclic Redundancy Check)技术为每组数据生成冗余校验码,之后将每组数据和其校验码共同构成一帧后再发送出去。

3.2 PPP 协议

点到点协议(PPP,Point to Point Protocol)是目前使用最为广泛的数据链路层协议,主要用于建立点对点的连接来传输数据单元。它由以下三部分组成:

  • 一个将 IP 数据报封装到串行链路的方法;
  • 链路控制协议 (LCP) :一种扩展链路控制协议,用于建立、配置、测试和管理数据链路连接。
  • 网络控制协议 (NCP) :协商该链路上所传输的数据包格式与类型,建立、配置不同的网络层协议。

3.3 Mac 地址

MAC 地址(Media Access Control Address),直译为媒体存取控制地址,也称为局域网地址(LAN Address)或物理地址(Physical Address)。MAC 地址用于在网络中唯一标识一个网卡,一台设备若有多个网卡,则每个网卡都会有一个唯一的 MAC 地址。链路层通过 Mac 地址来识别需要发送数据的目标节点。

MAC地址为 48 位的(6 个字节),通常表示为 12 个 16 进制数,每两个 16 进制数之间用冒号隔开,如 08:00:20:0A:8C:6D,前 3 字节为组织机构唯一标识(OUI,Organizationally Unique Identifier),由 IEEE 的注册管理机构统一分配给硬件生产厂家,以确保在全球范围内的唯一;后 3 字节由厂家自行分配。

3.4 局域网

局域网(LAN,Local Area Network)是连接住宅、学校、实验室、大学校园或办公大楼等有限区域内计算机的网络。 按照 IEEE802 标准,局域网体系结构分为三层,即物理层,媒体链路控制层(MAC),逻辑链路控制层(LLC)。实际上是两层,该标准将数据链路层拆分为更具体的媒体链路控制层和逻辑链路控制层。

3.5 以太网

以太网(Ethernet)是目前使用范围最广的局域网,以常用的以太网 v2 标准为例,其帧格式如下:

其中 Mac Header 分别记录了目的地的 Mac 地址和来源地的 Mac 地址。

四、网络层

4.1 网际协议 IP

网际协议(Internet Protocol)是网络层中最重要的协议,也是 TCP\IP 两大核心协议之一,所有需要互联的计算机网络都需要遵循该协议,以便能够将不同网络在全世界范围内连接起来。该层传输的基本数据单元是 IP 数据报,其格式如下:

各字段的含义如下:

  • 版本:占 4 位,指 IP 协议的版本(IPv4 或 IPv6)。
  • 首部长度:占 4 位,可表示的最大十进制数是 15 。
  • 区分服务:只有在使用区分服务时,该字段才有用,一般情况下不会用到。
  • 总长度:指首部长度和数据长度之和,单位为字节。该字段为 16 位,因此数据报最大长度为 65535 个字节,由于数据链路层规定了一个帧中数据字段的最大长度 MTU(Maximum Transfer Unit,最大传送单元),以以太网为例,该值为 1500,所以当数据报长度超过 MTU 时,需要对数据进行分片。
  • 标识:占 16 位,由 IP 软件内部的计数器维护,每产生一个数据报,计数器就加 1,用于发生分片时,将相同数据报标识的分片重组为原数据报。
  • 标志:占 3 位,目前只有两位有意义:
    • 最低位 MF(More Fragment):为 1 时表示后面还有分片,为 0 时表示该数据报分片已经是最后一个;
    • 中间位 DF(Don’t Fragment):代表不能分片,只有将其设为 1 时,才允许分片。
  • 片偏移:占 13 位,标识该片在原数据报中的偏移位置。
  • 生存时间:TTL,每经过一个路由器,其值就会减 1,当值为 0 时,就将该数据报丢弃。这样做是为了避免数据报目的地址不存在时,数据报一直在网络中无限制转发。
  • 协议:占 8 位,指明数据报携带的数据所使用的协议。
  • 首部校验和:占 16 位,其只校验数据报的首部,不包括数据部分。
  • 源地址:占 32 位,数据来源的 IP 地址;
  • 目的地址:占 32 位,目的地的 IP 地址。

4.2 ARP 协议

IP 数据报中的源地址和目标地址均是 IP 地址,而数据链路层的帧中的源地址和目标地址均是 Mac 地址,那么怎样根据 IP 地址获得 Mac 地址?这就需要使用到 ARP 协议。互联网络中的每台主机都有一个 ARP 缓存表,存储了本局域网内各主机和路由器的 IP 地址与 Mac 地址的映射关系,示例如下:

主机名称

IP地址

MAC地址

A

192.168.38.10

00-AA-00-62-D2-02

B

192.168.38.11

00-BB-00-62-C2-02

C

192.168.38.12

00-CC-00-62-C2-02

D

192.168.38.13

00-DD-00-62-C2-02

E

192.168.38.14

00-EE-00-62-C2-02

你也可以使用 arp -a 来查看你本机的 ARP 缓存表 。

拥有 ARP 表后,数据链路层中帧的发送过程如下:

  • 主机 A 发送数据前, 会先查看自己的 ARP 表中是否有目标 IP 对应的 Mac 地址,如果有则将其封装到帧里,然后发送;
  • 如果没有找到,主机 A 则会以广播的方式向同一网段内的所有主机发出对该 IP 地址的询问;
  • 对应 IP 地址的主机接收到这个消息后以单播的方式将对应的 Mac 地址回复给主机 A 。

4.3 IP 地址分类

IP 地址由 ICANN(The Internet Corporation for Assigned Names and Numbers,互联网名称与数字地址分配机构)进行分配,它是一个在全世界范围内唯一的 32 位标识符,最早的 IP 地址采用两级分类,只由 网络号 + 主机号 组成,分为以下五类:

A,B,C 三类是最常使用的类型,其类别位分别为 0,10,110 。需要注意的是另外并非所有 IP 地址都可用来分配,限制如下:

网络号限制

  • 网络号全为 0 的 IP 地址是保留地址,代表 “本网络”(B,C 两类地址的网络号开头都是 1,所以不存在全 0 的情况);
  • 网络号为 127(即 01111111)也是保留地址,作为回环测试使用(同上,B 和 C 两类地址也不存在该情况);
  • B 类地址 128.0.0.0 (网络号为 10000000 00000000)不能用于分配;
  • C 类地址 192.0.0.0 (网络号为 11000000 00000000)不能用于分配;

主机号限制

  • 全 0 主机号表示该 IP 地址是本主机所连接到的单个网络地址,如 IP 地址为 5.6.7.8 的主机所在的网络地址就是 5.0.0.0,该地址不能用于分配;
  • 全 1 主机号表示该网络上的所有主机,因此也不能被分配。

综上所述,每种网络类型所能分配到 IP 地址的情况如下:

网络类别

最大可分配的网络数

第一个可分配的网络号

最后一个可分配的网络号

每个网络的最大主机数

A

126(27-2)

1

126

16 777 215(224-2)

B

16 383(214-1)

128.1

191.255

65 534(216-2)

C

2 097 151(221-1)

192.0.1

223.255.255

254(28-2)

从该表我们可以看出来,两级 IP 地址灵活性不足,且利用率较低,假设你现在的公司有 4 个机房(每个机房 20 台主机),出于信息安全的考虑,每个机房的网络需要彼此隔离,在两级 IP 的架构下你就只能申请 4 个 C 类地址,此时你浪费的 IP 数量为 (254-20)*4 ,为解决两级 IP 地址灵活性不足问题,就产生了三级 IP 地址,即划分子网。此时你只需要申请一个 C 类地址,然后将其划分为 4 个子网。

4.4 划分子网

划分子网方案诞生与 1985 年,它从主机号借用若干位作为子网号,从而将 IP 地址划分为三级:网络号 + 子网号 + 主机号。假设网络地址为 192.168.10.0,利用子网掩码 255.255.255.224 对其进行划分子网,此时可以划分为四个子网:

由于子网对外是不可见的,所以需要使用子网掩码来辅助路由,假设目标 IP 地址为 192.168.10.198,想要正确到达该地址,必须先正确到达网络地址 192.168.10.192 。网络地址,子网掩码和主机 IP 之间的关系如下:

IP 地址:192.168.10.198             二进制IP地址:11000000.10101000.00001010.11000110
子网掩码:255.255.255.224           二进制掩码:11111111.11111111.11111111.11100000
网络地址:192.168.10.192            按位逻辑与运算结果为:11000000.10101000.00001010.11000000

现代互联网标准规定:所有网络都必须使用子网掩码,同时路由器的路由表中也必须包含子网掩码这一项。因为路由表包含了 IP 地址和子网掩码,所以通过位运算就能很快计算出网络地址。

最后,如果一个网络不划分子网掩码,则其子网掩码取默认值,各类 IP 地址默认的掩码如下:

类别

子网掩码的二进制数值

子网掩码的十进制数值

A

11111111 00000000 00000000 00000000

255.0.0.0

B

11111111 11111111 00000000 00000000

255.255.0.0

C

11111111 11111111 11111111 00000000

255.255.255.0

4.5 构成超网

无类别域间路由(CIDR,Classless Inter-Domain Routing)是一个给用户分配 IP 地址以及在互联网上有效地路由 IP 数据报的地址归类方法。它消除了传统的 A 类,B 类 和 C 类地址以及划分子网的概念,采用无分类的两级编址:

IP地址 ::= {<网络前缀>,<主机号>}

并使用斜线记法进行表示:

128.14.35.7 / 20 = 10000000 00001110 00100011 00000111

此时表示前 20 位都是网络前缀,该地址所处的地址块中的最小地址和最大地址则分别为:

十进制

二进制

最小地址

128.14.32.0

10000000 00001110 00100000 00000000

最大地址

128.14.47.255

10000000 00001110 00101111 11111111

每个地址块可以使用地址块中的最小地址和网络前缀的位数进行指定,例如上面的地址块可以记为 128.14.32.0 / 20 ,也可以简称为 /20地址块 。为更方便的进行路由选择,CIDR 使用 32 位的地址掩码,斜线后面的数字同时表示地址掩码中 1 的个数,例如 /20地址块 的地址掩码为 11111111 11111111 11110000 00000000 。

由于一个 CIDR 地址块可以包含多个地址,所以路由表就利用 CIDR 地址块来查找目标网络,这种地址聚合常称为路由聚合,也称为构成超网。通过路由聚合,可以极大减少路由表中项目的数量,从而提高网络的整体性能。

4.6 ICMP 和 IGMP

在网络层,除了上面介绍的 IP 协议和 ARP 协议外,最常使用的还有以下两个协议:

  • 互联网控制消息协议 (ICMP,Internet Control Message Protocol):为了提高 IP 数据报的交付率,ICMP 允许主机或路由器报告差错情况和提供异常报告给发送者,以便发送者进行补偿行为。
  • 网路群组管理协议 (IGMP,Internet Group Management Protocol) :是用于管理网路协议多播组成员的一种通信协议。IP 主机和相邻的路由器可以利用 IGMP 来建立多播组的组成员。

4.7 专用地址

RFC 1918 中指明了一些专用地址(Private Address),这些地址只能用于一个机构的内部通信,但不能用于和互联网上的主机进行通信。在互联网中的所有路由器,对目的地址是专用地址的数据报一律不进行转发。下面是三个专用的地址块:

  • 10.0.0.0 – 10.255.255.255(或记为 10.0.0.0/8 ,又称为 24 位块);
  • 172.16.0.0 – 172.31.255.255(或记为 172.16.0.0/12 ,又称为 20 位块);
  • 192.168.0.0 – 192.168.255.255(或记为 192.168.0.0/16 ,又称为 16 位块)。

因为不同机构可以采用相同的专用地址,因此其也被称为可重用地址。

4.8 VPN

如果一个机构内使用的是由专用地址构成的专用网,但该机构的部门却分布在不同的、远距离的地理位置上,此时可以利用公共的互联网作为本机构内各专用网之间的通信载体,这样的专用网称为虚拟专用网(Virtual Private Network)。此时通过公共互联网的数据可以使用 IPSec(IP Security)协议加密来保证安全性。

4.8 NAT

当某台主机获取到的地址是专用地址时,其是无法和外部互联网进行通讯的,如果想要和外部互联网进行通讯,可以采用 NAT(Network Address Translation,网络地址转换)技术来实现。该方法需要在专用网连接到互联网的路由器上安装 NAT 软件,NAT 路由器需要至少一个有效的全球 IP 地址,当使用专用地址的主机在和外界进行通信时,NAT 路由器会将其转换为全球 IP 地址。

由上面的原理也可以看出,具有 n 个全球 IP 地址的路由器最多只允许 n 台主机同时接入到互联网。 为了解决这个问题,现在常用的 NAT 转换表会把传输层的端口号也利用上。

4.9 IPv6

上面我们介绍过 IPv4 的长度为 32 位,因此所有可分配的 IP 地址大约为 42 亿个,到 2011 年 2 月,所有可分配地址均已耗尽,因此产生了 IPv6,IPv6 的地址长度为 128 位,采用十六进制表示。

五、传输层

传输层负责为两台主机中的进程提供通信服务,它使用 16 位的端口号来标识端口,当两个计算机中的进程要进行通讯时,除了要知道对方的 IP 地址外,还需要知道对方的端口。该层主要有以下两个协议:用户数据报协议(UDP,User Datagram Protocol)和传输控制协议(TCP,Transmission Control Protocol):

5.1 UDP

用户数据报协议 UDP 具有以下特点:

  • UDP 是无连接的;
  • UDP 提供尽最大努力的交付服务,但不保证交付的可靠性;
  • UDP 是面向报文的;
  • UDP 没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低;
  • UDP 支持一对一、一对多、多对一和多对多的交互通信;
  • UDP 的首部开销较小,只有 8 个字节,远小于 TCP 的 20 个字节。首部共由四个字段组成,每个字段两个字节:
    • 源端口号:在需要对方回信时选用,不需要时可用全 0 表示;
    • 目标端口号;
    • 长度:UDP 用户数报的总长度;
    • 校验和:检测 UDP 用户数据报在传输中是否有错,如果有错则丢弃。

5.2 TCP 简介

传输控制协议 TCP 具有以下特点:

  • TCP 是面向连接的;
  • TCP 提供可靠的交付服务;
  • TCP 提供全双工的通信,两端都设有缓存,用来临时存放通信数据;
  • 面向字节流,这里的流指的是流入或流出进程的字节序列;
  • 每一条 TCP 连接唯一地被通信两端的两个端点所确定,即:
TCP 连接 ::= {socket1,socket2} = {(IP1,port1),(IP2,port2)}

5.3 TCP 报文首部

TCP 虽然是面向字节流的,但其传输的基本数据单元则是报文段。一个 TCP 报文段分为首部和数据两部分,TCP 首部的前 20 个字节是固定的,后面有 4n 字节是根据需要而增加的选项(n 为整数),具体格式如下:

各字段的含义如下:

  1. 源端口和目的端口:各占 2 个字节。
  2. 序号:占 4 字节,序号范围为 \[ 0 , 232 \- 1 \],序号增加到 232 - 1 后又会回到 0 。在一个 TCP 连接中,传送的字节流中的每一个字节都要按顺序进行编号。
  3. 确认号:占 4 字节,表示期望收到对方下一个报文段的第一个数据字节的序号。例如 B 收到 A 的报文,序号值为 501 ,数据长度为 200 字节(序号 501 ~ 700),此时表明 B 正确收到了序号 700 及其之前的所有数据,因此 B 在发送给 A 的确认报文段中确认号的值为 701。
  4. 数据偏移:占 4 位,其所能表达的最大数字是 15 。数据偏移表示该数据报中数据的起始位置,由于数据报是由 首部+数据 组成,所以实际上就是指报文段的首部长度。数据偏移的单位是 32 位字(即以 4 字节长为单位),所以数据偏移的最大长度是 60 (15*4)字节,即 TCP 报文段的首部长度不能超过 60 字节,对应的选项长度不能超过 40 字节。
  5. 保留:占 6 位,保留为今后使用,目前应置为 0 。
  6. 六个控制位:其作用分别如下:
    • 紧急 URG (URGent):当值为 1 时,表明紧急指针字段有效,代表此报文中有紧急数据,应尽快传送,而无需按原来的排队顺序传送。
    • 确认 ACK (ACKnowledgment):当值为 1 时,确认号有效;值为 0 时,确认号无效。TCP 规定,在连接建立后所有传送的报文段都必须把 ACK 置为 1。
    • 推送 PSH (Push):当值为 1 时,表示接受方应该将数据立即交付给应用进程,而不是等待缓存填满后再向上交付。
    • 复位 RST (Reset):当值为 1 时,表明 TCP 连接出现严重差错,必须立即释放,然后再重新建立连接;也可以用来拒绝一个非法的报文段或拒绝打开一个连接。
    • 同步 SYN (SYNchronization):在连接建立时用来同步序号。当 SYN = 1 而 ACK = 0 时,表明这是一个连接请求报文段;对方若同意建立连接,则应在响应的报文段中使 SYN = 1 和 ACK = 1 。
    • 终止 FIN (FINis):当值为 1 时,表明此报文段发送方的数据已发送完毕,并要求释放连接。
  7. 窗口:占 2 字节,取值范围为 \[ 0 , 216 \- 1 \]之间的整数。窗口字段保持动态变化,用于指明接收方允许发送方发送的数据量。
  8. 校验和:占 2 字节,校验的字段范围包括首部和数据。
  9. 紧急指针:占 2 字节,仅在 URG = 1 时才有意义,用于指明紧急数据的结束位置,位于结束位置之后的就是普通数据。
  10. 选项:长度可变,最长可达 40 字节。可用的选项有:最大报文段长度 ,窗口扩大选项、时间戳选项等。

5.4 三次握手

TCP 建立连接的过程叫做握手,握手需要在客户和服务器之间交换三个 TCP 报文段,具体如下:

  1. 服务器进程 B 首先创建传输控制模块 TCB,然后进入 LISTEN(收听)状态,准备接受客户端的连接请求;
  2. 客户端进程 A 首先创建传输控制模块 TCB,然后发出连接请求报文段,此时同步位 SYN = 1 ,同时选择一个初始序号 seq = x ,之后进入 SYN-SENT(同步已发送)状态;
  3. B 收到连接请求报文段后,如果同意建立连接,则发送确认报文段,此时 SYN 和 ACK 都置为 1,确认号 ack = x + 1 ,并为自己选择一个初始序号 seq =y ,之后进入 SYN-RCVD(同步收到)状态;
  4. A 收到来自 B 的确认后,发出最后的确认,确认报文段的 ACK 为 1,确认号 ack = y + 1,序号 seq = x + 1。TCP 标准规定,ACK 报文段可以携带数据也可以不携带,如果不携带则该序号不被消耗,下一个数据报文段的序号仍然是 seq = x + 1。之后 A 进入 ESTABLISHED(已连接)状态;
  5. 当 B 收到 A 的确认后,也进入 ESTABLISHED 状态。

5.5 四次挥手

数据传输结束后,通信的双方都可以释放连接,具体过程如下:

  1. 假设应用进程 A 先主动关闭连接,此时需要发送连接释放报文段:首部终止控制位 FIN 为 1,序号 seq = u,其中 u 等于前面传送过的数据的最后一个字节的序号加 1 。之后 A 进入 FIN-WAIT-1(终止等待 1)状态;
  2. 应用进程 B 收到连接释放报文段后立即发出确认,确认号 ack = u + 1,序号 seq = v ,其中 v 等于前面传送过的数据的最后一个字节的序号加 1 。之后 B 进入 CLOSE-WAIT(关闭等待)状态,并通知高层应用进程。此时 TCP 连接处于半关闭状态,即 A 已经没有数据需要发送,但如果 B 发送数据,A 仍要接收;
  3. A 收到来自 B 的确认后就进入 FIN-WAIT-2(终止等待 2)状态,等待 B 发出连接释放报文段;
  4. 若高层应用进程已经没有数据要发送,则通知 B 释放 TCP 连接。此时 B 发出释放连接报文段:首部终止控制位 FIN 为 1,序号 seq = w(在半关闭状态下 B 可能又发送了一些数据),另外还需要重复上次已经发送过的确认号 ack = u + 1。之后 B 进入 LAST-ACK(最后确认)状态;
  5. A 收到 B 的连接释放报文段后,发出最后确认:ACK 为 1,确认号 ack = w + 1,序号 seq = u + 1,然后进入 TIME-WAIT(有时间限制的等待)状态;
  6. B 收到来自 A 的最后确认后进入 CLOSED(关闭)状态;
  7. A 经过 2 倍的 MSL(Maximum Segment Lifetime,最长报文段寿命)后,才进入 CLOSED 状态。

RFC 793 建议 MSL 设置为 2 分钟,现在的网络环境已经有了质的提升,该值可以按需缩短。A 之所以要等待两倍的 MSL 时间后才进入 CLOSED 状态,主要基于以下两个原因:

  • 为了保证 A 发送的最后一个 ACK 报文段能够到达 B。如果 B 没有收到该最后确认,则会进行超时重发 FIN+ACK 报文段,A 在 2MSL 等待时间内会响应该报文段并重发最后确认;
  • 确保本次连接内产生的所有报文段都从网络消失,进而确保下一个新的连接中不会出现旧的连接请求报文段。

5.6 可靠传输的原理

1. 停止等待协议

想要实现可靠性传输,最基本的可以使用停止等待协议:每发送完一个数据单元就停止发送,并等待对方的确认。

此时面临两个问题:

  • 如果 A 给 B 发送数据的过程中出现了丢失,此时 B 无法收到数据,自然也不会返回确认,那么程序就会一直等待;
  • 如果 B 给 A 发送确认的过程中出现了丢失或经过很长时间才到达 A,那么程序也会持续等待。

针对第一个问题,解决方案是如果在给定的时间内没有收到确认,则进行超时重传:

针对第二个问题,其解决方案依然是超时重传,具体细分为以下两种情况:

  • 如果 B 收到了 M1,只是返回的确认丢失了,当超时重传后,B 需要丢弃重复收到的 M1;
  • 如果 B 的返回确认没有丢失,只是超过了重传时间后才到达 A,此时 A 可能会收到两次确认,一次是补传得到确认,一次是原有的延迟到达的确认,A 需要丢弃延时到达的确认,不做任何处理:

在基本的停止等待协议中,一次只发送一个数据单元,此时信道利用率非常低,为了解决这个问题,可以采用流水线传输,一次发送多个数据单元:

当使用流水线传输时,为保证可靠性,需要配合使用连续 ARQ 协议和滑动窗口协议。

2. 连续 ARQ 协议

连续ARQ(Automatic Repeat reQuest)协议指发送方维持着一个一定大小的发送窗口,位于发送窗口内的所有分组都可连续发送出去,中途不需要等待对方的确认,发送方在每收到一个确认时就把发送窗口向前滑动一个分组的位置:

通常接收方一般都是采用累积确认的方式。此时接收方不必对收到的分组逐个发送确认,而是在收到几个分组后,对按序到达的最后一个分组发送确认,它表示:这个分组及其之前的所有分组都已正确到达。

5.7 TCP 的可靠传输

TCP 的滑动窗口以字节为单位,并采用以下方法来计算超时重传时间 RTO(Retransmission Time Out):

RTO = RTT_S + 4 × RTT_D

其中 RTTS 表示加权平均往返时间,计算方式如下:

新的 RTT_S = (1-α) × 旧的 RTT_S +  α × 新的 RTT 值
  • RTT (Round Trip Time)代表报文段的往返时间,它记录一个报文段从发出去到收到确认的时间长度;
  • 第一次测量时, RTTS 的值就等于 RTT 的值,之后的 RTTS 则采用上面的公式进行计算;
  • 其中 0 ≤ α<1 ,RFC 6298 推荐其值取 0.125 。

RTTD 是 RTT 偏差的加权平均值,计算方式如下:

新的 RTT_D = (1-β) × 旧的 RTT_D +  β × |RTT_S - 新的 RTT 值|
  • 第一次测量时,RTTD 的值就等于 RTT 值的一半,之后的 RTTD 则采用上面的公式进行计算;
  • β 值是一个小于 1 的系数,RFC 6298 推荐其值取 0.25 。

5.8 流量控制

流量控制(flow control)是指控制发送方的发送速率,以便接收方来得及接收。假设 A 向 B 发送数据,在连接建立时,B 会将自己接收窗口(rwnd,receiver window)的大小告诉 A ,而 A 需要保证发送窗口的大小不能超过 B 接收窗口的大小,通过该机制就可以实现对发送方的流量控制。

5.9 拥塞控制

网络拥塞(congestion)是指传输的数据量超过节点承受能力而导致传输能力下降的情况。而拥塞控制就是防止过多的数据注入到网络中而造成路由器和链路过载。TCP 采用四种算法来进行拥塞控制,分别是:慢启动(slow start)、拥塞避免(congestion avoidance)、快重传(fast retransmit)和快恢复(fast recovery):

1. 慢启动

慢开始和拥塞避免都是基于窗口的拥塞控制:发送方会维持一个名为拥塞窗口 cwnd(congestion window)的状态变量,其值取决于网络的拥塞程度,并会动态变化,同时发送方会让自己的发送窗口等于拥塞窗口。

慢启动的思路如下:由于不知道网络的负载能力,所以最好的选择就是逐步探测,即由小到大成倍地增大发送窗口,也就是说,由小到大成倍地增大拥塞窗口的值。

2. 拥塞避免

拥塞避免算法的思路是让拥塞窗口 cwnd 缓慢地增大:每经过一个往返时间 RTT 就把发送方的拥塞窗口 cwnd 加 1,而不是像慢启动阶段那样加倍地增长。慢启动和拥塞避免通常是配合使用,以保证启动速度,一开始使用慢启动进行成倍增长,当达到某一个阈值 ssthresh 后采用拥塞避免进行稳步尝试:

3. 快重传和快恢复

快重传算法要求接收方不要等待自己发送数据时才进捎带确认,而是要立即发送确认,即使收到了失序报文段也要立即发出对已收到的报文段的重复确认。示例如下:

如上图所示,当 M3 丢失时,之后发送 M4 , M5 , M6 时收到的都是对于 M2 的重复确认,此时发送方就可以知道 M3 已经丢失,需要立即进行重传。由于此时只是个别报文出现了丢失,而不是网络拥塞,所以执行快恢复:发送方调整 ssthresh = cwnd / 2,并设置 cwnd = ssthresh = 8 (图中点5),并开始执行拥塞避免算法。

六、应用层

6.1 域名系统 DNS

目前我们都是使用易于理解的域名来访问互联网应用,但传输层需要的则是 IP 地址,因此需要使用域名系统(DNS,Domain Name System)来进行域名与 IP 地址之间的转换 。

域名是一个逻辑上的概念,分为多级域名,其中最基础的是根域名,其次是顶级域名,顶级域名共分为四类:

  • 国家顶级域名 nTLD:如 cn 表示中国,us 表示美国;
  • 通用顶级域名 gTLD:如 com 表示公司企业,org 表示非盈利性组织,net 表示网络服务机构;
  • 基础结构域名:又称为反向域名,用于反向域名解析,该顶级域名只有一个 arpa;
  • 新顶级域名 New gTLD:ICANN 机构在 2011 年 6 月 20 日批准新顶级域名,允许任何满足条件的公司或机构进行申请。

6.2 文件传输协议 FTP

文件传输协议(FTP,File Transfer Protocol)是用于在网络上进行文件传输的一套标准协议,允许客户指明文件的类型和格式,并获得文件的存储权限。FTP 的服务器进程由两大部分组成:

  • 一个主进程:负责接收新的请求;
  • 若干个从属进程:负责处理单个请求。

因此一个 FTP 服务器进程可以同时为多个客户端进程提供服务。

6.3 远程终端协议 TELNET

Telnet 协议是 Internet 远程登录服务的标准协议和主要方式,它为用户提供了在本地计算机上访问远程主机的能力。Telnet 能将用户的击键传到远程主机,同时也能将远程主机的输出通过 TCP 连接返回到用户屏幕,这种服务是透明的,用户感觉键盘和显示器好像都是直接连在远程主机上,因此 Telnet 又称为终端仿真协议。

6.4 万维网 WWW

万维网是一个分布式的超媒体系统,它是超文本系统的扩展。它包含以下重要概念:

1. 统一资源定位符 URL

用于定位互联网上资源的位置和访问这些资源的方法,其格式如下:

<协议>://<主机>:<端口>/<路径>

2. 超文本传送协议 HTTP

HTTP 协议定义了浏览器如何向万维网请求文档,以及服务器如何把文档传送给浏览器。

3. 超文本标记语言 HTML

超文本标记语言 HTML 是一种标识性的语言,包括一系列标签,这些标签可以用于说明文字、图形、动画、声音、表格、链接等各种类型的资源,并能将网络文档格式进行统一。

6.5 动态主机配置协议 DHCP

通常连接到互联网的计算机的协议软件都需要配置多个项目,如 IP 地址,子网掩码,默认路由器的 IP 地址以及域名服务器的 IP 地址等等,为了省去配置的麻烦,现在互联网普遍采用动态主机配置协议 DHCP(Dynamic Host Configuration Protocol),它提供了一种即插即用联网的机制。此时你只需要采用默认的配置即可,如下所示:

此时需要进行联网的主机在启动时候会广播发现报文(DHCP DISCOVER),其目的地址为 255.255.255.255(即受限广播地址),此时本地网络上的所有主机都能接收到这个广播报文,但只有 DHCP 服务器才会通过提供报文(DHCP OFFER)对此广播进行响应。DHCP 服务器先在其数据库中查找该计算机的配置信息,若找到,则直接返回;若找不到,则从服务器的 IP 地址池取一个地址分配给该计算机。

通常不是每个网络都有 DHCP 服务器,但每个网络都至少有一个 DHCP 中继代理(通常是路由器),它配置了 DHCP 服务器的 IP 地址信息。当 DHCP 中继代理收到主机 A 的发现报文后,就以单播的方式向 DHCP 服务器进行转发;并等待其回复后,再转发回主机 A 。

DHCP 服务器分配给 DHCP 客户的 IP 地址是临时性的,只能在一段时间内使用,该时间称为租用期,由 DHCP 服务器进行设置。

5. 说说DOS及DDOS的原理及防御方式

难度:3 · 类型:QA

题目要点

DOS(Denial of Service)和DDOS(Distributed Denial of Service)是一种网络攻击方式,其主要原理是通过向目标系统发送大量的请求或数据流量,使目标系统无法正常服务或响应。DOS攻击通常由单个计算机或机器人网络发起,而DDOS攻击则是由多个不同来源的计算机或机器人网络同时攻击,更加难以防御和发现。

参考答案

DOS(Denial of Service)和DDOS(Distributed Denial of Service)是一种网络攻击方式,其主要原理是通过向目标系统发送大量的请求或数据流量,使目标系统无法正常服务或响应。DOS攻击通常由单个计算机或机器人网络发起,而DDOS攻击则是由多个不同来源的计算机或机器人网络同时攻击,更加难以防御和发现。

DOS 和 DDOS 的防御方式主要包括以下几种:

  1. 流量过滤:使用防火墙、反垃圾邮件服务器等设备来监测并过滤网络流量,识别并限制恶意流量。

  2. 负载均衡:使用负载均衡设备在多台服务器之间分配流量,避免某一台服务器承受过大压力,从而增强系统的稳定性和容错能力。

  3. 加强认证和授权:加强身份验证和访问控制,防止未经授权的用户或程序访问系统资源。

  4. 升级硬件和软件:及时升级和更新系统软件,安装最新的安全补丁,以及增强硬件配置,提高系统的性能和安全性。

  5. 限制带宽:通过限制网络带宽来限制攻击者的流量,减轻系统负担。这种方式需要根据具体情况和业务需求来进行调整,以避免影响正常服务。

DOS 和 DDOS 攻击是一种比较常见的网络安全问题,其防御需要综合运用多种技术手段和策略,包括流量过滤、负载均衡、加强认证和授权、升级硬件和软件等,并且需要及时调整和更新。

6. app中常提到的webview是什么?

难度:2 · 类型:QA

题目要点

webview 用来展示网页的 view 组件,该组件是你运行自己的浏览器或者在你的线程中展示线上内容的基础。使用 webkit 渲染引擎来展示,并且支持前进后退等基于浏览历史,放大缩小,等更多功能。

参考答案

webview 用来展示网页的 view 组件,该组件是你运行自己的浏览器或者在你的线程中展示线上内容的基础。使用 webkit 渲染引擎来展示,并且支持前进后退等基于浏览历史,放大缩小,等更多功能。

简单来说 WebView 是手机中内置了一款高性能 webkit 内核浏览器,在 SDK 中封装的一个组件。不过没有提供地址栏和导航栏,只是单纯的展示一个网页界面。

webview 可以简单理解为页面里的 iframe 。原生app与 webview 的交互可以简单看作是页面与页面内 iframe 页面进行的交互。就如页面与页面内的 iframe 共用一个 window 一样,原生与 webview 也共用了一套原生的方法。

7. 原码、反码和补码分别是什么?

难度:1 · 类型:QA

题目要点

原码是计算机中对数字的二进制的定点表示方法,最高位表示符号位,其余位表示数值位。优点是易于分辨,缺点是不能够直接参与运算。

参考答案

原码是计算机中对数字的二进制的定点表示方法,最高位表示符号位,其余位表示数值位。优点是易于分辨,缺点是不能够直接参与运算。

正数的反码和其原码一样;负数的反码,符号位为1,数值部分按原码取反。

如 [+7]原 = 00000111,[+7]反 = 00000111; [-7]原 = 10000111,[-7]反 = 11111000。

正数的补码和其原码一样;负数的补码为其反码加1。

例如 [+7]原 = 00000111,[+7]反 = 00000111,[+7]补 = 00000111;

[-7]原 = 10000111,[-7]反 = 11111000,[-7]补 = 11111001

之所以在计算机中使用补码来表示负数的原因是,这样可以将加法运算扩展到所有的数值计算上,因此在数字电路中我们只需要考虑加法器的设计就行了,而不用再为减法设置新的数字电路。

8. Unicode 和 UTF-8 之间有什么关系?

难度:1 · 类型:QA

题目要点

Unicode可以认为是字符的编号,即每个字符在Unicode表里面的序号,每个字符对应一个不同的 Unicode 编码,它只规定了符号的二进制代码,却没有规定这个二进制代码在计算机中如何编码传输。

参考答案

Unicode可以认为是字符的编号,即每个字符在Unicode表里面的序号,每个字符对应一个不同的 Unicode 编码,它只规定了符号的二进制代码,却没有规定这个二进制代码在计算机中如何编码传输。

utf8是一种编码方式,类似于哈夫曼编码过程,就是把常用(位置靠前)的Unicode字符用短编码表示,不常用的字符用长代码表示,从而实现更小的整个文档的文件大小。在 UTF-8 编码中,英文字母是一个字节,中文(非生僻字)是 2~3 个字节。

可以认为, utf8 是对 Unicode 的一种压缩算法。

9. 说说你对操作系统的理解?核心概念有哪些?

难度:2 · 类型:QA

题目要点

操作系统(Operating System,缩写:OS)是一组主管并控制计算机操作、运用和运行硬件、软件资源和提供公共服务来组织用户交互的相互关联的系统软件程序,同时也是计算机系统的内核与基石

参考答案

一、是什么

操作系统(Operating System,缩写:OS)是一组主管并控制计算机操作、运用和运行硬件、软件资源和提供公共服务来组织用户交互的相互关联的系统软件程序,同时也是计算机系统的内核与基石

简单来讲,操作系统就是一种复杂的软件,相当于软件管家

操作系统需要处理如管理与配置内存、决定系统资源供需的优先次序、控制输入与输出设备、操作网络与管理文件系统等基本事务,

操作系统的类型非常多样,不同机器安装的操作系统可从简单到复杂,可从移动电话的嵌入式系统到超级电脑的大型操作系统,在计算机与用户之间起接口的作用,如下图:

许多操作系统制造者对它涵盖范畴的定义也不尽一致,例如有些操作系统集成了图形用户界面,而有些仅使用命令行界面,将图形用户界面视为一种非必要的应用程序

二、核心概念

操作系统的核心概念都是对具体物理硬件的抽象,主要有如下:

  • 进程(线程):进程(线程)是操作系统对CPU的抽象

  • 虚拟内存(地址空间):虚拟内存是操作系统对物理内存的抽象

  • 文件:文件是操作系统对物理磁盘的抽象

  • shell:它是一个程序,可从键盘获取命令并将其提供给操作系统以执行。

  • GUI :是一种用户界面,允许用户通过图形图标和音频指示符与电子设备进行交互

  • 计算机架构(computer architecture): 在计算机工程中,计算机体系结构是描述计算机系统功能,组织和实现的一组规则和方法。它主要包括指令集、内存管理、I/O 和总线结构

  • 多处理系统(Computer multitasking):是指计算机同时运行多个程序的能力

  • 程序计数器(Program counter):程序计数器 是一个 CPU 中的寄存器,用于指示计算机在其程序序列中的位置

  • 多线程(multithreading):是指从软件或者硬件上实现多个线程并发执行的技术

  • CPU 核心(core):它是 CPU 的大脑,它接收指令,并执行计算或运算以满足这些指令。一个 CPU 可以有多个内核

  • 图形处理器(Graphics Processing Unit):又称显示核心、视觉处理器、显示芯片或绘图芯片

  • 缓存命中(cache hit):当应用程序或软件请求数据时,会首先发生缓存命中

  • RAM((Random Access Memory):随机存取存储器,也叫主存,是与 CPU 直接交换数据的内部存储器

  • ROM (Read Only Memory):只读存储器是一种半导体存储器,其特性是一旦存储数据就无法改变或删除

  • 虚拟地址(virtual memory): 虚拟内存是计算机系统内存管理的一种机制

  • 驱动程序(device driver):设备驱动程序,简称驱动程序(driver),是一个允许高级别电脑软件与硬件交互的程序

  • USB(Universal Serial Bus):是连接计算机系统与外部设备的一种串口总线标准,也是一种输入输出接口的技术规范

  • 地址空间(address space):地址空间是内存中可供程序或进程使用的有效地址范

  • 进程间通信(interprocess communication): 指至少两个进程或线程间传送数据或信号的一些技术或方法

  • 目录(directory): 在计算机或相关设备中,一个目录或文件夹就是一个装有数字文件系统的虚拟容器

  • 路径(path name): 路径是一种电脑文件或目录的名称的通用表现形式,它指向文件系统上的一个唯一位置。

  • 根目录(root directory):根目录指的就是计算机系统中的顶层目录,比如 Windows 中的 C 盘和 D 盘,Linux 中的 /

  • 工作目录(Working directory):它是一个计算机用语。用户在操作系统内所在的目录,用户可在此目录之下,用相对文件名访问文件。

  • 文件描述符(file descriptor): 文件描述符是计算机科学中的一个术语,是一个用于表述指向文件的引用的抽象化概念

  • 客户端(clients):客户端是访问服务器提供的服务的计算机硬件或软件。

  • 服务端(servers): 在计算中,服务器是为其他程序或设备提供功能的计算机程序或设备

三、总结

  • 操作系统是管理计算机硬件与软件资源的程序,是计算机的基石
  • 操作系统本质上是一个运行在计算机上的软件程序 ,用于管理计算机硬件和软件资源
  • 操作系统存在屏蔽了硬件层的复杂性。 操作系统就像是硬件使用的负责人,统筹着各种相关事项
  • 操作系统的内核(Kernel)是操作系统的核心部分,它负责系统的内存管理,硬件设备的管理,文件系统的管理以及应用程序的管理。 内核是连接应用程序和硬件的桥梁,决定着系统的性能和稳定性

10. 使用cookie、session维持登录状态的原理是什么?

难度:1 · 类型:QA

题目要点

  • Cookie 用于在客户端存储小型数据,如会话标识符。它允许浏览器在请求中自动发送这些数据,但由于存储在客户端,可能面临安全风险。
  • Session 将会话数据存储在服务器端,客户端只保存会话标识符。它提供更高的安全性,但需要服务器端的存储和管理。

通常,现代应用会结合使用 Cookie 和 Session。客户端通过 Cookie 传递会话标识符,服务器通过 Session 进行用户认证和数据存储。这样可以在保持高安全性的同时,简化用户体验。

参考答案

HTTP协议

要弄明白cookie和session,就得先了解一下HTTP协议。

HTTP是一种无状态的协议,请求响应后,断开了TCP连接,下一次连接与上一次无关。无状态就意味着每个请求之间的不会直接地相互影响,对于每个请求,同样的请求参数就会得到同样的结果。

为了识别不同的请求是否来自同一客户,引用HTTP会话机制,而维持这个会话则主要靠session和cookie。简单来说,cookie机制采用的是在客户端保持状态的方案,而session机制采用的是在服务器端保持状态的方案。

由于HTTP是一种无状态的协议,服务器单从网络连接上无从知道客户身份。怎么办呢?就给客户端们颁发一个通行证吧,每人一个,无论谁访问都必须携带自己通行证。这样服务器就能从通行证上确认客户身份了,而这个通行证就是cookie了。

Cookie实际上是一小段的文本信息,存储在客户端,Web服务器通过传送 HTTP 包头中的 Set-Cookie 把一个cookie发送到用户的浏览器中,内容主要包括:名字过期时间路径,路径与域一起构成cookie的作用范围。

如果不设置过期时间,则表示这个cookie的生命期为浏览器会话期间,只要关闭浏览器窗口,cookie就消失了。这种生命期为浏览器会话期的 cookie被称为会话cookie。会话cookie一般不存储在硬盘上而是保存在内存里,当然这种行为并不是规范规定的。

如果设置了过期时间,浏览器就会把cookie保存到硬盘上,关闭后再次打开浏览器,这些cookie仍然有效直到超过设定的过期时间。

session

session机制是一种服务器端的机制,服务器使用一种类似于散列表的结构来保存信息,一般存储在文件、数据库或内存中。

当客户端第一次请求服务端的时候,服务端会检查客户端的请求头携带的cookie中,是否包含sessionid,如果有的话则会检索这个sessionid对应的session是否存在。

如果不存在则会创建相应的会话信息,生成对应的session,并将sessionid返回给客户端,客户端接收到这个sessionid,把它存储起来,下一次发送请求的时候,附带着这个session一起发送给服务端,服务端只要根据这个sessionid,就知道是谁了,而这个sessionid就是这次会话生命周期的凭证,服务端可以给这个sessionid设置过期时间,一但客户端丢失这个sessionid或者是服务端认为这个sessionid失效了,那么这次会话就结束了。

登录态的维持过程:

(1)首先用户在客户端浏览器发起登陆请求

(2)登陆成功后,服务端会把用户信息保存在服务端,并返回一个唯一的 session 标识给客户端浏览器。

(3)客户端浏览器会把这个唯一的 session 标识保存在起来(存在cookie中)

(4)以后再次访问 web 应用时,客户端浏览器会把这个唯一的 session 标识带上,这样服务端就能根据这个唯一标识找到用户信息。

11. 浏览器的同源策略是什么?

难度:0.5 · 类型:QA

题目要点

同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说 Web 是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。

参考答案

同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说 Web 是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。

它的核心就在于它认为自任何站点装载的信赖内容是不安全的。当被浏览器半信半疑的脚本运行在沙箱时,它们应该只被允许访问来自同一站点的资源,而不是那些来自其它站点可能怀有恶意的资源。

所谓同源是指:域名协议端口相同。

另外,同源策略又分为以下两种:

  • DOM 同源策略:禁止对不同源页面 DOM 进行操作。这里主要场景是 iframe 跨域的情况,不同域名的 iframe 是限制互相访问的。
  • XMLHttpRequest 同源策略:禁止使用 XHR 对象向不同源的服务器地址发起 HTTP 请求。

12. 什么是内存泄漏?

难度:1 · 类型:QA

题目要点

程序的运行需要内存。只要程序提出要求,操作系统或者运行时(runtime)就必须供给内存。

参考答案

什么是内存泄漏?

程序的运行需要内存。只要程序提出要求,操作系统或者运行时(runtime)就必须供给内存。

对于持续运行的服务进程(daemon),必须及时释放不再用到的内存。否则,内存占用越来越高,轻则影响系统性能,重则导致进程崩溃。

不再用到的内存,没有及时释放,就叫做内存泄漏(memory leak)。

有些语言(比如 C 语言)必须手动释放内存,程序员负责内存管理。

char * buffer;
buffer = (char*) malloc(42);

// Do something with buffer

free(buffer);

上面是 C 语言代码,malloc方法用来申请内存,使用完毕之后,必须自己用free方法释放内存。

13. 堆与栈有什么区别?

难度:2 · 类型:QA

题目要点

堆与栈的区别

堆(Heap)和栈(Stack)是计算机内存管理中的两种不同数据结构,具有以下主要区别:

栈(Stack)

  • 数据结构:遵循后进先出(LIFO)原则。
  • 内存分配:自动和快速,用于存储局部变量和函数调用上下文。
  • 访问速度:由于内存连续,访问速度快。
  • 生命周期:数据(如局部变量)在函数调用结束时自动销毁。
  • 内存管理:自动释放,不需要垃圾回收。

堆(Heap)

  • 数据结构:任意分配,非连续内存。
  • 内存分配:手动分配和释放,速度相对较慢。
  • 访问速度:可能较慢,因为内存可能不连续。
  • 生命周期:需要手动管理或通过垃圾回收机制处理。
  • 内存管理:通常需要垃圾回收器来识别和回收不再使用的对象。

区别总结

  • 数据结构:栈是LIFO结构,堆是任意分配的结构。
  • 内存分配:栈内存分配快速且自动,堆内存分配较慢且手动。
  • 访问速度:栈通常提供更快的数据访问速度。
  • 生命周期管理:栈上的数据生命周期明确,堆上的数据需要手动管理或垃圾回收。
  • 使用场景:栈通常用于函数调用和局部变量存储,堆用于动态内存分配。
参考答案

堆(Heap)与栈(Stack)是开发人员必须面对的两个概念,在理解这两个概念时,需要放到具体的场景下,因为不同场景下,堆与栈代表不同的含义。一般情况下,有两层含义:

  • 程序内存布局场景下,堆与栈表示两种内存管理方式;
  • 数据结构场景下,堆与栈表示两种常用的数据结构。

程序内存分区中的堆与栈

栈简介

栈由操作系统自动分配释放 ,用于存放函数的参数值、局部变量等,其操作方式类似于数据结构中的栈。

其中函数中定义的局部变量按照先后定义的顺序依次压入栈中,也就是说相邻变量的地址之间不会存在其它变量。栈的内存地址生长方向与堆相反,由高到底,所以后定义的变量地址低于先定义的变量,比如上面代码中变量 s 的地址小于变量 b 的地址,p2 地址小于 s 的地址。栈中存储的数据的生命周期随着函数的执行完成而结束。

堆简介

堆由开发人员分配和释放, 若开发人员不释放,程序结束时由 OS 回收,分配方式类似于链表。

堆的内存地址生长方向与栈相反,由低到高,但需要注意的是,后申请的内存空间并不一定在先申请的内存空间的后面,即 p2 指向的地址并不一定大于 p1 所指向的内存地址,原因是先申请的内存空间一旦被释放,后申请的内存空间则会利用先前被释放的内存,从而导致先后分配的内存空间在地址上不存在先后关系。堆中存储的数据若未释放,则其生命周期等同于程序的生命周期。

关于堆上内存空间的分配过程,首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆节点,然后将该节点从空闲节点链表中删除,并将该节点的空间分配给程序。另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样,代码中的delete语句才能正确地释放本内存空间。由于找到的堆节点的大小不一定正好等于申请的大小,系统会自动地将多余的那部分重新放入空闲链表。

堆与栈区别

堆与栈实际上是操作系统对进程占用的内存空间的两种管理方式,主要有如下几种区别:

(1)管理方式不同。栈由操作系统自动分配释放,无需我们手动控制;堆的申请和释放工作由程序员控制,容易产生内存泄漏;

(2)空间大小不同。每个进程拥有的栈的大小要远远小于堆的大小。理论上,程序员可申请的堆大小为虚拟内存的大小,进程栈的大小 64bits 的 Windows 默认 1MB,64bits 的 Linux 默认 10MB;

(3)生长方向不同。堆的生长方向向上,内存地址由低到高;栈的生长方向向下,内存地址由高到低。

(4)分配方式不同。堆都是动态分配的,没有静态分配的堆。栈有2种分配方式:静态分配和动态分配。静态分配是由操作系统完成的,比如局部变量的分配。动态分配由alloca函数进行分配,但是栈的动态分配和堆是不同的,他的动态分配是由操作系统进行释放,无需我们手工实现。

(5)分配效率不同。栈由操作系统自动分配,会在硬件层级对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆则是由C/C++提供的库函数或运算符来完成申请与管理,实现机制较为复杂,频繁的内存申请容易产生内存碎片。显然,堆的效率比栈要低得多。

(6)存放内容不同。栈存放的内容,函数返回地址、相关参数、局部变量和寄存器内容等。当主函数调用另外一个函数的时候,要对当前函数执行断点进行保存,需要使用栈来实现,首先入栈的是主函数下一条语句的地址,即扩展指针寄存器的内容(EIP),然后是当前栈帧的底部地址,即扩展基址指针寄存器内容(EBP),再然后是被调函数的实参等,一般情况下是按照从右向左的顺序入栈,之后是被调函数的局部变量,注意静态变量是存放在数据段或者BSS段,是不入栈的。出栈的顺序正好相反,最终栈顶指向主函数下一条语句的地址,主程序又从该地址开始执行。堆,一般情况堆顶使用一个字节的空间来存放堆的大小,而堆中具体存放内容是由程序员来填充的。

从以上可以看到,堆和栈相比,由于大量malloc()/free()或new/delete的使用,容易造成大量的内存碎片,并且可能引发用户态和核心态的切换,效率较低。栈相比于堆,在程序中应用较为广泛,最常见的是函数的调用过程由栈来实现,函数返回地址、EBP、实参和局部变量都采用栈的方式存放。虽然栈有众多的好处,但是由于和堆相比不是那么灵活,有时候分配大量的内存空间,主要还是用堆。

无论是堆还是栈,在内存使用时都要防止非法越界,越界导致的非法内存访问可能会摧毁程序的堆、栈数据,轻则导致程序运行处于不确定状态,获取不到预期结果,重则导致程序异常崩溃,这些都是我们编程时与内存打交道时应该注意的问题。

数据结构中的堆与栈

数据结构中,堆与栈是两个常见的数据结构,理解二者的定义、用法与区别,能够利用堆与栈解决很多实际问题。

栈简介

栈是一种运算受限的线性表,其限制是指只仅允许在表的一端进行插入和删除操作,这一端被称为栈顶(Top),相对地,把另一端称为栈底(Bottom)。把新元素放到栈顶元素的上面,使之成为新的栈顶元素称作进栈、入栈或压栈(Push);把栈顶元素删除,使其相邻的元素成为新的栈顶元素称作出栈或退栈(Pop)。这种受限的运算使栈拥有“先进后出”的特性(First In Last Out),简称FILO。

栈分顺序栈和链式栈两种。栈是一种线性结构,所以可以使用数组或链表(单向链表、双向链表或循环链表)作为底层数据结构。使用数组实现的栈叫做顺序栈,使用链表实现的栈叫做链式栈,二者的区别是顺序栈中的元素地址连续,链式栈中的元素地址不连续。

栈的基本操作包括初始化、判断栈是否为空、入栈、出栈以及获取栈顶元素等。

堆简介

堆是一种常用的树形结构,是一种特殊的完全二叉树,当且仅当满足所有节点的值总是不大于或不小于其父节点的值的完全二叉树被称之为堆。堆的这一特性称之为堆序性。因此,在一个堆中,根节点是最大(或最小)节点。如果根节点最小,称之为小顶堆(或小根堆),如果根节点最大,称之为大顶堆(或大根堆)。堆的左右孩子没有大小的顺序。

堆的存储一般都用数组来存储堆,i节点的父节点下标就为( i – 1 ) / 2 (i – 1) / 2(i–1)/2。它的左右子节点下标分别为 2 ∗ i + 1 2 * i + 12∗i+1 和 2 ∗ i + 2 2 * i + 22∗i+2。如第0个节点左右子节点下标分别为1和2。

14. 为什么部分请求中,参数需要使用 encodeURIComponent 进行转码?

难度:3 · 类型:QA

题目要点

URL(统一资源定位符)在构成上有着严格的限制,只能使用英文字母(a-z,A-Z)、阿拉伯数字(0-9)以及某些特定的标点符号。这一限制源于网络标准RFC 1738的规定,该标准明确指出,URL中只能使用字母数字字符、特定的特殊字符(如"$-_.+!*’(),",不包括引号),以及用于其预定目的的保留字符。

由于这一规定,URL中不能直接使用汉字或其他非ASCII字符。如果URL中包含这些字符,就必须进行编码处理。然而,RFC 1738并没有为URL编码指定一个统一的方法,而是将编码的实现交给了应用程序(如浏览器)自行决定。这导致了URL编码领域的混乱,因为不同的操作系统、浏览器和网页字符集可能会导致完全不同的编码结果。

为了确保客户端向服务器发送的数据格式统一,可以使用Javascript进行URL编码。Javascript提供以下三个函数用于URL编码:

  1. escape():这是最古老的Javascript编码函数,它对ASCII字母、数字和特定标点符号("@ * _ + - . /")之外的字符进行编码。虽然这个函数现在已经不推荐使用,但由于历史原因,它在一些地方仍然被采用。

  2. encodeURI():这个函数是专门用于对整个URL进行编码的。它不会对ASCII字母、数字、特定标点符号以及URL中有特殊含义的符号(如"; / ? : @ & = + $ , #")进行编码。编码后,它会输出符号的UTF-8形式,并在每个字节前加上"%“符号。

  3. encodeURIComponent():这个函数用于对URL的组成部分进行个别编码,而不是对整个URL进行编码。与encodeURI()不同的是,encodeURIComponent()会对”; / ? : @ & = + $ , #“这些在encodeURI()中不被编码的符号进行编码。具体的编码方法与encodeURI()相同。

对于解码,encodeURIComponent()函数对应的解码函数是decodeURIComponent(),它用于将encodeURIComponent()编码的字符串解码回原始形式。

总结来说,为了避免因不同浏览器和系统导致的URL编码不一致问题,可以使用Javascript的encodeURI()和encodeURIComponent()函数来确保URL编码的统一性,并通过decodeURIComponent()函数进行相应的解码。

参考答案

一般来说,URL只能使用英文字母、阿拉伯数字和某些标点符号,不能使用其他文字和符号。

这是因为网络标准RFC 1738做了硬性规定:

“…Only alphanumerics [0-9a-zA-Z], the special characters “$-_.+!*’(),” [not including the quotes - ed], and reserved characters used for their reserved purposes may be used unencoded within a URL.”

这意味着,如果URL中有汉字,就必须编码后使用。但是麻烦的是,RFC 1738没有规定具体的编码方法,而是交给应用程序(浏览器)自己决定。这导致"URL编码"成为了一个混乱的领域。

不同的操作系统、不同的浏览器、不同的网页字符集,将导致完全不同的编码结果。如果程序员要把每一种结果都考虑进去,是不是太恐怖了?有没有办法,能够保证客户端只用一种编码方法向服务器发出请求?

就是使用Javascript先对URL编码,然后再向服务器提交,不要给浏览器插手的机会。因为Javascript的输出总是一致的,所以就保证了服务器得到的数据是格式统一的。

Javascript语言用于编码的函数,一共有三个,最古老的一个就是escape()。虽然这个函数现在已经不提倡使用了,但是由于历史原因,很多地方还在使用它,所以有必要先从它讲起。

它的具体规则是,除了ASCII字母、数字、标点符号”@ * _ + - . /“以外,对其他所有字符进行编码。

encodeURI()是Javascript中真正用来对URL编码的函数。

它着眼于对整个URL进行编码,因此除了常见的符号以外,对其他一些在网址中有特殊含义的符号”; / ? : @ & = + $ , #",也不进行编码。编码后,它输出符号的utf-8形式,并且在每个字节前加上%。

最后一个Javascript编码函数是encodeURIComponent()。与encodeURI()的区别是,它用于对URL的组成部分进行个别编码,而不用于对整个URL进行编码。

因此,"; / ? : @ & = + $ , #",这些在encodeURI()中不被编码的符号,在encodeURIComponent()中统统会被编码。至于具体的编码方法,两者是一样。

它对应的解码函数是decodeURIComponent()。

15. 什么是空间复杂度?

难度:2 · 类型:QA

题目要点

空间复杂度是对一个算法在运行过程中临时占用存储空间的大小。

参考答案

空间复杂度是对一个算法在运行过程中临时占用存储空间的大小。

计算方法

  • 忽略常数,用O(1)表示
  • 递归算法的空间复杂度=(递归深度n)*(每次递归所要的辅助空间)

仅仅只复制单个变量,空间复杂度为O(1)。

举例如下:空间复杂度为O(n) = O(1)。

let a = 1;
let b = 2;
let c = 3;
console.log('输出a,b,c', a, b, c);

递归实现,调用fun函数,每次都创建1个变量k。调用n次,空间复杂度O(n*1) = O(n)。

function fun(n) {
  let k = 10;
  if (n == k) {
    return n;
  } else {
    return fun(++n)
  }
}

16. 介绍你知道的一些数据结构

难度:3 · 类型:QA

题目要点

栈:一种特殊串联形式的抽象数据类型,可由链表或数组实现,通过链表或数组的栈顶(Top)指针对数据进行压栈(Push)和出栈(Pop)操作,其特点是LIFO。

参考答案
  • 栈:一种特殊串联形式的抽象数据类型,可由链表或数组实现,通过链表或数组的栈顶(Top)指针对数据进行压栈(Push)和出栈(Pop)操作,其特点是LIFO。

  • 队列:先进先出(FIFO)的线性表,一般用链表和数组来实现,只允许在后端(back or rear)插入,在前端(front)删除。

  • 数组:由相同元素的集合所组成的数据结构,存储在一块连续的内存单元,根据元素的索引可以计算出该元素对应的存储地址。

  • 链表:由一连串节点组成,每个节点包含任意的实例数据和一个或两个用来指向下一个/上一个节点位置的链接。

  • 树:实现抽象数据类型的数据结构,如:二叉树、霍夫曼树。

  • 图:表示物件与物件之间的关系,图论的基本研究对象。

  • 堆:是计算机科学中一种特别的树状数据结构,也是一种特殊的二叉树。

  • 散列表:根据键(key)直接访问内存存储位置的一种数据结构,通过计算一个关于键值的函数,将所需查询的数据映射到表中的一个位置来访问记录,映射函数叫做散列函数,存放记录的数组叫散列表(散列函数和哈希冲突是实现散列表最重要的两个环节)。

17. 请说说cookie与session有什么区别?

难度:1 · 类型:QA

题目要点

Session和Cookie是Web应用程序中用于跟踪用户状态的两种机制。

Session

  • 定义:Session是在服务端保存的一个数据结构,用于跟踪用户的状态。
  • 存储位置:Session可以保存在服务端的内存、数据库或文件中。
  • 集群处理:在集群环境中,Session服务器集群用于保存用户会话,通常使用内存中的缓存服务来存储Session信息。

Cookie

  • 定义:Cookie是客户端保存用户信息的一种机制,用来记录用户的一些信息,如登录状态、偏好设置等。
  • 实现Session跟踪:Cookie通常用于实现Session跟踪,服务端在创建Session时会在HTTP协议中告诉客户端在Cookie中记录一个Session ID。
  • 客户端禁用Cookie:如果客户端禁用了Cookie,可以使用URL重写技术,通过在URL后面添加参数(如sid=xxxxx)来识别用户。
  • 用户体验:Cookie也可以用来存储登录信息,以便用户下次访问时无需再次输入账号。

总结

  • Session是服务端用来跟踪用户状态的数据结构,可以保存在服务端的不同位置。
  • Cookie是客户端用来记录用户信息的机制,用于实现Session跟踪,并可以提高用户体验。
参考答案
  • 由于HTTP协议是无状态的协议,所以服务端需要记录用户的状态时,就需要用某种机制来识具体的用户,这个机制就是Session。

典型的场景比如购物车,当你点击下单按钮时,由于HTTP协议无状态,所以并不知道是哪个用户操作的,所以服务端要为特定的用户创建了特定的Session,用用于标识这个用户,并且跟踪用户,这样才知道购物车里面有几本书。这个Session是保存在服务端的,有一个唯一标识。

在服务端保存Session的方法很多,内存、数据库、文件都有。

集群的时候也要考虑Session的转移,在大型的网站,一般会有专门的Session服务器集群,用来保存用户会话,这个时候 Session 信息都是放在内存的,使用一些缓存服务比如Memcached之类的来放 Session。

  • 思考一下服务端如何识别特定的客户?

这个时候Cookie就登场了。每次HTTP请求的时候,客户端都会发送相应的Cookie信息到服务端。实际上大多数的应用都是用 Cookie 来实现Session跟踪的,第一次创建Session的时候,服务端会在HTTP协议中告诉客户端,需要在 Cookie 里面记录一个Session ID,以后每次请求把这个会话ID发送到服务器,我就知道你是谁了。

有人问,如果客户端的浏览器禁用了 Cookie 怎么办?

一般这种情况下,会使用一种叫做URL重写的技术来进行会话跟踪,即每次HTTP交互,URL后面都会被附加上一个诸如 sid=xxxxx 这样的参数,服务端据此来识别用户。

  • Cookie其实还可以用在一些方便用户的场景下,设想你某次登陆过一个网站,下次登录的时候不想再次输入账号了,怎么办?

这个信息可以写到Cookie里面,访问网站的时候,网站页面的脚本可以读取这个信息,就自动帮你把用户名给填了,能够方便一下用户。

这也是Cookie名称的由来,给用户的一点甜头。

所以,总结一下

  • Session是在服务端保存的一个数据结构,用来跟踪用户的状态,这个数据可以保存在集群、数据库、文件中;
  • Cookie是客户端保存用户信息的一种机制,用来记录用户的一些信息,也是实现Session的一种方式。

18. 进程间有哪些通信方式?

难度:1 · 类型:QA

题目要点

管道通信

参考答案
  • 管道通信
  • 消息队列通信
  • 信号量通信
  • 共享内存通信
  • 套接字通信

19. 进程与线程有什么区别?

难度:1 · 类型:QA

题目要点

进程是系统进行资源分配和调度的一个独立单位

参考答案
  • 进程是系统进行资源分配和调度的一个独立单位
  • 线程是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位
  • 一个进程至少由一个线程组成。

线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。