操作系统和计算机网络连环问,你能坚持到第几问?


前言

作为JAVA开发程序员,在学习的过程中不能只盯着JAVA和数据库看,对于计算机网络和操作系统这样的计算机基础课程也要兼顾。本文总结了面试中常问的计网和操作系统问题,供大家参考学习。


一、操作系统

线程和进程的区别是什么?

1.进程作为资源分配的单位,线程作为独立调度和分派的基本单位。
2.一个进程可以包含多个线程,一个线程只能属于一个进程,线程不能脱离进程而独立运行;
3.进程作为拥有资源的一个基本单位,线程仅拥有一点必不可少、能保证独立运行的资源(线程控制块TCB、程序计数器、一组寄存器和堆栈)
4.OS为创建、撤销、调度进程耗费的资源明显的大于线程的开销
5.进程之间的独立性高于线程,因为线程共享进程中的地址空间和资源(进程可以看成是一个班级,线程就是里面的学生,学校给班级分配了500元的资金,这个资金相当于分配的系统资源,这些学生共享这些资金。)


进程通信方式有哪几种?

1.管道:如果你学过 Linux 命令,那你肯定很熟悉「 | 」这个竖线。 上⾯命令⾏⾥的「 | 」竖线就是⼀个管道,它的功能是将前⼀个命令( ps auxf )的输出, 作为后⼀个命令( grep mysql )的输⼊,从这功能描述,可以看出管道传输数据是单向的,如果想相互通信,我们需要创建两个管道才行。

例如:ps -ef | grep 进程名: 查看指定名称的进程号,先输出所有 管道命令交给 grep 名称过滤 过滤出指定进程信息。

特点:进程写⼊的数据都是缓存在内核中,另⼀个进程读取数据时自然也是从内核中获取。管道这种通信⽅式效率低,不适合进程间频繁地交换数据。当然,它的好处,⾃然就是简单,同时也我们很容易得知管道⾥的数据已经被另⼀个进程读取了。

2.消息队列:前⾯说到管道的通信方式是效率低的,因此管道不适合进程间频繁地交换数据。 对于这个问题,消息队列的通信模式就可以解决。比如,A 进程要给 B 进程发送消息,A 进程把数据放在对应的消息队列后就可以正常返回了,B 进程需要的时候再去读取数据就可以了。同理,B 进程要给 A 进程发送消息也是如此。

特点:消息这种模型,两个进程之间的通信就像平时发邮件⼀样,你来⼀封,我回⼀封,可以频繁沟通了。 但邮件的通信方式存在不足的地方有两点,⼀是通信不及时,二是附件也有大小限制,这同样也是消息队列通信不⾜的点。

3.共享内存:消息队列的读取和写入的过程,都会有发生用户态与内核态之间的消息拷贝过程。那共享内存的方式,就很好的解决了这⼀问题。共享内存的机制,就是拿出⼀块虚拟地址空间来,映射到相同的物理内存中。这样这个进程写入的东西,另外⼀个进程马上就能看到了,都不需要拷贝来拷贝去,传来传去,大大提高了进程间通信的速度。

特点:用了共享内存通信方式,带来新的问题,那就是如果多个进程同时修改同⼀个共享内存,很有可能就冲突了。例如两个进程都同时写⼀个地址,那先写的那个进程会发现内容被别人覆盖了。

4.信号量: 为了防止多进程竞争共享资源,而造成的数据错乱,所以需要保护机制,使得共享的资源, 在任意时刻只能被⼀个进程访问。正好,信号量就实现了这一保护机制。

信号量其实是⼀个整型的计数器,主要⽤于实现进程间的互斥与同步,⽽不是⽤于缓存进程间通信的数据。 信号量表示资源的数量,控制信号量的⽅式有两种原⼦操作:

1.⼀个是 P 操作,这个操作会把信号量减去 1,相减后如果信号量 < 0,则表明资源已被占⽤,进程需阻塞等待;相减后如果信号量 >= 0,则表明还有资源可使⽤,进程可正常继续执⾏。

2.另⼀个是 V 操作,这个操作会把信号量加上 1,相加后如果信号量 <= 0,则表明当前有 阻塞中的进程,于是会将该进程唤醒运⾏;相加后如果信号量 > 0,则表明当前没有阻塞 中的进程;

特点:P 操作是用在进入共享资源之前,V 操作是用在离开共享资源之后,这两个操作是必须成对出现的

5.信号:上面说的进程间通信,都是常规状态下,对于异常情况下的⼯作模式,就需要⽤信号的⽅式来通知进程。

例如:如果进程在后台运⾏,可以通过 kill 命令的⽅式给进程发送信号,但前提需要知道运⾏中的进程 PID 号,例如: kill -9 1050 ,表示给 PID 为 1050 的进程发送 SIGKILL 信号,⽤来⽴即结束该进程


Linux常用命令有哪些?

查看文件

cd … 进入到根目录或回到上一级目录。

ls 查看目录下的文件

ls -a 显示所有文件目录(包括隐藏文件)

ls -l 显示文件和目录的详细资料

pwd:显示当前所在的目录

mkdir:创建目录

touch : 创建文件

rm:删除文件

rm -rf:意思是不论还有多少级别的目录,都会同时删除

查看进程和管道

ps -aux 查看所有的进程

ps -ef :全格式显示进程所有信息,包括父进程Pid,创建人,创建时间,进程号
kill -9 [PID] #-9 表示强迫进程立即停止

例如:ps -ef | grep 进程名: 查看指定名称的进程号,先输出所有 管道命令交给 grep 名称过滤 过滤出指定进程信息。查看当前是否启动 MySQL 服务 ps -ef | grep mysql

ps -ef|grep xxx.jar 来查看当前运行的jar包程序进程号

top:如果想要动态的显示进程信息,就可以使用top命令,同时还可以看cpu的利用率

vim编译器

vim 文件名

i 进入编辑模式

Esc 退出编辑模式

q! 若曾修改过档案,又不想储存,使用 ! 为强制离开不储存档案。

:wq 保存并离开

解压缩命令

tar-zxvf 解压gz文件

tar-czvf 压缩文件

Linux查看文件行数命令

1、tail -n -数字 文件名 表示查看文件的最后几行

2、tail -n +数字 文件名 表示查看文件的某一行到最后一行

3、head -n 数字 文件名 表示查看文件前几行的内容


死锁是什么?

造成死锁的四个条件:

1.⼀个资源每次只能被⼀个线程使用(一个叉子只能被一个哲学家使用)

2.⼀个线程在阻塞等待某个资源时,不释放已占有资源 (即使拿不到第二个叉子,哲学家也不会放弃已经拿到的叉子)

3.⼀个线程已经获得的资源,在未使用完之前,不能被强姓剥夺 (不能从其他哲学家手上抢走叉子)

4.若干线程形成头尾相接的循环等待资源关系(每个哲学家都在等待下一个人释放叉子,形成了一个环)

5.这是造成死锁必须要达到的4个条件!如果要避免死锁,只需要不满⾜其中某⼀个条件即可。但是其中前3个条件是作为锁要符合的条件,所以要避免死锁就需要打破第4个条件,不出现循环等待锁的关系。打破这个条件最常用的方法就是资源有序分配法。

预防死锁

作为程序员,在开发过程中:

1. 要注意加锁顺序,保证每个线程按同样的顺序进⾏加锁

2. 要注意加锁时限,可以针对所设置⼀个超时时间

3. 要注意死锁检查,这是⼀种预防机制,确保在第⼀时间发现死锁并进⾏解决


IO,BIO,AIO和NIO区别是什么?

同步阻塞(blocking-IO)简称 BIO :去饭店吃饭,就这样在那里等着排队,等了一小时,轮到了,然后开始吃,这就是BIO,整个过程是同步阻塞的。典型的的例子为data=socket.read(),如果内核数据没有准备就绪,Socket线程就会一直阻塞在read()中等待内核数据就绪。

同步非阻塞(non-blocking-IO)简称 NIO:去饭店吃饭,一看要等挺久的,于是就可以去逛会商场,每次逛一下,

就跑回来看看,是不是等到了。于是最后她既购了物,又吃上了饭。例如非阻塞IO模型和信号驱动IO模型就是NIO。

异步非阻塞(asynchronous-non-blocking-IO)简称 AIO:去饭店吃饭,一看要等挺久的,于是就可以去逛会商场,每次逛一下,但是不用每次跑回来看看是不是等到了,等到了的话店长会打电话给你。异步IO模型就是AIO。

Java NIO(Non Blocking IO)是从 Java 1.4 版本开始引入的一个新的 IO API,可以替代标准的 Java IO API,NIO 支持面向缓冲区的、基于通道的 IO 操作。NIO 将以更加高效的方式进行文件的读写操作。

Java NIO 核心部分组成

1.Channels :Channel,可以翻译成“通道”。Channel 和 IO 中的 Stream(流)是差不多一个等级的。只不过 Stream 是单向的,譬如:InputStream,OutputStream;而 Channel 是双向的,既可以用来进行读操作,又可以用来进行写操作。因为 Channel 是全双工的,所以它可以比流更好地映射底层操作系统的 API。

2.Buffers :Java NIO 中的 Buffer 用于和 NIO 通道进行交互。数据是从通道读入缓冲 区,从缓冲区写入到通道中的。 缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存。这块内存被包装成 NIO Buffer 对象,并提供了一组方法,用来方便的访问该块内存。

3.Selectors :一般称为选择器。它是 Java NIO 核心组件中的一个,用于检查一 个或多个 NIO Channel(通道)的状态是否处于可读、可写。如此可以实现单 线程管理多个 channels,也就是可以管理多个网络链接。

使用 Selector 的好处在于:使用更少的线程来就可以来处理通道了,相比使用多个线程,避免了线程上下文切换带来的开销。


二、计算机网络

HTTP常见的状态码

1XX——表示提示信息

2XX——请求被成功处理

  1. 200:响应头有body数据
  2. 204:没有body数据
  3. 206:body是部分资源

3XX——表示重定向,资源位置发生改动

  1. 301:永久重定向
  2. 302:临时重定向
  3. 303:缓存重定向

4XX——表明客户端发生错误

  1. 400 Bad Request:服务器端无法理解客户端发送的请求,请求报文中可能存在语法错误。
  2. 403 Forbidden不允许访问那个资源。该状态码表明对请求资源的访问被服务器拒绝了。(权限,未授权IP等)
  3. 404 Not Found:服务器上没有请求的资源,可能是路径错误等。

5XX——服务器本身发生错误

  1. 500 Internal Server Error:貌似内部资源出故障了。该状态码表明服务器端在执行请求时发生了错误。也有可能是web应用存在bug或某些临时故障。
  2. 503 Service Unavailable:该状态码表明服务器暂时处于超负载或正在停机维护,现在无法处理请求。

HTTP1和2的区别

HTTP2是对HTTP1.1的升级,对HTTP1.1性能问题进行了优化,主要从以下两个方面来优化:头部压缩和队头阻塞。

  1. HTTP1.1主要是对Body进行压缩,而头部却没有压缩。HTTP2对头部进行压缩,减少了传输时间。
  2. HTTP1.1使用的是TCP协议,并且为了节省资源,采用了长连接,长连接引入了队头阻塞的问题。HTTP2引入了流和帧,解决了HTTP层面上的队头阻塞。

get和post区别

1、语义上的区别:

我们通常将Get定义成“读取“一个资源,例如读取全部学生的信息,将POST用于“创建一个资源,例如新增一条学生记录。

2、安全性方面:

我们常听到GET不如POST安全,因为POST用body传输数据,而GET用url传输,更加容易看到。但是从攻击的角度,无论是GET还是POST都不够安全,因为HTTP本身是明文协议。为了避免传输中数据被窃取,必须做从客户端到服务器的端端加密,业界的通行做法就是https

3、缓存方面:

因为GET因为是读取,幂等不修改服务器状态,就可以对GET请求的数据做缓存,这个缓存可以做到浏览器本身上(彻底避免浏览器发请求)。**而POST则用于“创建一个资源“,这个动作是不幂等且修改服务器状态的,因此也就不能缓存。**例如:如果POST请求被浏览器缓存了,假如有一个下单请求,就可以不向服务器发请求,而直接返回本地缓存的“下单成功界面”,却又没有真的在服务器下单,这就会导致问题。

4.请求参数

重点:从协议本身看,并没有什么限制说GET一定不能没有body,POST就一定不能把参放到URL上。因此其实可以更加自由的去利用格式。

缺点:当然,太自由也带来了另一种麻烦,开发人员不得不每次讨论确定参数是放url的path里还是body里这种问题,太低效了。

解决办法:于是就有了一些列接口规范/风格。其中名气最大的当属REST。REST充分运用GET、POST、PUT和DELETE,约定了这4个接口分别获取、创建、修改和删除“资源”,REST最佳实践还推荐在请求体使用json格式。这样仅仅通过看HTTP的method就可以明白接口是什么意思,并且解析格式也得到了统一。

5.数据包

一般来说,GET产生一个TCP数据包;POST产生两个TCP数据包。

对于GET方式的请求,浏览器会把header和data一并发送出去,服务器响应200(返回数据);而对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)。

举例:也就是说,GET只需要汽车跑一趟就把货送到了,而POST得跑两趟,第一趟,先去和服务器打个招呼“嗨,我等下要送一批货来,你们打开门迎接我”,然后再回头把货送过去。


TCP确认应答和重传机制

TCP实现可靠传输的方式之一,就是通过序列号和确认应答。

确认应答:在TCP中,当发送端的数据到达接收端之后,接收端主机会返回一个确认应答消息,表示已经接收到消息
在这里插入图片描述

在网络复杂,并不一定能够上上图那样正常的数据传输,数据有可能在传输过程中丢失。所以TCP针对数据包丢失测情况,会用重传机制来解决

常见重传机制

有四种:

  • 超时重传重传机制的其中一个方式,就是在发送数据时,设定一个定时器,当超过指定的时间RTO后,没有收到对方的ACK确认应答报文,就会重发该数据,也就是超时重传
  • 快速重传所以,快速重传的工作方式是当收到三个相同的ACK报文时,会在定时器过期之前,重传丢失的报文段。
  • SACK:SACK( Selective Acknowledgment 选择性确认)。它会在TCP头部的[选项]字段里面加一个SACK的东西,它可以将缓存的地图发送给发送方,这样发送方就可以知道哪些数据送到了,哪些数据没有收到,知道了这些信息,就可以只重传丢失的数据
  • D-SACK:Duplicate SACK 又称 D-SACK,其主要使用SACK来告诉[发送方]有哪些数据被重复接收了

TCP流量控制和拥塞控制

流量控制

如果发送方把数据发送得过快,接收方可能会来不及接收,这就会造成数据的丢失。所谓流量控制就是让发送方的发送速率不要太快,要让接收方来得及接收。利用滑动窗口机制可以很方便地在TCP连接上实现对发送方的流量控制。

设A向B发送数据。在连接建立时,B告诉了A:“我的接收窗口是 rwnd = 400 ”(这里的 rwnd 表示 receiver window) 。因此,发送方的发送窗口不能超过接收方给出的接收窗口的数值。

拥塞控制

拥塞控制是让网络能够承受现有的网络负荷,是一个全局性的过程,涉及所有的主机、所有的路由器,以及与降低网络传输性能有关的所有因素。

流量控制往往是指点对点的通信量的控制,即接收端控制发送端,它所要做的是抑制发送端发送数据的速率,以便使接收端来得及接收。如果发送端发送数据太快,接收端来不及接收,可能会丢失数据。

几种拥塞控制方法:

慢开始( slow-start )、拥塞避免( congestion avoidance )、快重传( fast retransmit )和快恢复( fast recovery )。

慢开始算法:当主机开始发送数据时,如果立即所大量数据字节注入到网络,那么就有可能引起网络拥塞,因为现在并不清楚网络的负荷情况。因此,较好的方法是先探测一下,即由小到大逐渐增大发送窗口,也就是说,由小到大逐渐增大拥塞窗口数值。

拥塞避免算法:让拥塞窗口cwnd缓慢地增大,即每经过一个往返时间RTT就把发送方的拥塞窗口cwnd加1,而不是加倍。这样拥塞窗口cwnd按线性规律缓慢增长,比慢开始算法的拥塞窗口增长速率缓慢得多。

快重传要求接收方在收到一个失序的报文段后就立即发出重复确认(为的是使发送方及早知道有报文段没有到达对方)而不要等到自己发送数据时捎带确认。快重传算法规定,发送方只要一连收到三个重复确认就应当立即重传对方尚未收到的报文段,而不必继续等待设置的重传计时器时间到期。

快速恢复”算法是在上述的“快速重传”算法后添加的,当收到3个重复ACK时,TCP最后进入的不是拥塞避免阶段,而是快速恢复阶段。快速重传和快速恢复算法一般同时使用。


总结

本篇文章主要介绍了一些计算机网络和操作系统常见的问题,像线程和进程的区别、Linux操作系统的常用命令都是面试的高频面试题。本篇文章内容较多,更多需要记忆。


猜你喜欢

转载自blog.csdn.net/qq_52173163/article/details/126951059
今日推荐