计算机网络

写在前面:

本文为博主秋招时的面试总结。本文适合互联网实习、校招阶段阅读,以及有需要巩固计算机基础知识的阅读,编程语言部分为Java。文中有错误之处,欢迎来评论区探讨并指正。

网络分层⭐

国际标准化组织提出了 OSI 模型:应用层、表示层、会话层、运输层、网络层、链路层和物理层,理论完善,但复杂且不实用。

学习网络原理使用五层模型:应用层、运输层、网络层、链路层和物理层。

实际使用 TCP/IP 模型:应用层、运输层、网际层和网络接口层。

每层使用下层的服务来提供服务,对等层间的数据单位是协议数据单元 PDU,上下层间的数据单位是服务数据单元 SDU。


应用层

应用层协议定义了应用进程的通信规则,应用进程互相通信完成网络应用。

应用层协议包括:

  • 域名解析系统 DNS

    DNS 是一个分布式数据库系统,存储了域名和 IP 地址的映射关系。

    主机向本地域名服务器的查询采用递归查询:如果本地域名服务器不知道被查询域名的 IP 地址,就会以 DNS 客户的身份向其他根域名服务器继续发出查询请求。

    本地域名服务器向根域名服务器查询采用迭代查询:根域名服务器会告知顶级域名服务器的地址,顶级域名服务器给出 IP 地址,或者告知下一步应该向哪个权限域名服务器进行查询。

  • 文件传送协议 FTP

    FTP 通过TCP 保证可靠运输,使用两个端口,控制端口 21 和数据端口 20,分别进行控制连接和数据连接。

  • 电子邮件协议

    从用户代理把邮件传送到服务器,以及在服务器之间的传送使用 SMTP 协议。

    用户代理从服务器读取邮件时使用 POP3 或 IMAP 协议。


运输层

运输层负责向主机应用进程间的通信提供数据传输服务,由于一台主机可以同时运行多个进程,因此运输层具有复用和分用的功能,复用就是多个应用进程可以同时使用运输层发送数据,分用就是把运输层收到的数据交付给对应的应用进程。

运输层协议包括:

  • 用户数据报协议 UDP,提供无连接的、尽最大努力交付的数据传输服务,不保证可靠性,传输单位是用户数据报。

  • 传输控制协议 TCP,提供面向连接的数据传输服务、保证可靠性,传输单位是报文。


网络层

网络层任务:① 为分组交换网上的主机提供通信服务,在发送数据时把运输层数据报封装成分组传送。② 选择合适路由,使源主机的分组通过路由器找到目的主机。

网络层协议包括:

  • 网际协议 IP

    一般指 IPv4,与 IP 配套使用的还有 ARP、ICMP 和 IGMP。

    IP 数据报分为首部和数据两部分。首部前 20 字节是固定的,包含源地址、目的地址、总长度等,生存时间限制了 IP 数据报在网络中能经过的最大路由数,防止其兜圈子。

    要解决 IP 地址耗尽的问题,根本方法是采用具有更大地址空间的 IPv6(128 位)。

  • 地址解析协议 ARP

    由于 IP 使用了 ARP,因此把 ARP 归到网络层,但 ARP 的作用是通过一个高速缓存,存储本地局域网的各主机和路由器的 IP 地址到硬件地址的映射表,以从网络层的 IP 解析出数据链路层的硬件地址,因此也可以把 ARP 划归在数据链路层。

    与 ARP 对应的是 RARP 逆地址解析协议,作用是通过硬件地址找到 IP 地址,被 DHCP 协议取代。

  • 路由选择协议

    内部网关协议:

    • RIP:分布式的距离向量协议,适用于小型网络,按固定时间间隔与相邻路由器交换路由表信息。

    • OSPF:分布式的链路状态协议,适用于大型网络,只在链路状态变化时才向本自治系统中的所有路由器发送相邻路由器的信息。

    外部网关协议:

    • BGP-4:针对不同自治系统之间的路由器,目标是寻找一条能够到达目的网络且不兜圈子的路由。
  • 网际控制报文协议 ICMP

    ICMP 报文包括差错报文和询问报文,ICMP 报文作为 IP 数据报的数据,加上首部后组成 IP 数据报发送出去。ICMP 允许主机或路由器报告差错情况,提供有关异常情况的信息。ICMP 的重要应用是分组探测 PING,测试主机间的连通性。

  • 网际组管理协议 IGMP

    IGMP 的作用是让连接在本地局域网上的多播路由器知道本局域网上是否有主机的某个进程参加或退出了某个多播组。


链路层

数据链路层将网络层的分组封装成帧,在两个相邻结点间的链路上传输,每一帧包括数据和必要的控制信息(同步信息、地址信息、差错信息)。控制信息使接收端能够知道一个帧从哪个比特开始到哪个比特结束,从帧中提取出数据上交给网络层。控制信息还使接收端可以检测收到的帧有无差错,如果有差错就简单地丢弃,避免继续传送而浪费网络资源。

链路层协议包括:

  • 点对点协议 PPP

    在通信质量较差的年代使用高级数据链路控制 HDLC 作为数据链路层协议,目前使用最广泛的协议是 PPP。PPP 的特点是简单、只检测差错而不纠正、不使用序号也不进行流量控制、同时支持多种网络层协议。

  • CSMA/CD 协议

    以太网采用具有冲突检测的载波监听多点接入协议,特点是:发送前先监听、边发送边监听,一旦发现总线上出现了碰撞就立即停止发送,然后按退避算法等待一段随机时间后再次发送。


物理层

物理层尽可能屏蔽传输媒体和通信手段的差异,使数据链路层只需考虑本层协议和服务。

物理层的数据单位是比特,发送方和接收方发送和接收 1 或 0,因此物理层需要考虑用多大的电压代表 1 或 0,以及接收方如何识别发送方所发送的比特。此外物理层还要确定传输媒体规范,例如接线器形状、电缆电压范围等。


TCP⭐

特点

TCP 是面向连接的,一个应用进程在向另一个进程发送数据前必须先建立连接,发送某些预备报文段。

TCP 提供全双工服务,允许通信双方的应用进程在任何时候发送数据。TCP 连接的两端都有发送缓存和接收缓存:发送时,应用程序把数据传送给 TCP 缓存后就可以做自己的事,TCP 在合适的时候发送;接收时,TCP 把收到的数据放入缓存,应用程序在合适的时候读取。

TCP 连接是点对点的,只能是单个发送方和单个接收方之间的连接。

TCP 提供可靠的交付服务,通过 TCP 传送的数据无差错、不丢失、不重复,按序到达。

TCP 是面向字节流的,流是指流入进程或从进程流出的字节序列。虽然应用程序和 TCP 的交互是每次一个数据块,但 TCP 把数据块仅看成一连串无结构的字节流。TCP 不保证接收方的数据块和发送方的数据块具有对应大小的关系,但接收方的字节流必须和发送方的字节流完全一样。应用程序必须有能力识别收到的字节流,把它还原成应用层数据。


UDP 和 TCP 的区别⭐

UDP 无连接,发送数据前不需要建立连接,减少了开销和时延。

UDP 使用尽最大努力交付,不保证可靠性,主机不需要维持复杂的连接状态。

UDP 面向报文,UDP 对应用层报文添加首部后就交付 IP 层。

UDP 没有拥塞控制,网络拥塞不会降低源主机的发送速率,这对某些实时应用很重要,如视频会议。

UDP 支持一对一、一对多和多对多通信。


TCP 报文结构

TCP 报文段分为首部和数据两部分。首部的前 20 个字节固定,后面有 4n 字节根据需要增加。

字段 大小 说明
源端口和目的端口 2B 分别写入源端口号和目的端口号,TCP 的分用功能是通过端口实现的。
序号 4B 本报文段所发数据第一个字节的序号,使用 mod 232 计算。
确认号 4B 期望收到对方下一个报文段第一个字节的序号,确认号为 N 代表到 N-1 为止都已收到。
数据偏移 4B 指出了报文的数据起始处到报文起始处的距离。
标志 6b URG:紧急,URG=1 时表示存在紧急数据,不再排队等待发送,需要和紧急指针配合使用。
ACK:确认,ACK=1 时表示成功接收了报文段。
SYN:同步,在建立连接时用来同步序号,SYN=1 表示一个连接请求或连接响应报文。
FIN:终止,用来释放连接,当 FIN=1 时表示发送方已发送完毕,并要求释放连接。
PSH:推送,PSH=1 时接收方不再等待整个缓存填满再交付数据,而是尽快交付数据。
RST:复位,当 RST=1 时表示 TCP 连接出现了严重错误,必须释放再重新建立连接。
接收窗口 2B 限制发送方的发送窗口,因为接收方的缓存有限。
检验和 2B 检验包括首部和数据两部分,如果接收方检测到差错会丢弃 TCP 报文。

自动重传请求 ARQ

ARQ 包括停止等待协议、回退 N 步协议和选择重传协议,后两种结合了窗口机制,属于连续 ARQ 协议。

停止等待协议

每发送完一个分组就停止发送,等待对方确认,在收到确认后再发送下一个分组。包括三种情况:

  • 无差错

    A 发送分组 M1,发送完后暂停并等待 B 的确认;B 收到 M1 后向 A 发送确认;A 收到确认后再发送下一个分组 M2

  • 出现差错

    B 收到 M1 后检测到了差错,或者 M1 在传输过程中丢失,这两种情况下 B 都不会发送确认信息,解决方法是:A 只要超过一段时间没有收到确认,就进行超时重传,每发送完一个分组就设置超时计时器,如果在计时器到期前收到确认就撤销计时。

    注意:① 发送完分组后必须暂时保留副本,收到确认再清除。② 分组和确认分组都必须进行编号。③ 超时时间应当比分组传输的往返时间稍长,过短会产生不必要的重传,过长会降低通信效率。

  • 确认丢失和确认迟到

    B 发送的确认丢失,A 会超时重传,B 会丢弃重传分组并重新确认;B 发送的确认迟到,A 收到重复确认后将其丢弃。

    通常 A 最终总是可以收到对所有发出分组的确认,如果 A 不断重传分组但总收不到确认,就说明通信线路质量太差,不能通信。

停止等待协议的优点是简单,缺点是信道利用率低。为了提高传输效率,发送方可以连续发送多个分组,不必每发送完一个分组就停下来等待确认,使信道上一直有数据传送。但流水线传输可能会遇到差错,解决方法包括回退 N 步和选择重传。


回退 N 步协议

回退 N 步即 GBN 协议,允许发送方发送多个分组而不需要等待确认。GBN 中发送方已发送但还未确认的序号和允许发送但还未发送的序号可以被看作一个长度为 N 的窗口,随协议运行该窗口向前滑动,因此 GBN 也被称为滑动窗口协议。

GBN 采用累积确认的方式,对按序到达的最后一个分组发送确认,如果超时,发送方会重传所有已发送但还未确认的分组。例如发送了序号为 1~5 的五个分组,除了第三个全部收到了,那么确认序号就是 2,发送方将重传 3~5 的分组。

在 GBN 中,接收方丢弃所有失序分组,因为接收方必须按序交付数据。这种做法的优点是缓存简单,不需要缓存任何失序分组;缺点是对失序分组的重传可能出错而导致更多重传。


选择重传协议

GBN 中单个分组的差错就能引起大量分组重传,随着信道差错率的增加,流水线会被不必要重传的分组所充斥。

选择重传即 SR 协议,让发送方仅重传那些它怀疑接收出错的分组,避免不必要的重传。接收方将确认一个正确接收的分组而不管其是否按序,失序分组将被缓存直到收到所有丢失分组,此时将分组按序交付上层。


TCP 可靠原理

TCP 的可靠传输包含很多机制,例如使用检验和来检测传输中的比特错误、使用定时器超时重传、使用序号检测丢失分组和冗余副本、使用确认号告诉发送方确认的分组信息。

TCP 的发送方仅需维持已发送但未确认的最小序号,以及下一个要发送的序号,从这种角度看 TCP 像一个 GBN 协议。但 TCP 和 GBN 的区别是 TCP 会将正确接收但失序的报文缓存起来,当分组 n 丢失时,GBN 会重传 n 之后的所有分组,但 TCP 至多只会重传分组 n。TCP 允许接收方有选择地确认失序报文段,而不是累积确认最后一个正确接收的有序报文段,从这个角度看 TCP 又像 SR 协议。因此 TCP 的差错恢复机制是一种 GBN 和 SR 的结合体。


滑动窗口

滑动窗口以字节为单位。发送端有一个发送窗口,窗口中的序号是允许发送的序号,窗口的后沿是已发送且确认的序号,窗口的前沿是不允许发送的序号。窗口的后沿可能不动(没有收到新的确认),也有可能前移(收到了新的确认),但不会后移(不可能撤销已经确认的数据)。窗口的前沿一般是向前的,可能不动(没有收到新的请求或对方的接收窗口变小),也可能收缩(TCP 强烈不建议这么做,因为发送端在收到通知前可能已经发送了很多数据,将产生错误)。

发送缓存存放应用程序传给 TCP 准备发送的数据和已发送但还未确认的数据;接收缓存存放按序到达但尚未被应用程序读取的数据和未按序到达的数据。

发送窗口根据接收窗口设置,但并不总是一样大,还要根据网络的拥塞情况调整。

接收方必须有累积确认功能,既可以在合适的时候确认,也可以在发送数据时捎带确认,但不能过分推迟,一般不超过 0.5 秒。


流量控制

如果应用程序读取的速度较慢,而发送方发送得太快,就会使接收缓存溢出,TCP 通过流量控制解决该问题。

TCP 通过接收窗口实现流量控制,接收窗口告诉发送方自己可用的缓存空间,发送方的发送窗口不能超过接收方的接收窗口。

当接收窗口=0 时就不再允许发送方发送数据,但可能存在一种情况:在发送零窗口报文不久后,接收方的接收缓存又有了存储空间,因此发送报文说明新的接收窗口,但该报文在传输中丢失。发送方会一直等待接收方的非零窗口通知,而接收方也一直在等待发送方发送数据,形成死锁。为解决该问题,TCP 为每个连接设有持续计时器,只要 TCP 连接的一方收到对方的零窗口通知,就启动该计时器,到期后发送一个零窗口探测报文,避免死锁。

有一种问题叫糊涂窗口综合症,当接收方处理数据很慢时,应用进程间传送的有效数据很小, 极端情况下有效数据只有 1B 但传输开销却有 40B(IP 首部及TCP 首部各占 20B) ,导致通信效率极低。为解决该问题,可以等到接收方有足够空间容纳一个最长报文段,或接收缓存已有一半空间再发送;发送方也不要发送太小的报文,而是把数据积累成足够大的报文,或达到接收方缓存一半时才发送。


拥塞控制

网络中对资源的需求超过可用量的情况就叫拥塞,当吞吐量明显小于理想吞吐量时就出现了轻度拥塞。拥塞控制就是减少注入网络的数据,减轻路由器和链路的负担,这是一个全局性问题,涉及网络中的所有路由器和主机,而流量控制是一个端到端的问题。

根据网络层是否为拥塞控制提供显式帮助,将拥塞控制分为:端到端拥塞控制网络辅助的拥塞控制。TCP 使用端到端的拥塞控制,因为 IP 层不会向端系统提供显式的拥塞反馈。TCP 让发送方根据拥塞程度限制发送速率。如果发送方感知到没什么拥塞会增加发送速率,否则会降低发送速率。限制发送速率通过拥塞窗口实现,判断拥塞通过超时或连续接收到 3 个冗余 ACK 实现。

TCP 的拥塞控制算法包括了慢启动、拥塞避免和快恢复。慢启动和拥塞避免是 TCP 的强制部分,差异在于对收到的 ACK 做出反应时拥塞窗口增加的方式,慢启动比拥塞避免增加得更快。快恢复是推荐部分,对 TCP 发送方不是必须的。

1. 慢启动

拥塞窗口 cwnd 以一个 MSS 最大报文段开始,每当传输的报文段首次被确认就增加一个 MSS。因此每经过一个 RTT 往返时间,拥塞窗口就会翻倍,发送速率也会翻倍。

结束慢启动的情况:① 发生超时事件,发送方将 cwnd 设为 1,重新开始慢启动,并将慢启动阈值设置为 cwnd/2。② 当拥塞窗口达到慢启动阈值时就结束慢启动而进入拥塞避免模式。③ 如果检测到三个冗余的 ACK,TCP 就会执行快重传并进入快恢复状态。

2. 拥塞避免

一旦进入拥塞避免状态,cwnd 值大约是上次拥塞时的 1/2,距离拥塞并不遥远。因此 TCP 不会每经过一个 RTT 就将 cwnd 翻倍,而是较为保守地在每个 RTT 后将 cwnd 加 1。

发生超时事件时,拥塞避免和慢启动一样,将 cwnd 设为 1,并将慢启动阈值设置为 cwnd/2。

3. 快恢复

有时个别报文段丢失,但网络中并没有出现拥塞,如果使用慢启动会降低传输效率。这时应该使用快重传来让发送方尽早知道出现了个别分组的丢失,快重传要求接收端不要等待自己发送数据时再捎带确认,而是要立即发送确认。即使收到了乱序的报文段也要立即发出对已收到报文段的重复确认。当发送方连续收到三个冗余 ACK 后就知道出现了报文段丢失的情况,会立即重传并进入快恢复状态。

在快恢复中,会调整慢启动阈值为 cwnd/2,并进入拥塞避免状态。


三次握手⭐

TCP 是全双工通信,任何一方都可以发起连接请求,假设 A 是客户端,B 是服务器。

初始 A 和 B 均处于 CLOSED 状态,B 会创建传输进程控制块 TCB 并进入 LISTEND 状态,监听端口是否收到连接请求。

当 A 要发送数据时,就向 B 发送连接请求报文,其中 SYN=1,ACK=0,SYN 不可以携带数据,但要消耗一个序号(假设 seq=x)。发送后 A 进入 SYN-SENT 同步已发送状态。

当 B 收到 A 的连接请求报文后,进入 SYN-RCVD 同步已接收状态,如果同意建立连接就会发送给 A 一个连接响应报文,其中 SYN=1,ACK=1,ack=x+1,seq=y。ack 的值为 A 发送的序号加 1,ACK 可以携带数据,如果不携带的话则不消耗序号。

当 A 收到 B 的确认后,还要对该确认再进行一次确认,报文的 ACK=1,ack=y+1,seq=x+1,发送后 A 进入 ESTABLISHED 状态,当 B 接收到该报文后也进入 ESTABLISHED 状态,客户端会稍早于服务器端建立连接。

三次握手的原因:

  • 从信息对等的角度看,双方只有确定 4 类信息才能建立连接,即 A 和 B 分别确认自己和对方的发送和接收能力正常。在第二次握手后,B 还不能确定自己的发送能力和 A 的接收能力,只有在第三次握手后才能确认。

  • 报文的生存时间往往会超过 TCP 请求的超时时间,A 的某个超时连接请求可能会在双方释放连接后到达 B,B 会误以为是 A 创建了新的连接请求,然后发送确认报文创建连接。由于 A 的状态不是 SYN_SENT,将直接丢弃 B 的确认数据。如果是两次握手,连接建立,服务器资源被白白浪费;如果是三次握手,B 由于长时间没有收到确认,最终超时导致连接失败,不会出现脏连接。


四次挥手⭐

当 A 没有要发送的数据时就会向 B 发送终止连接报文,其中 FIN=1,seq=u,u 的值为之前 A 发送的最后一个序号加 1,发送后 A 进入 FIN-WAIT-1 状态。

B 收到后响应给 A 一个确认报文,ACK=1,ack=u+1,seq=v,v 的值为 B 之前发送的最后一个序号加 1。此时 A 进入 FIN-WAIT-2 状态,B 进入 CLOSE-WAIT 状态,但连接并未完全释放,B 会通知应用进程结束 A 到 B 方向的连接,此时 TCP 处于半关闭状态。

当 B 也准备释放连接时就向 A 发送连接终止报文,FIN=1,同时还要重发 ACK=1,ack=u+1,seq=w,seq 改变的原因是在半关闭状态 B 可能又发送了数据,之后 B 进入 LAST-ACK 状态。

A 收到连接终止报文后还要再进行一次确认,确认报文中 ACK=1,ack=w+1,seq=u+1,发送完后进入 TIME-WAIT 状态,等待 2MSL 后进入 CLOSED 状态。B 收到该确认后进入 CLOSED 状态,服务器端会稍早于客户端释放连接。

四次挥手的原因:TCP 是全双工通信,两个方向的连接需要单独断开。

等待 2MSL 的原因:

  • 保证被动关闭方可以进入 CLOSED 状态。MSL 是最大报文段寿命,等待 2MSL 可以保证 A 发送的最后一个确认报文被 B 接收,如果该报文丢失,B 会超时重传之前的 FIN+ACK 报文,而如果 A 在发送确认报文后立即释放连接就无法收到 B 可能超时重传的报文,也不会再次发送确认报文段,B 就无法正常进入 CLOSED 状态。

  • 2MSL 时间后,本连接中的所有报文就都会从网络中消失,防止已失效连接的请求数据包与正常连接的请求数据包混淆而发生异常。

除此之外,TCP 还设有一个保活计时器,用于解决客户端故障问题,服务器每收到一次数据就重新设置保活计时器,如果 2 小时内没有收到数据就间隔 75 秒发送一次探测报文,连续 10 次没有响应后关闭连接。

TIME-WAIT

在高并发短连接的 TCP 服务器上,服务器处理完请求后立刻主动关闭连接,该场景下大量 socket 处于 TIME-WAIT 状态。TIME-WAIT 状态无法真正释放句柄资源,socket 使用的本地端口在默认情况下不能再被使用,会限制有效连接数量,成为性能瓶颈。

解决:调小 tcp_fin_timeout 的值、将 tcp_tw_reuse 设为 1 开启重用,将 tcp_tw_recycle 设为 1 开启快速回收。


HTTP ⭐

概况

HTTP 超文本传输协议,由客户程序和服务器程序实现,客户程序和服务器程序通过交换 HTTP 报文进行会话。HTTP 定义了这些报文的结构以及报文交换的方式,当用户请求一个 Web 页面时,浏览器向服务器发出对该页面中所包含对象的 HTTP 请求报文,服务器接收请求并返回包含这些对象的 HTTP 响应报文。

HTTP 使用 TCP 作为运输协议,HTTP 客户首先发起一个与服务器的 TCP 连接,一旦连接建立,浏览器和服务器进程就可以通过套接字访问 TCP。客户向它的套接字接口发送请求报文,服务器从它的套接字接口接收请求报文。

HTTP 是一种无状态的协议,服务器不存储任何关于该客户的状态信息。假如某个客户在短时间内连续两次请求同一个对象,服务器并不会因为刚刚为该客户做出了响应就不再响应,而是重新进行响应。


非持续连接和持续连接

非持续连接必须为每个请求维护一个连接,对于每个连接,在客户和服务器中都要分配 TCP 缓冲区,给服务器造成很大负担。每次请求到响应大约需要花费两个 RTT 加上服务器传输文件的时间,RTT 指分组从客户到服务器再返回客户的时间。三次握手的前两部分占用一个 RTT,第三部分向服务器发送请求报文,服务器收到后做出响应,占用另一个 RTT。

HTTP1.1 使用持续连接,服务器响应后保持连接打开。在相同客户与服务器之间,后续的请求和响应报文能够通过相同的连接进行传送。


报文格式

请求报文

请求报文包括请求行、首部行和实体。

  • 请求行包括方法、URL 和 HTTP 版本。方法包括了 GET、POST、HEAD、PUT 和 DELETE 等。HEAD 类似于 GET,当服务器收到一个 HEAD 请求时,会用一个 HTTP 报文进行响应,但并不返回请求对象,通常使用 HEAD 进行调试;PUT 常用于上传对象到 Web 服务器;DELETE 用于删除 Web 服务器上的对象。

  • 首部行可以携带信息,例如 Connection:close 可以告诉服务器不要使用持续连接;User-agent 可以指明浏览器类型,服务器可以为不同类型的用户代理发送对象的不同版本。

  • 在首部行后有一个空行,后面跟着的是实体。使用 GET 时实体为空,而使用 POST 时才会使用实体。

响应报文

响应报文包括状态行、首部行和实体。

  • 状态行包括协议版本、状态码和对应的状态信息。

  • 首部行中,Date 是服务器发送响应报文的时间;Server 指明了服务器类型,类似于请求报文中的 User-agent

  • 实体是报文的主要部分,即所请求的对象本身。

状态码 短语 含义
200 OK 成功响应
301 Moved Permanently 请求对象已被永久转移,新的 URL 定义在响应报文的首部行,客户端将自动获取。
302 Found 与301类似,但资源只是临时被移动,客户端继续使用原有 URL。
400 Bad Request 通用的差错代码,请求不能被服务器理解。
401 Unauthorized 未认证,缺乏相关权限。
402 Payment Required 保留,将来使用。
403 Forbidden 服务器理解客户端的请求,但是拒绝执行。
404 Not Found 被请求的文档不在服务器上,有可能因为请求 URL 出错。
405 Method Not Allowed 客户端中请求的方法被禁止,例如限制 POST 方式但使用了 GET 访问。
500 Internal Server Error 服务器内部错误,无法完成请求。
501 Not Implemented 服务器不支持请求的功能,无法完成请求。
502 Bad Gateway 作为网关或代理工作的服务器尝试执行请求时,从远程服务器收到了一个无效响应。
503 Service Unavailable 由于超载或系统维护,服务器暂时无法处理客户端的请求。
504 Gateway Timeout 充当网关或代理的服务器,未及时从远端服务器获取请求。
505 HTTP Version Not Supported 服务器不支持请求报文使用的 HTTP 版本。

GET 和 POST 的区别⭐

  • GET 读取一个资源,可以将 GET 数据缓存在浏览器、代理或服务端。反复 GET 不应该对访问有副作用,没有副作用被称为幂等。

    POST 不是幂等的,意味着不能随意多次执行,因此不能缓存,如果尝试重新执行 POST 请求,浏览器会弹出提示框询问是否重新提交表单。

  • GET 请求由 url 触发,想携带参数就只能在 url 后附加。

    POST 请求来自表单提交,表单数据被浏览器编码到 HTTP 请求报文的请求体中。主要有两种编码格式,一种是 application/..,用来传输简单数据;另一种是 multipart/form-data格式,用来传输文件,对二进制数据传输效率高。

  • 从攻击的角度说,无论 GET 还是 POST 都不安全,因为 HTTP 是明文协议。

  • GET 长度受限于 url,而 url 的长度由浏览器和服务器决定。

    POST 没有大小限制,起限制作用的是服务器的处理能力。


cookie⭐

HTTP 的无状态性简化了服务器设计,提高了性能,使其可以同时处理大量 TCP 连接。但无状态也导致服务器不能识别用户,为解决该问题 HTTP 使用 cookie 客户端会话技术对用户进行追踪。

工作流程

① 当客户通过浏览器第一次访问站点时,该站点将产生一个唯一识别码,并以此作为索引,在后端数据库中产生一个表项。

② 服务器用一个包含 Set-cookie 首部的 HTTP 响应报文对浏览器进行响应,浏览器收到后将其添加到自己管理的 cookie 文件。

③ 在下次访问该站点时,请求报文的首部行会包括这个识别码,尽管浏览器不知道客户是谁,但可以确定是同一个客户。

cookie 和 session 的区别

① cookie 只能存储 ASCII 码,而 session 可以存储任何类型的数据。

② session 存储在服务器,而 cookie 存储在客户浏览器中,容易被恶意查看。。

③ session 的运行依赖 session id,而 session id 存在 cookie 中,叫做 JSESSIONID。如果浏览器禁用了 cookie ,同时 session 也会失效(可以通过其它方式实现,比如在 url 中传递 session_id)。


输入一个 url 发生的事

判断 url 是否合法,如果不合法会使用默认的搜索引擎进行搜索。如果输入的是一个域名,默认会加上一个 http 前缀。

先检查浏览器的 DNS 缓存,没有则检查本地 hosts 文件的缓存,如果仍然没有会向本地 DNS 服务器发送请求,最终本地 DNS 服务器得到域名和 IP 地址的映射关系,把结果返回给用户并进行缓存。

获取 IP 地址后,通过 TCP 三次握手建立连接,发送请求报文。

服务器收到请求报文后进行响应,主进程进行监听,创建子进程处理,先判断是否是重定向,如果是重定向则返回重定向地址。如果是静态资源则直接返回,否则通过 REST URL 在代码层面处理,最后返回响应报文。

浏览器收到 HTTP 响应报文后进行解析,首先查看响应报文的状态码,根据不同的状态码做不同处理。之后解析 HTML、CSS、JS 等文件,构建 DOM 树,渲染树,重绘。最后将像素发送 GPU 进行渲染,将渲染结果返回给用户并进行缓存。

通过 TCP 的四次挥手断开连接,如果是 HTTP1.1 则会将连接保持一小段时间。


HTTPS⭐

HTTP 存在的问题

没有加密,无法保证通信内容不被窃听。

没有报文完整性验证,无法确保通信内容在传输中不被改变。

没有身份鉴别,无法让通信双方确认对方身份。

HTTPS 原理

HTTP over SSL,在 HTTP 传输上增加了 SSL 安全套接字层,通过机密性、数据完整性、身份鉴别为 HTTP 事务提供安全保证。SSL 会对数据进行加密并把加密数据送往 TCP 套接字,在接收方,SSL 读取 TCP 套接字的数据并解密,把数据交给应用层。HTTPS 采用混合加密机制,使用非对称加密传输对称密钥保证传输安全,使用对称加密保证通信效率。

HTTPS 流程:

① 客户发送它支持的算法列表以及一个不重数。不重数就是在协议的生存期只使用一次的数,用于防止重放攻击,每个 TCP 会话使用不同的不重数,可以使加密密钥不同,重放记录无法通过完整性检查。

② 服务器从该列表中选择一种对称加密算法(例如 AES),一种公钥加密算法(例如 RSA)和一种报文鉴别码算法,然后把它的选择、证书,一个不重数返回给客户。

③ 客户通过 CA 提供的公钥验证证书,成功后提取服务器的公钥,生成一个前主密钥 PMS 并发送给服务器。

④ 客户和服务器独立地从 PMS 和不重数中计算出仅用于当前会话的主密钥 MS,然后通过 MS 生成密码和报文鉴别码密钥。此后客户和服务器间发送的所有报文均被加密和鉴别。


网络安全

网络攻击

被动攻击指攻击者从网络上窃听他人的通信内容,只是分析协议数据单元 PDU 而不干扰信息流。

主动攻击包括:

  • 篡改

    攻击者篡改网络上传输的报文、中断报文的传送、或者把完全伪造的报文发给接收端。

  • 恶意程序

    ① 计算机病毒,修改其他程序来把自身的变种复制进去。② 计算机蠕虫,通过网络通信把自己从一个节点发往另一个节点,并自动启动。③ 特洛伊木马,它执行的功能并非声称的功能,而是恶意程序。④ 逻辑炸弹,当运行环境满足某种条件时就会执行某种功能。⑤ 后门入侵,利用系统漏洞通过网络入侵。

  • 拒绝服务DoS

    DoS 攻击使网络、主机不能由合法用户使用,电子邮件服务器、DNS 服务器和机构都可能成为攻击目标。

    DoS 包括:① 弱点攻击,向目标主机上运行的易受攻击的应用程序或操作系统发送精细制作的报文。② 带宽洪泛,攻击者向目标主机发送大量分组,使其接入链路变得阻塞导致分组无法到达服务器。③ 连接洪泛,在目标主机创建大量 TCP 连接,主机因这些伪造的连接而陷入阻塞。

  • ARP欺骗

    攻击者向以太网交换机发送大量伪造的源 MAC 地址,以太网交换机把虚假的 MAC 地址填入到交换表中,导致交换机无法正常工作。

对于被动攻击可以采用数据加密技术,对于主动攻击则需要将加密技术与鉴别技术相结合。

安全的计算机网络特性:

  • 机密性

    仅有通信双方能理解传输内容,报文必须加密使截获者无法理解。

  • 报文完整性

    通信内容在传输过程中需要确保未被篡改。

  • 端点鉴别

    通信双方都能证实另一方的身份。

  • 运行安全性

    几乎所有机构都与互联网相连,需要通过访问控制确保安全性,防火墙位于机构和公共网络之间,控制通过网络的分组;入侵检测系统执行分组检查任务,检测可疑活动。


密码技术⭐

密码技术使发送方可以伪装数据,入侵者不能从截获到的数据中获得有效信息。

对称密钥密码体制

使用相同的加密密钥和解密密钥,运算速度快,但安全性差。使用对称密钥时,在通信信道上可以进行一对一的双向保密通信,每一方既可以用该密钥加密明文,也可以解密密文。这种保密通信仅限于持有此密钥的双方。

公开密钥密码体制

使用公钥进行加密,私钥进行解密,公钥是任何人都可以得知的,而私钥是通信双方独有的。运算速度慢,但是安全性好。最常见的公钥加密算法是 RSA,它使用两个大素数 p 和 q 生成密钥,pq 的值越大破解难度越大,但耗时也越长。使用公开密钥时,在通信信道上是多对一的单向保密通信,可以同时有很多客户利用公钥对报文加密后发送给服务器,服务器利用其私钥可以对收到的密文一一解密,但如果是反方向则行不通,例如网购时很多客户都向同一网站发送各自的信用卡信息。


数字签名⭐

作用

报文鉴别:接收者可以确认报文发送方的身份。

报文完整性:接收者可以确信报文内容没有被篡改过。

不可否认:发送者事后不能抵赖对报文的签名。

实现原理

用私钥对报文进行 D 运算得到密文,接收方会利用发送方的公钥进行 E 运算还原出明文。

  • 报文鉴别:除了发送方外没有人持有其私钥,无法产生发送方才能产生的密文。

  • 报文完整性:如果其他人篡改过密文,解密出的明文就会不可读。

  • 不可否认:如果发送方抵赖发送过报文,接收方可以把初始报文和密文发送给公证的第三者,第三者通过公钥进行验证。

公钥认证

攻击者可能会发送使用自己私钥加密的密文和自己的公钥来伪造发送方的身份,该问题通过 CA 解决,发送方在发送数据时也会发送 CA 签署的证书,接收方会利用 CA 的公钥核实发送方证书的合法性并提取发送方的公钥。

CA 即认证中心,将公钥与特定的实体绑定, 职责是使识别和发行证书合法化。CA 认证一个实体的真实身份,生成一个将其身份和实体的公钥绑定起来的证书,证书包含了这个公钥和公钥所有者全局唯一的身份标识信息(例如一个人名或一个 IP)。


报文鉴别

报文鉴别就是鉴别收到的报文确实是期望的发送方发送的,而不是别人伪造的。

数字签名可以实现报文鉴别,但缺点是对较长报文进行签名时需要长时间的运算。有一种相对简单的报文鉴别方式,即密码散列函数,要找到两个不同的报文,它们具有相同的密码散列函数输出,在计算上是不可行的。

使用散列函数进行报文鉴别

通信双方共享一个密钥 k ,发送方生成报文 m,用 k 级联 m 生成 m+k,并使用 SHA-1 或 MD5 这样的散列函数计算 m+k 的散列值 h,这个散列值就被称为报文鉴别码 MAC。发送方会利用 MAC 生成扩展报文并发送给接收方。接收方收到后,由于知道共享密钥 k,因此可以计算出 MAC,如果和 h 相等就可以得出一切正常的结论。


端点鉴别

端点鉴别主要通过鉴别协议 ap 实现,鉴别协议通常在两个通信实体运行其他协议之前运行,仅当鉴别完成后各方才继续下面的工作。

ap1.0:发送方直接发送报文说明身份,攻击者可以任意伪造。

ap2.0:接收方验证 IP 数据报的源地址和发送方常用地址是否匹配来进行鉴别。存在 IP 欺骗的可能性,攻击者可以伪造源 IP 地址。

ap3.0:接收方会要求发送方提供口令进行验证,但依旧不安全,因为攻击者能通过嗅探获得口令并不断重放。

ap4.0:重放攻击主要是由于接收方并不知道此时发送方是否活跃,ap4.0 通过不重数防止重放攻击。接收方会向发送方发送一个不重数,发送方将其加密后发回给接收方,接收方通过验证这个数字来判断发送方是否活跃。


安全协议

网络层

IPsec 是能够为两个网络实体提供通信安全的协议族,没有限定用户必须使用的加密算法,许多机构都使用 IPsec 保证 VPN 的安全性。

IPsec 有两个主要协议:鉴别首部 AH 和封装安全有效载荷 ESP。AH 提供源鉴别和数据完整性服务,而 ESP 除了这两种服务外还提供机密性服务,因此使用比 AH 广泛。使用 AH 或 ESP 的 IP 数据报称为 IP 安全数据报,IP 安全数据报有两种工作方式:① 运输方式,在整个运输层报文段的前后分别加上控制信息,再加上 IP 首部。② 隧道方式,在原始 IP 数据报的前后分别加上控制信息,这种方式使用较多。

运输层

运输层的安全协议主要是 SSL 和 TLS ,TLS 是 SSL3.0 的修改版本。SSL 主要作用在端系统的 HTTP 和运输层之间,在 TCP 上建立起一个安全通道,为 TCP 传输数据提供安全保障。

SSL 提供的安全服务包括:服务器鉴别,允许用户证实服务器的身份,支持 SSL 的客户端通过验证来自服务器的证书鉴别服务器的身份并取得服务器的公钥;客户鉴别,SSL 可选的安全服务,允许服务器验证用户的身份;加密的 SSL 会话,对客户和服务器发送的所有报文进行加密,检测报文是否被篡改。


防火墙和入侵检测

在计算机网络中,当通信流量进出网络时要执行安全检查、记录、丢弃或转发,这些工作由防火墙和入侵检测系统完成。

防火墙

防火墙严格控制进出网络的分组,禁止任何不必要通信,从外部到内部和从内部到外部的所有流量都必须经过防火墙。

防火墙分为三种:① 基于分组过滤,分组过滤器独立地检查每个数据报,然后基于特定规则决定该数据报应当通过还是丢弃,过滤因素包括 IP 地址、TCP 或 UDP 的端口等。② 基于状态过滤,利用一张连接表跟踪 TCP 连接,通过跟踪信息决定。③ 应用程序网关,一个应用程序特定的服务器,所有数据都必须通过它。

入侵检测系统 IDS

防火墙不能阻止所有入侵,入侵检测系统作为第二道防线,对网络分组进行深度分析与检测从而发现异常行为。

  • 基于特征的 IDS

    维护一个攻击特征数据库,每个特征是一个与入侵活动关联的规则集,基于特征的 IDS 嗅探通过它的每个分组,将分组中的数据与数据库中的特征进行比较,如果匹配将产生一个警告,缺点是无法应对新型攻击。

  • 基于异常的 IDS

    观察正常运行的网络流量,学习正常流量的统计特性和规律,当检测到网络中流量的某种统计规律不符合正常情况时则认为可能发生了入侵行为,区分正常流量和统计异常流量非常困难 ,大多数 IDS 都是基于特征的。


缓存⭐

概念

当需要频繁访问用户信息等热数据时,为了加快响应速度往往会把数据缓存在内存中,这样再次访问数据时直接从内存中获取即可,降低了后端的负载。

  • 处理写请求时先将数据写入数据库,然后写入缓存。
  • 处理读请求时首先尝试从缓存获取,如果失败则从数据库查询并将结果缓存。

缓存更新策略

缓存数据会和真实数据有一段时间的不一致,需要利用某种策略进行更新。低一致性业务建议配置最大内存并使用算法剔除,高一致性业务可以结合超时剔除和主动更新,即使主动更新出错也能保证数据过期后删除脏数据。

算法剔除

  • FIFO 先进先出

    判断存储时间,离当前时间最远的数据优先淘汰。

    新数据插入队列尾部,数据在队列中顺序移动;淘汰队列头部的数据。

  • LRU 最近最少使用

    判断最近使用时间,离当前时间最远的数据优先被淘汰。

    新数据插入到队列头部;每当缓存命中则将数据移到队列头部;当队列满的时候,将队列尾部的数据丢弃。

  • LFU 最不经常使用

    在一段时间内,被使用次数最少的数据优先淘汰。LFU 的每个数据块都有一个引用计数,所有数据块按照引用计数排序,具有相同引用计数的数据块按时间排序。

    新数据插入到队列尾部;数据被访问后引用计数增加,队列重新排序;当需要淘汰数据时,将队列尾部数据删除。

剔除算法常用于缓存使用量超过预设最大值时对现有数据进行剔除,数据一致性最差。


2 超时剔除

通过给缓存设置过期时间实现,例如 Redis 的 expire 命令。如果业务可以容忍一段时间内缓存数据和真实数据不一致,可以为其设置过期时间,在数据过期后再从数据源获取数据,更新缓存并设置过期时间。数据一致性较差。


3 主动更新

在真实数据更新后立即更新缓存,可以利用消息系统实现。数据一致性强,但如果主动更新出错会导致脏数据,建议结合超时剔除使用。


缓存穿透

缓存穿透指查询不存在的数据,缓存层和存储层都不会命中。过程:① 缓存层不命中。② 存储层不命中,不将空结果写回内存(出于容错考虑)。③ 返回空结果。

缓存穿透将导致不存在的数据每次请求都要到存储层查询,可能会使后端负载增大,由于很多后端存储不具备高并发性,甚至可能造成后端宕机。通常在程序中分别统计总调用数、缓存命中数、存储层命中数,如果发现大量存储层空命中,说明可能出现了缓存穿透。

产生原因:自身业务代码或数据出现问题; 一些恶意攻击、爬虫等造成大量空命中。

解决方法:

  • 缓存空对象:如果一个查询返回结果为 null,仍然缓存 null 结果,但其过期时间很短,通常不超过 5 分钟。
  • 布隆过滤器:将所有可能存在的数据映射到一个足够大的 Bitmap 中,在用户发起请求时首先经过布隆过滤器的拦截,一个一定不存在的数据会被拦截。

缓存击穿

对于热数据的访问量非常大,在其缓存失效的瞬间,大量请求直达存储层,导致服务崩溃。

解决:

  • 加锁互斥:当一个线程访问后,缓存中数据会被重建,其他线程就可以从缓存中取值。
  • 永不过期:为热点数据不设置过期时间。

缓存雪崩

如果缓存层因为某些问题不能提供服务,所有请求都会到达存储层,对数据库造成巨大压力。

解决方法:

  • 保证缓存层服务的高可用性:使用集群,即使个别节点宕机仍然可以提供服务。
  • 依赖隔离组件为后端限流并降级:对重要资源进行隔离,让每种资源单独运行在自己的线程池中,即使个别资源出现问题,对其他服务没有影响,例如 Java 中的隔离工具 Hystrix。降级机制在高并发系统中使用普遍,例如在推荐服务中,如果个性化推荐服务不可用,可以降级补充热点数据,避免前端页面空白。
  • 构建多级缓存:增加本地缓存,在存储层前多加一层屏障,降低请求直达存储层概率。

CDN⭐

CDN 内容分发网络,指基于部署在各地的服务器,通过中心平台的负载均衡、内容分发,使用户就近获取所需内容,降低网络延迟。

关键技术:

  • 内容发布:借助缓存、组播等技术,将内容发布到网络上距离用户最近的中心机房。
  • 内容路由:通过内容路由器中的重定向机制,在多个中心机房的服务器上负载均衡用户的请求。
  • 内容交换:根据内容可用性、服务器可用性及用户背景,在缓存服务器上利用应用层交换、流分裂等技术,平衡负载流量。
  • 性能管理:通过监控系统,获取网络信息,测量内容发布的端到端性能(延时、包丢失、平均带宽等),保证网络处于最佳状态。

特点:

  • 缓存加速:将用户经常访问的数据缓存在本地,提升响应速度。
  • 镜像服务:消除不同运营商之间的网络差异,实现跨运营商的网络加速。
  • 远程加速:利用负载均衡为用户选择高质量服务器,加快访问速度。
  • 带宽优化:自动生产服务器的远程镜像缓存,分担流量,降低原站点负载。

操作系统

进程

进程是程序的一次执行过程,是系统进行资源分配和调度的一个独立单位,目的是为了更好地描述和控制程序的并发执行。

结构 说明
进程控制块 PCB 进程存在的唯一标识,包括进程描述信息、控制信息、资源分配信息等。
程序段 能被进程调度到 CPU 执行的代码。
数据段 进程对应的程序加工处理的原始数据。

进程特征

特征 说明
动态性 进程最基本的特征,进程是程序的一次执行,具有一定的生命周期。
并发性 多个进程可以同时存在于内存中,在一段时间内同时运行。
独立性 进程是一个能独立运行、独立接受调度的单位。
异步性 进程按不可预知的速度推进。

进程状态

状态 说明
创建态 进程正在被创建,尚未转到就绪态。
就绪态 进程已处于准备运行的状态,获得了除处理机外的一切资源。
运行态 进程正在处理机上运行。
阻塞态 进程正在等待某一事件而暂停运行,如等待某资源可用或等待 IO 流完成。
结束态 进程正常结束或中断退出。

进程控制

进程的创建

过程:

  • 为新进程分配一个唯一的进程标识号,并申请一个空白的 PCB,若申请失败则创建失败。

  • 为新进程的程序和数据分配内存空间,若资源不足会进入阻塞态。

  • 初始化 PCB,主要包括标志信息、处理机状态信息、以及设置进程优先级等。

  • 若进程就绪队列未满,就将新进程插入就绪队列,等待被调度运行。


进程的终止

进程终止包括:正常结束,表示进程已经完成并准备退出;异常结束,表示进程在运行时发生异常,程序无法继续运行,例如非法指令,IO 故障等;外界干预,指进程因为外界请求而终止,例如操作系统干预等。

过程:

  • 根据被终止进程的标识符,检索 PCB,读出该进程的状态。
  • 若被终止的进程处于执行状态,终止执行,将处理机资源分配给其他进程。
  • 若进程还有子进程,将所有子进程终止。
  • 将该进程的全部资源归还给父进程或操作系统,并将 PCB 从队列删除。

进程的阻塞与唤醒

正在执行的进程由于等待的事件未发生,由系统执行阻塞原语,由运行态变为阻塞态。

阻塞过程:

  • 找到将要被阻塞进程的 PCB。
  • 如果进程为运行态,保护现场并转为阻塞态,停止运行。
  • 把 PCB 插入相应事件的等待队列,当被阻塞进程期待的事件发生时,由相关进程调用唤醒原语,将进程唤醒。

唤醒过程:

  • 在该事件的等待队列中找到进程对应的 PCB。
  • 将其从等待队列中移除,设置状态为就绪态。
  • 将 PCB 插入就绪队列,等待调度程序调度。

进程切换

进程切换是指处理机从一个进程的运行转到另一个进程上运行。

进程切换过程:

  • 保存处理机上下文,包括程序计数器和其他寄存器。
  • 更新 PCB 信息,并把 PCB 移入相应的阻塞队列。
  • 选择另一个进程执行并更新其 PCB。
  • 更新内存管理的数据结构,恢复处理机上下文。

进程通信⭐

管道通信

Linux 里的 | 就是一个管道,功能是将前一个命令的输出作为后一个命令的输入。

管道通信中存储空间是内核缓冲区,只允许一边写、另一边读,只要缓冲区有数据,进程就能读出。写进程会先将缓冲区写满才让读进程读,当缓冲区还有数据时,写进程不会往缓冲区写数据。因此管道是半双工通信,效率低,不适合进程间频繁交换数据。

消息队列

消息队列是保存在内核中的消息链表,消息的发送方和接收方要约定好消息体的数据类型,每个消息体都是固定大小的存储块,不像管道是无格式的字节流。如果进程从消息队列中读取了消息体,内核就会把这个消息体删除。消息队列的通信效率高于管道,进程发送消息时,把数据放在消息队列后就可以正常返回。

消息队列不适合较大数据的传输,因为内核中每个消息体都有最大长度限制。此外,消息队列通信存在数据拷贝开销,进程写数据到消息队列时,会发生从用户态拷贝数据到内核态的过程,读取数据时,会发生从内核态拷贝数据到用户态的过程。

共享内存

共享内存解决了消息队列中用户态与内核态间的数据拷贝问题,将虚拟地址空间映射到相同的物理内存,当某个进程写数据时,另一个进程马上就能看到,不需要拷贝,提高通信效率。


线程

线程是进程中的一个实体,是操作系统独立调度和分配的基本单位,由线程 ID、程序计数器、寄存器集合和堆栈组成。引入线程是为了减少程序并发执行的开销,进一步提高操作系统的并发性能。

线程和进程的区别⭐

调度: 进程是分配资源的基本单位,而线程是独立调度的基本单位。

资源: 进程拥有系统资源,而线程只有一点运行必需的资源。如果线程也是分配资源的单位,切换就需要较大开销,引入没有意义。

开销: 进程切换涉及当前 CPU 环境的保存和设置,但线程切换只需要保存和设置少量的寄存器容量。

地址空间: 进程的地址空间互相独立,同一进程的线程共享进程资源,进程内的线程对其他进程不可见。

通信: 进程通信需要同步和互斥手段的辅助,保证数据一致性。线程可以直接读写进程数据段(全局变量)来进行通信。


线程实现

内核级线程 1:1 实现

内核通过操纵调度器对线程进行调度,并将线程的任务映射到处理器上。程序一般不会直接使用内核线程,而是使用内核线程的一种高级接口,轻量级进程,即通常意义上的线程。

优点:当一个线程被阻塞时,允许其他线程继续执行。

缺点:代价相对较高,需要在用户态和内核态来回切换。


用户级线程 1:N 实现

从广义上讲,一个线程只要不是内核线程,就可以认为是用户线程。狭义上的用户线程指的完全建立在用户空间的线程库上,系统内核不能感知到用户线程的存在及其是如何实现的。

优点:由于线程管理在用户空间进行,不需要切换到内核态,开销小,支持大规模并发。

缺点:一个线程在使用内核服务时被阻塞,整个进程都会被阻塞。


混合方式 N:M 实现

混合模式下既存在用户线程,也存在轻量级进程。用户线程完全建立在用户空间中,因此开销依然很小,可以支持大规模并发。轻量级进程作为用户线程和内核线程之间的桥梁,使用内核提供的线程调度功能及处理器映射,降低整个进程阻塞的风险。


死锁⭐

死锁就是指多个进程因为互相竞争资源而造成的一种互相等待的僵局,若无外力作用,这些进程都无法继续向前推进。

死锁的原因

不可剥夺资源数量的不足,如打印机,对可剥夺资源的竞争不会造成死锁。

进程请求和释放资源的顺序不当,例如进程 P1 和 P2 分别占用资源 R1 和 R2,而此时 P1 和 P2 又分别申请资源 R2 和 R1。

信号量的使用不当,进程间彼此互相等待对方发来的消息,也会使进程无法推进。

必要条件

互斥条件:进程对资源的占有具有排它性,如果进程请求的资源已被占用,请求就会被阻塞。

不可剥夺条件:进程获得的资源没有使用完成前,不能被其它进程强行获取,只能由占有它的进程主动释放。

请求和保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源已被其它进程占有,此时请求被阻塞,但进程也不会释放自己已经占有的资源。

循环等待条件:存在一个进程资源的循环等待链,链中每个进程已经占有的资源同时是其他进程请求的资源。


死锁处理

预防

  • 破坏互斥条件

    允许系统资源共享,但有的资源不可能同时访问,如打印机等临界资源。

  • 破坏不可剥夺条件

    允许剥夺其他进程已占有的资源,但释放已获得的资源可能会造成前一段工作的失效。

  • 破坏请求和保持条件

    采用预先资源分配法,在进程运行前一次性分配它需要的所有资源,缺点是有些资源可能仅在运行初期或快结束时才使用。

  • 破坏循环等待条件

    采用顺序资源分配法, 给系统资源编号,规定每个进程必须按编号递增的顺序请求资源。


避免

同样属于事先预防,但并不是事先采取某种限制措施,而是动态地根据情况处理。

  • 系统安全状态

    不安全状态可能会导致死锁,如果一次分配不会导致系统进入不安全状态,则将资源分配给进程,否则就让进程等待。

    安全状态是指系统能按照某种进程推进顺序为每个进程分配资源,直到满足每个进程对资源的需求。

  • 银行家算法

    把操作系统视为银行家,资源视为资金,进程向操作系统申请资源相当于用户向银行家贷款。操作系统按照规则为进程分配资源,当进程首次申请资源时,要测试系统现存资源能否满足其最大需求量,可以则按申请量分配,否则推迟分配。

    当进程在执行中继续申请资源时,先测试该进程已占有的资源数与申请的资源数之和是否超过该进程对资源的最大需求量,如果超过则拒绝分配,否则再测试系统现存的资源能否满足该进程尚需的最大资源量,如果满足则按申请量分配,否则推迟分配。


检测

系统死锁可用资源分配图描述,圆圈表示进程,框表示资源。从进程到资源的有向边是请求边,从资源到进程的边是分配边。

简化资源分配图可以检测系统状态是否为死锁状态。在资源分配图中,找出既不阻塞也不孤立的进程,消去它的所有请求边和分配边,使之成为孤立的点。如果系统状态不可被完全简化,那么代表死锁。


解除

  • 资源剥夺法

    挂起某些死锁进程,抢占其资源,分配给其它死锁进程。

  • 撤销进程法

    强制撤销部分甚至全部死锁进程,可以按进程优先级和撤销代价进行。

  • 进程回退法

    让一个或多个进程回退到足以避免死锁的地步,要求系统保持进程的历史信息,设置还原点。


Java 基础

语言特性

优点

① 平台无关,摆脱硬件束缚,“一次编写,到处运行”。

② 安全的内存管理和访问机制,避免大部分内存泄漏和指针越界。

③ 热点代码检测和运行时编译优化,程序随运行时长获得更高性能。

④ 完善的应用程序接口,支持第三方类库。


平台无关⭐

JVM: 编译器生成与计算机体系结构无关的字节码,字节码文件不仅能在任何机器解释执行,还能动态转换成本地机器码,转换由 JVM 实现。JVM 是平台相关的,屏蔽了不同操作系统的差异。

语言规范: 基本数据类型大小有明确规定,如 int 永远 32 位,而 C/C++ 可能是 16 位、32 位,或编译器开发商指定的其他大小。数值类型有固定字节数,字符串用标准 Unicode 格式。


JDK 和 JRE

JDK: Java Development Kit,开发工具包。提供了编译运行 Java 程序的各种工具,包括编译器、JRE 及常用类库,是 JAVA 核心。

JRE: Java Runtime Environment,运行时环境,运行 Java 程序的必要环境,包括 JVM、核心类库、核心配置工具。


值调用和引用调用

按值调用指方法接收调用者提供的值,按引用调用指方法接收调用者提供的变量地址。

Java 总是按值调用,方法得到的是参数的副本,传递对象时实际上传递的是对象引用的副本。

  • 方法不能修改基本数据类型的参数,例如传递了一个 int 值 ,改变 int 值不会影响实参。

  • 方法可以改变对象参数的状态,但不能让对象参数引用新的对象。例如传递了一个 int 数组,改变数组内容会影响实参,而改变其引用并不会让实参引用新的数组对象。


浅拷贝和深拷贝

浅拷贝只复制当前对象的基本数据类型及引用变量,没有复制引用变量指向的实际对象。修改克隆对象可能影响原对象。

深拷贝完全拷贝基本数据类型和引用数据类型,修改克隆对象不会影响原对象。


反射

在运行状态中,对于任意一个类都能知道它的所有属性和方法,对于任意一个对象都能调用它的任意方法和属性,这种动态获取信息及调用对象方法的功能称为反射,缺点是破坏了封装性及泛型约束。


Class 类

在程序运行期间,Java 运行时系统为所有对象维护一个运行时类型标识,这个信息会跟踪每个对象所属的类,虚拟机利用运行时类型信息选择要执行的正确方法,保存这些信息的类就是 Class,这是一个泛型类。

获取 Class 对象:① 类名.class 。② 对象的 getClass方法。③ Class.forName(类的全限定名)


注解⭐

注解是一种标记,使类或接口附加额外信息,帮助编译器和 JVM 完成一些特定功能,例如 @Override 标识一个方法是重写方法。

元注解是自定义注解的注解,例如:

@Target:约束作用位置,值是 ElementType 枚举常量,包括 METHOD 方法、VARIABLE 变量、TYPE 类/接口、PARAMETER 方法参数、CONSTRUCTORS 构造方法和 LOACL_VARIABLE 局部变量等。

@Rentention:约束生命周期,值是 RetentionPolicy 枚举常量,包括 SOURCE 源码、CLASS 字节码和 RUNTIME 运行时。

@Documented:表明注解应该被 javadoc 记录。


泛型

泛型本质是参数化类型,解决不确定对象具体类型的问题。

泛型的好处:① 类型安全,不存在 ClassCastException。② 提升可读性,编码阶段就显式知道泛型集合、泛型方法等处理的数据类型。

泛型用于编译阶段,编译后的字节码文件不包含泛型类型信息,因为虚拟机没有泛型类型对象,所有对象都属于普通类。例如定义 List<Object>List<String>,在编译后都会变成 List


JDK8 新特性

**lambda 表达式:**允许把函数作为参数传递到方法,简化匿名内部类代码。

**函数式接口:**使用 @FunctionalInterface 标识,有且仅有一个抽象方法,可被隐式转换为 lambda 表达式。

**方法引用:**可以引用已有类或对象的方法和构造方法,进一步简化 lambda 表达式。

**接口:**接口可以定义 default 修饰的默认方法,降低了接口升级的复杂性,还可以定义静态方法。

**注解:**引入重复注解机制,相同注解在同地方可以声明多次。注解作用范围也进行了扩展,可作用于局部变量、泛型、方法异常等。

**类型推测:**加强了类型推测机制,使代码更加简洁。

**Optional 类:**处理空指针异常,提高代码可读性。

**Stream 类:**引入函数式编程风格,提供了很多功能,使代码更加简洁。方法包括 forEach 遍历、count 统计个数、filter 按条件过滤、limit 取前 n 个元素、skip 跳过前 n 个元素、map 映射加工、concat 合并 stream 流等。

**日期:**增强了日期和时间 API,新的 java.time 包主要包含了处理日期、时间、日期/时间、时区、时刻和时钟等操作。

**JavaScript:**提供了一个新的 JavaScript 引擎,允许在 JVM上运行特定 JavaScript 应用。


异常

总结-互联网校招面试锦囊相关推荐

  1. 2021一线互联网校招面试真题解析,看完这一篇你就懂了

    前言 JavaScript是面向 Web 的编程语言,获得了所有网页浏览器的支持,是目前使用最广泛的脚本编程语言之一,也是网页设计和 Web 应用必须掌握的基本工具. JavaScript主要用途 嵌 ...

  2. java工程师面试宝典_【Java工程师面试宝典】学习说明_互联网校招面试真题面经汇总_牛客网...

    ● 请你讲讲Java里面的final关键字是怎么用的? 考察点:关键字 参考回答: 当用final修饰一个类时,表明这个类不能被继承.也就是说,如果一个类你永远不会让他被继承,就可以用final进行修 ...

  3. c语言socket面试题,【C++工程师面试宝典】学习说明_互联网校招面试真题面经汇总_牛客网...

    ● 请你讲述一下互斥锁(mutex)机制,以及互斥锁和读写锁的区别 参考回答: 1.互斥锁和读写锁区别: 互斥锁:mutex,用于保证在任何时刻,都只能有一个线程访问该对象.当获取锁操作失败时,线程会 ...

  4. 某视频互联网企业 校招面试

    单位是国内某著名视屏网站企业,本人是视频编解码专业相关,比较感兴趣,还认真准备了下,投的是c++研发,面试途中才发现接收内推的部门是做推荐系统的,要求的技能其实和web后台开发差不多. 面试挺久的下午 ...

  5. 同学,你有一份来自支付宝AI学姐的面试锦囊待查收

    简介: 这里有创造未来的技术,这里有蚂蚁最丰富的场景,这里有挑战也有机遇,还有为你助力的师兄师姐.此时此刻,非你莫属!期待你们的到来! 就现在!蚂蚁「校招季」重磅来袭!除了介绍蚂蚁的技术大咖,我们还邀 ...

  6. B 站校招面试官“炫耀资产、贬低应试者”?当事人发长文回应,北邮学子要求向学校道歉

    ‍ 作者 | Carol 出品 | CSDN(ID:CSDNnews) 数十个企业展位.诱人的薪酬福利宣传单.一个个手持简历的学子--小伙伴们应该很熟悉这样的场景,没错,"金三银四" ...

  7. B站校招面试官“炫耀资产、贬低应试者”?当事人发长文回应,北邮学子要求向学校道歉...

    作者 | Carol 出品 | CSDN(ID:CSDNnews) 数十个企业展位.诱人的薪酬福利宣传单.一个个手持简历的学子--小伙伴们应该很熟悉这样的场景,没错,"金三银四"的 ...

  8. 非计算机毕业生2015互联网校招求职之路(拿到腾讯阿里offer)

    0. 写在前面 以此文,献给自己这两年的青葱岁月,感谢淘宝的朗英师兄和微博的旭爷.全栈pm莹姐姐.酷炫石女王.以及我逝去的头发. 参照Lucida的<9个offer,12家公司,35场面试... ...

  9. 《非计算机毕业生2015互联网校招求职之路》2014-10-15

    0. 写在前面 以此文,献给自己这两年的青葱岁月,感谢淘宝的朗英师兄和微博的旭爷.全栈pm莹姐姐.酷炫石女王.以及我逝去的头发. 参照Lucida的<9个offer,12家公司,35场面试... ...

最新文章

  1. 运行在CentOS7.5上的Django项目时间不正确问题
  2. java datetime int_关于jodatime:Java中DateTime对象之间的小数天数
  3. f12控制台如何查看consul_Consul初探-从安装到运行
  4. MySQL-InnoDB究竟如何巧妙实现,4种事务的隔离级别
  5. python datetime datetime
  6. crt安装mysql教程_Centos系统安装MySQL详细图文教程
  7. 转载:VS2005 工具方便实用的快捷键。
  8. linux 共享内存 信号量 同步
  9. 基于51单片机的DHT11传感器
  10. echarts结合百度地图实现迁徙图效果
  11. 什么是 Scrum 中的 Timeboxing?
  12. java打开客户端程序_Java客户端服务器应用程序 - 已在使用的地址:connect
  13. Android手机电池耐用吗,手机电池是否还耐用?一招教你识别
  14. UICollectionView左对齐
  15. powerbuilder的dw中使用graph风格,当横轴是日期时,如何显示才能完整显示日期?
  16. beta阶段贡献分配实施
  17. 【前端三剑客三】 JavaScript
  18. 命令行执行 mvn package 和常见mvn命令
  19. element UI 模态层dialog自定义大小
  20. POJ 2245 Addition Chains(算竞进阶习题)

热门文章

  1. 疑难杂症:同网段ping不通,跨网段建不了链,怎么破?
  2. 【python】png转jpg(pillow)
  3. 工商银行u盾 java_中国工商银行u盾怎么用
  4. python中arcsec_在Python类中继承Cython类
  5. 使用WebRTC搭建前端视频聊天室-01——入门篇
  6. 证据权重 (WOE) 与信息价值 (IV)
  7. unity3d 中控制手机前后摄像头切换
  8. JavaSE进阶 | final关键字、抽象类和接口
  9. 修改树莓派的CoD(即蓝牙识别类型)
  10. 转贴汪应果先生的“全球华人应该向大陆中国人学什么?”