# 计网&操作系统

## 计网面试常见问题

自上而下的五层网络结构划分及其作用

应用层：应用层主要是保证应用进程之间的通信和交互规则，应用层协议有：DNS（域名系统，完成域名到操作系统的一个映射），HTTP（超文本传输协议，互联网上运用最为广泛的协议，所有的WWW文件必须遵从这个标准），SMTP（电子邮件发送协议，保证电子邮件的安全送达）

运输层：主要是负责为应用层提供数据传输服务，保证数据的传输，主要协议有TCP（面向连接的，可靠的数据传输服务）、UDP（无连接的，尽最大可能交付的数据传输服务）

网络层：确保数据可以选择到合适的网络路由和交换节点，确保数据及时送达，主要是IP协议和一些路由选择协议，传送IP数据报

数据链路层：保证相邻节点间的数据传输，将IP数据报封装成帧，这里需要进行差错检测，确保每个帧都是正确地，但不确保是否有帧丢失或者是帧乱序

物理层：实现比特流的透明传输，屏蔽底层的传播介质和物理设别之间的差异，发送的信息单位是比特

**TCP三次握手和四次握手**

基本是必问了，主要是确保TCP连接安全的建立和释放

三次握手：建立可靠的连接，**确认双方的数据发送和接收是正常的**

Client——带有SYN标志的数据包（TCP包）——>Server：Server端确认了对方发送正常，自己接收正常

Client<——带有SYN和ACK标志的数据包——Server：Client确认了自己发送正常，自己接收正常，对方发送正常，对方接收正常，Server端确认了对方发送正常，自己接收正常

Client——带有ACK标志的数据包——>Server：Client确认了自己发送正常，自己接收正常，对方发送正常，对方接收正常，Server端确认了自己发送正常，自己接收正常，对方发送正常，对方接受正常

> 整体上看，第二部的Server——Client的SYN标志就比较奇怪了，这里SYN是为了建立并确认从服务端到客户端的通信

![这里写图片描述](https://img-blog.csdn.net/20180528233114199?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3h1emhhbmd6ZQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)

四次握手：连接的正确释放

Client——带有FIN标志的数据报——>Server：关闭Client到Server的数据传输

Client<——带有ACK标志的数据报——Server：

Client<——带有FIN标志的数据报——Server：关闭Server与Client的数据连接

Client——带有ACK标志的数据报——Server：

**所有传ACK主要是为了表明我接受到的信息确实是你所发出的，一种确认机制**

![这里写图片描述](https://img-blog.csdn.net/20180528233131709?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3h1emhhbmd6ZQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)

TCP和UDP的比较

|       TCP       |     UDP     |
| :-------------: | :---------: |
|     面向连接，可靠     |   无连接，不可靠   |
|       字节流       |    用户数据报    |
|      传输效率低      |    传输效率高    |
| TCP报文需要20-60个字节 | UDP报文需要8个字节 |

TCP保证可靠传输的方法

1、校验和：除去首部前面的8字节用于存储源IP、目的IP、源端口、目的端口信息，剩下的12字节用于存储校验和信息【对报文段信息取反码】

2、序列号：会对发送的报文段进行编号，保证报文顺序，数据的不丢不重【连续ARQ协议】

3、超时重传：发送时候会设定一个计时器，如果在计时器走完之后还是没有接收到ACK确认消息，那么此时会认为超时了，会重新发送

4、流量控制：根据接收窗口的大小来调整发送窗口的大小，来避免接收端无法来得及接收所有发送端发送出来的数据，导致报文段丢失的问题

5、拥塞控制：维护一个拥塞窗口的大小，算法为

慢开始（一个传输轮次，拥塞窗口大小Double）——拥塞避免（拥塞窗口达到慢开始门限，拥塞窗口和慢开始门限都++）——快重传快恢复（连续3个ACK，立即重发，不必等待超时计时器【快重传】慢开始门限设置成当前拥塞窗口大小的一半，拥塞窗口大小设置成慢开始门限【快恢复】）

重传涉及到ARQ协议（自动重传请求，TCP层），属于错误纠正协议，通过确认和超时这两个机制保证了数据的可靠传输，主要分为停止等待ARQ协议和连续ARQ协议

接收方在接收到TCP数据报的时候都会返回一个确认号，也就是带有ACK标志的数据报

停止等待ARQ和连续ARQ唯一的区别就是停止等待会发送一个TCP数据报，然后等着确认，而连续ARQ协议则是利用发送窗口和接收窗口将一组TCP数据报直接发出去，对方会回最后一个的确认号，这里也正是可以通过滑动窗口来进行流量控制的关键。

拥塞控制是为了防止过多的数据进入到网络中来，导致网络过载，又不断重试导致网络环境越来越差的过程控制，一般会维护一个拥塞窗口，这样在发送的时候会计算拥塞窗口与接收窗口的较小值作为发送窗口的大小，以此来减少数据的发送，主要有四种算法：慢开始（拥塞窗口大小翻倍）、拥塞避免（加一）、快重传与快恢复。

**浏览器输入URL地址到出现页面的过程**

围绕这个思路扯就差不多了

DNS解析获取IP地址——与目标IP地址建立TCP连接（使用到了IP、OSPF（最优的路由器数据传输）、ARP（IP与MAC的转换））——客户端发送HTTP请求——服务器响应HTTP报文——浏览器进行页面渲染——断开TCP连接（HTTP1.0）

状态码

1打头的：信息性状态码，表示请求正在处理

2打头的：成功状态码，表示正常处理完成

3打头的：重定向状态码，需要进行附加操作来完成请求

4打头的：客户端错误状态码，服务器无法处理请求

5打头的：服务器错误状态码，服务器处理请求出错

长连接与短连接

长连接HTTP1.1会设置一个超时时间，只要在这个超时时间之内都会使用同一条TCP连接，不会被回收

短连接HTTP1.0表示每进行一次HTTP操作都会建立一次连接，因此如果访问一个HTML网页，然后其中包含图像，JS文件等，每次加载都需要重新建立TCP连接

HTTP请求是无状态的，不会对请求和响应之间的通信状态进行保存，因此使用Session在服务器内部来维持状态，请求时候通过使用Cookie内部携带一个JSESSIONID属性完成与Session的映射，如果Cookie被禁用了可以将JSESSIONID作为参数传递给后端进行手动处理

URL和URI的区别

URL：统一资源定位符，是更具体的URL，指明了资源的locale，绝对路径

URI：统一资源标志符，可以唯一标识一个资源，相对路径

HTTP和HTTPS的比较

端口：80和443

安全性：HTTP直接进行明文传输，HTTPS传输的是进行加密之后

资源消耗：毋庸置疑HTTP资源消耗低

HTTP协议是直接使用传输层来进行数据的传输，，HTTPS则是先和安全层（SSL/TLS）进行通信，然后安全层在完成对传输层的通信

之所以需要对HTTP数据进行一个加密，主要是为了避免如下几个问题：

1、窃听风险：HTTP直接使用明文，非常容易被第三方窃听（kali Linux中集成了大量的工具来完成对子网的数据的窃听）

2、冒充风险：不会实现对对方身份的验证，因此很可能存在伪造

3、篡改风险：可能监听到报文之后然后实现对报文的修改，然后再发送到服务器

> 当然，这些问题都可以在应用层我们自己来进行实现，来避免这些情况的发生

因此可以看到HTTPS较之于HTTP最重要的就是安全层，SSL和TLS，是通过如下几种方法来进行解决的：

1、所有数据都会进行加密传输

分为对称加密和非对称加密

对称加密：

![preview](https://segmentfault.com/img/remote/1460000022950454/view)

在数据发送之前，会先进行client\_random和server\_random生成，同时还会生成一些加密方法，然后客户端和服务端两边都会通过这一系列的加密方法来将client\_random和server\_random混合起来，得到的结果就是客户端与服务器通信的密钥。

当然这种对称加密也是存在问题的，特别是在服务器端和客户端的密钥生成过程中就被监听了，那么第三方也可以通过监听到的信息完成密钥的生成。

非对称加密则是使用公钥+私钥的方式来进行实现的，浏览器对服务器发送数据时候，会使用公钥来完成对数据的加密，然后服务器端使用私钥来完成数据的解密。

但是在服务器向浏览器发送数据的时候，这时候我们是使用私钥完成对数据的加密，浏览器使用公钥完成对数据的解密，但是公钥不是绝对保密的嘛，因此可能会被截获从服务器到浏览器的数据。

HTTPS使用的是对称加密和非对称加密结合的方式来完成的。

2、配备身份验证

3、具备校验机制、防止数据报被篡改

ping指令使用到的命令

如果ping后面跟的是域名，就需要使用DNS协议将域名解析成IP地址，DNS底层使用到了UDP协议

对目标IP发送ICMP协议（主要用于判断网络是否通畅），对获取到的IP地址，查看是否处于同一网段，如果不处于同一网段，需要使用OSPF协议走最短路径，进入目标子网当中

最后使用ARP协议解析出对应的MAC地址，

http请求分类：

主要了解的有四种：GET、POST、PUT、DELETE

GET和POST的主要区别：

1、方法参数：GET直接放在URL当中，存在长度限制，POST存放于Body中，不存在限制

2、安全性：POST更强

## 操作系统面试常见问题

什么是操作系统

操作系统是管理计算机硬件与软件资源的程序，是计算机的基石。操作系统属于系统软件的核心部分，屏蔽底层硬件的复杂性，让上层软件可以直接和操作系统打交道实现对硬件资源如CPU资源、内存资源和外设的调度。

什么是系统调用

就先得说说操作系统运行时候的两种状态：用户态和核态，在用户态运行的程序只能访问用户程序的数据，处于核态运行的程序几乎能够访问所有的系统资源不受限制

此时如果用户态的进程需要使用核态级别的操作（如文件管理，内存管理等），就需要通过系统调用的方式来完成。

线程与进程之间的区别

可以带着JVM的内存模型来说，因为线程之间是存在共享的，就可以说内存模型中共享了哪些数据。

1、进程是资源分配的基本单位、线程是任务调度和执行的基本单位

2、一个进程下面可以包含多个线程，一个进程有且只能从属于一个进程

3、进程之间资源隔离、线程之间资源共享（JVM内存模型）

4、切换而言进程切换消耗资源大、线程切换资源消耗少

主要是因为进程切换涉及到虚拟页表的切换，快表当中所有暂存的数据全部失效，只能去磁盘上面读取映射信息然后装载到快表当中来，比较缓慢，线程切换无关。

进程的状态

和线程类似：NEW RUNNING BLOCKING WAITING TIME\_WAITING TERMINATED

进程间的通信方式

主要有七种：

1、匿名管道：主要用于父子进程和通信进程之间的通信

2、有名管道：补充匿名管道，严格遵循FIFO，可以实现本机任意两个进程通信

3、信号：通知某个等待进程等待的事件已经发生

4、消息队列：类似于管道的通信方式，但是可以承载更多的数据，本质实现就是内核当中的链表

5、信号量，用于进程同步，也算是通信的一种

6、共享内存：需要进程同步机制来保证，最有用的进程间通信方式了

7、套接字：Socket，主要用于客户端与服务端的通信

大体上分为：管道（半双工）、消息队列（全双工）、共享内存和套接字

线程同步方式：锁机制（Synchronized ReentrantLock等）、信号量（Semaphore、CountDownLatch、CyclicBarrier）、事件（Wait/Notify）

进程调度算法：确定进程执行的顺序以保证CPU的利用率

1、先来先服务 2、短作业优先 3、时间片轮转 4、优先级调度 5、多级反馈队列调度算法（平衡前面集中算法）

操作系统的内存管理机制

内存管理机制主要是为了方便的对内存进行回收，分配

主要有以下几种：

块式管理：将内存分成若干大小不同的块，进程需要申请内存时候就去占据其中一个块，内存利用率极低

页式管理：将内存划分为一页一页的形式，大小相同，页较小，因此相比于块式管理提高了利用率

段式管理：和页式管理非常相似，将内存分为一段一段的，但是段大小可以由用户来制定而不是和页式管理一样只能使用固定的页大小

可以分为两大类：分配内存连续（块式管理）和分配内存不连续（页式管理和段式管理）

补充：段页式管理：结合了段式管理和页式管理的优点，先将主存划分成若干段，然后在段内部划分页信息。

页式管理中需要维持虚拟地址与物理地址之间的转换，需要使用页表来存储映射关系，但是随着内存的增大，页表体积也随之增大，查询速度变慢。于是提出了快表的概念，可以认为快表是页表的cache，可以高速的完成查找。多级页表则是防止页表过大占用大量内存连续空间，于是拆分开来存储，属于时间换空间的方式。

分页和分段的异同

同：对比于分块管理，都提升了内存利用率，减少了内存碎片化的程度，都是离散存储的

异：段可以用户自定，页大小是定死的、分页造成的是内碎片，分段造成的是 外碎片

虚拟内存

操作系统中大量使用到了虚拟技术，虚拟内存可能会比物理内存大得多，常见的实现如使用硬盘空间扩充来作为内存地址，通过虚拟内存，可以让进程感觉到自己在使用一段连续的内存空间，以此来减少程序出错的概率。

![5](https://images.cnblogs.com/cnblogs_com/CareySon/201204/20120425163755141.png)

如果需要的页不在物理内存当中，那么此时会产生一个缺页中断，从磁盘当中读取一个页信息，通过页面置换算法来加载到物理内存当中来。

局部性原理

发现程序执行的时候往往呈现局部性规律，主要包含两个方面：

时间局部性：如果程序中某条指令被执行过，不久后该指令可能被再次执行，如果数据被访问过，可能不久之后又会被访问，产生时间局部性的原因是存在大量循环操作。

空间局部性：一旦程序访问了某个存储单元，在不久之后附近的存储单元也会被访问，因为程序总是顺序存放，顺序执行的，数据也一般以聚合形式存储在一起。

页面置换算法

由于将虚拟内存划分成一个个页，如果请求页不在内存当中，就会发生缺页中断

如果此时内存中所存储页数量达到上限，那么就会使用页面置换算法决定淘汰掉哪一页

* FIFO（First In First Out）：淘汰内存驻留时间最久的页面
* LRU（Least Currently Used）：淘汰最久未使用的，是通过给每个页面维持一个持续时间T，移除T最大的
* LFU（Least Frequently Used）：淘汰掉最少使用的页面
* OPT：最佳页面置换算法，存在于理论当中，移除以后最长时间不会被使用到的页面

孤儿进程和僵尸进程：

孤儿进程指的是没有父进程的进程，因为在Linux环境下进程的产生是父线程调用fork方法来产生的，如果此时父进程执行结束了，那么这些子进程就成为了孤儿进程，操作系统会将这些孤儿进程挂载到pid为1的init进程下，在这些进程执行结束时候（exit调用）由父进程waitpid方法完成进程信息的状态收集与资源释放工作。因此**孤儿进程是无害的**

僵尸进程指的是当子线程执行完毕之后，父进程此时没有调用waitpid来完成收尾工作，那么此时这个子进程仍然拥有自己的进程描述符，此时就处于僵尸进程的状态了

select、poll、epoll填坑

在进行网络IO时候完成对Socket的几种监控方式：

1、Select方式，完成对所有Socket的无差别轮询，时间复杂度为O（n），每个监听线程有最大连接数的限制（32位是3&#x32;_&#x33;2 = 1024、64位是32_ 64 = 2048，可以在file-max文件当中进行改变），突破这个限制的方法如Tomcat和Netty是采用新建接收线程的方式来解决的，如果当前线程监听的Socket数量达到了1024则会新建一个线程去监听，直接使用数组在内核当中完成对Socket的维护的，因此存在最大限制，这个是软编码在配置文件当中的。

2、Poll方式：类似于Select方式，但是较之于Select方式没有一个连接数的限制，是因为Select的实现是使用数组的方式进行存储在核态内存当中的，因此需要对大小进行限制，Poll方式是使用链表存储到核态内存当中去的，没有大小的限制了

3、EPoll方式是基于Reactor模型来进行设计的，基于Reactor模型设计的框架还包括Redis的文件事件管理器和Netty的Server端，都是将外部请求封装成一个事件丢进来进行处理，因此Epoll可以负责大量的Socket，当Socket发出消息时候会主动调对应的Callback来完成处理，但是如果有大量活跃的Socket还是无法解决的

EPoll可以分为两种模式：LT模式（水平触发：默认模式，只要当前FD有数据可读就会完成数据的装载与Callback函数的回调）和ET模式（边缘触发：高速模式，只会触发一次，直到下次数据再流入之前都不会再提示了，系统这时候不会处理全部的已经就绪的FD了，减轻压力）。

kill命令常见参数：-9和-15

信号方式来进行消息传递的

-15也就是默认的操作了，此时是发送给指定pid进程之后，该进程可能：尝试释放相关资源再停止执行、执行系统调用如IO操作阻塞住了。所以-15命令是有可能被阻塞住的，可忽略的。

-9命令也是发送信号，必须立即停止，有可能造成残留的资源问题，拿JVM来说，如果直接kill -9一个Java进程，那么JVM的Hock都不会触发，而许多收尾工作如Spring容器关闭，流程引擎的关闭都是需要收尾的，可能导致数据丢失问题

mmap内存映射较之于传统的IO优势：

1、不需要两次文件的复制过程，传统IO发生了从磁盘——内核空间——用户空间两次复制，mmap通过缺页中断的方式直接将数据从磁盘加载到了物理内存上来了

2、如果同一个文件多个进程打开了，传统IO会产生每个进程都会从内核空间当中复制一份数据的副本，这样物理内存上可能存在多个相同的数据，而mmap会发现磁盘上面的空间已经映射到物理内存了（MMU）不会发生缺页中断，直接将虚拟内存映射到这一块儿物理内存上来了。
