侧边栏壁纸
博主头像
qiuker

常态咸鱼,偶尔动弹

  • 累计撰写 7 篇文章
  • 累计创建 11 个标签
  • 累计收到 0 条评论

八股文

qiuker
2022-03-09 / 0 评论 / 0 点赞 / 56 阅读 / 9,142 字

一.计算机网络

1.网络协议分层

OSI共七层协议:物理层,数据链路层,网络层,运输层,会话层,表示层, 应用层

TCP/IP体系共四层协议:网络接口层,网络层,运输层,应用层

  • 网络接口层:没有具体内容,对应OSI的物理层和数据链路层
  • 网络层:IP协议
  • 运输层:TCP协议和UDP协议
  • 应用层:协议很多,如HTTP、DNS、SMTP等

2.TCP/UDP

TCP和UDP的区别:

TCP(Transmission Control Protocol):

  • 仅支持单播(全双工通信)
  • 传输速度慢(因为很多为了确保可靠性的机制)
  • 面向字节流进行传输
  • 提供面向连接的可靠传输,适合文件传输等面向连接的应用

UDP(User Datagram Protocol):

  • 支持单播、多播以及广播
  • 传输速度快
  • 直接打包应用层报文
  • 提供无连接不可靠的传输服务,适合视频会议等实时应用(接收方能通过校验和判断有无误码,不可靠只是指不保证报文会送到)

DNS为什么采用UDP协议?

因为UDP协议传输速率快,一些冷门网站的DNS寻址可能需要经过多次查询,使用TCP连接太慢了。

TCP协议确保可靠性的手段:

序列号、校验和、确认应答信号(收到对方的确认后才继续发数据)、重发控制(超时重传)、连接管理、窗口控制、流量控制、拥塞控制实现可靠性。

TCP三次握手:

所谓三次握手(Three-way Handshake),是指建立一个 TCP 连接时,需要客户端和服务器总共发送3个报文。

  • 第一次握手:
    客户端将TCP报文同步标志位SYN置为1,随机产生一个序号值seq=J,指明客户端打算连接的服务器的端口,并将该数据包发送给服务器端,发送完毕后,客户端进入SYN_SENT(同步已发送)状态,等待服务器端确认。

  • 第二次握手:
    服务器端收到数据包后由标志位SYN=1知道客户端要请求建立连接,服务器端将同步标志位SYN和确认标志位ACK都置为1,ack=J+1,随机产生一个序号值seq=K,并将该数据包发送给客户端以确认连接请求,服务器端进入SYN_RCVD(同步已接收)状态。

  • 第三次握手:
    客户端收到确认后,检查ack是否为J+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=K+1,并将该数据包发送给服务器端,服务器端检查ack是否为K+1,ACK是否为1,如果正确则连接建立成功,客户端和服务器端进入ESTABLISHED(连接已建立)状态,完成三次握手,随后客户端与服务器端之间可以开始传输数据了。

注:

  • 小写的ack代表的是头部的确认号Acknowledge number, 缩写ack,是对上一个包的序号进行确认的号,ack=seq+1。
  • 大写的ACK,则是我们上面说的TCP首部的标志位,用于标志的TCP包是否对上一个包进行了确认操作,如果确认了,则把ACK标志位设置成1。

为什么要三次握手,不能是两次握手?

若某次客户端发送的TCP连接请求超时重传,但在滞留很久后又到达了服务器端,在两报文握手的规则下服务器端将直接进入连接已建立的状态并一直等待客户端的数据,白白浪费资源

TCP四次握手:

四次挥手即终止TCP连接,就是指断开一个TCP连接时,需要客户端和服务端总共发送4个包以确认连接的断开。这是因为TCP是全双工通信,双方都要完成关闭连接的工作。

挥手请求可以是Client端,也可以是Server端发起的,我们假设是Client端发起:

  • 第一次挥手: Client端发起挥手请求,向Server端发送终止标志位FIN=1的报文段,设置序列号seq,此时,Client端进入FIN_WAIT_1(终止等待1)状态,这表示Client端没有数据要发送给Server端了。
  • 第二次挥手: Server端收到了Client端发送的FIN报文段,向Client端返回一个标志位是ACK的报文段,ack设为seq加1,Client端进入FIN_WAIT_2(终止等待2)状态,Server端告诉Client端,我确认并同意你的关闭请求,并进入CLOSE-WAIT(关闭等待)状态,因为server端可能还有数据要传输,所以不会直接关闭。
  • 第三次挥手: Server端向Client端发送终止标志位FIN=1的报文段,请求关闭连接,同时Client端进入LAST_ACK(最后确认)状态。
  • 第四次挥手 : Client端收到Server端发送的FIN报文段,向Server端发送确认标志位ACK=1的报文段,然后Client端进入TIME_WAIT(时间等待)状态。Server端收到Client端的ACK报文段以后,就关闭连接。此时,Client端等待2MSL(Maximum Segment Lifetime,最长报文段寿命)的时间后依然没有收到回复,则证明Server端已正常关闭,那好,Client端也可以关闭连接了。

TIME-WAIT状态的意义是什么?
避免第四次挥手(Client端发送的确认报文)的报文没有正常到达,若直接进入关闭状态,Server端没收到确认会一直发送报文,但Client端却已经关闭不再监听了,从而白白导致资源浪费

TCP的流量控制:

目的:防止发送方发的太快,耗尽接收方的资源,从而使接收方来不及处理

如何实现:通过滑动窗口,在接收方的确认信号中有一个值rwnd表示接收端还能接收多少数据,发送方会据此调整自己的发送窗口大小。

TCP的拥塞控制:

目的:当网络拥塞时,减少数据的发送。

实现方式:发送方维护一个叫做拥塞窗口cwnd的状态变量,其值取决于网络的拥塞程度

发送方实际的发送窗口大小=min{拥塞窗口cwnd,接收窗口rwnd}

发送方还需要维护一个慢开始门限变量ssthresh

拥塞控制算法由四部分构成:

慢开始算法:cwnd<ssthresh时生效,窗口呈指数增长(1->2->4->8)

拥塞避免算法:cwnd>=ssthresh后,值线性增加,若突然发生超时重传的情况,此时发送方认为网络存在拥塞,将ssthresh值设为cwnd值的一半,再将cwnd值设为1,随后重新进行慢开始算法。

快重传算法:有时候报文段在网络中丢失不一定是因为网络拥塞,若直接进行拥塞避免算法可能降低传输效率。因此需要尽快重传(连续三次收到接收方的重复确认),而不是等到重传计时器超时再重传。

快恢复算法:收到三个重复确认时,发送方判断只是个别报文丢失而不是网络拥塞,此时让ssthresh和cwnd值都为原cwnd值的一半,再执行拥塞避免算法

超时重传:

超时重传的时间若太长,则会使网络的空闲时间增大,降低传输效率;太短则导致不必要的重传,增大了网络的负荷

所以超时重传的时间根据一定的算法动态变化。

3.HTTP

HTTP是浏览器进程和服务器间的通信协议,属于应用层

GET和POST方法的区别:

  1. POST方法不安全,因为在请求的URL地址后会以键值对的形式带上交给服务器的数据,多个数据之间以&进行分隔,例:/mail/1.html?name=abc&password=xyz?后的就是数据;POST方法更安全
  2. GET能携带的参数较少,数据容量有限制(HTTP协议中并没有限制,而是各家浏览器/服务器所限制的);POST方法没有限制
  3. GET方法是form表单的默认提交方式
  4. GET方法执行效率更高;POST请求较为低效,速度慢

HTTP状态码:

HTTP 状态码由三个十进制数字组成,第一个十进制数字定义了状态码的类型。响应分为五类:信息响应(100–199),成功响应(200–299),重定向(300–399),客户端错误(400–499)和服务器错误 (500–599),具体而言:

  • 1XX:服务器收到请求,需要请求者继续执行操作;
  • 2XX:成功,操作被成功接收并处理
  • 3XX:重定向,需要进一步的操作以完成请求
  • 4XX:客户端错误,请求包含语法错误或无法完成请求
  • 5XX:服务器错误,服务器在处理请求的过程中发生了错误

下面是常见的 HTTP 状态码:

  • 200 - 请求成功
  • 301 - 资源(网页等)被永久转移到其它URL
  • 404 - 请求的资源(网页等)不存在
  • 500 - 服务器内部发生错误

4.HTTPS

HTTP协议以明文方式(即不进行任何数据加密)发送内容,如果攻击者截取了Web浏览器和网站服务器之间的传输报文,就可以直接读懂其中的信息。

HTTPS协议的本质就是HTTP + SSL(or TLS)。在HTTP报文进入TCP报文之前,先使用SSL对HTTP报文进行加密。从网络的层级结构看它位于HTTP协议与TCP协议之间。HTTPS在传输数据之前需要客户端与服务器进行一个握手(TLS/SSL握手),在握手过程中将确立双方加密传输数据的密码信息。TLS/SSL使用了非对称加密,对称加密以及hash等。

HTTP与HTTPS的区别:

  1. https协议需要到CA申请证书,一般免费证书较少,因而需要一定费用。

  2. http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl/tls加密传输协议。

  3. http和https的默认端口也不一样,前者是80,后者是443。

5.DNS寻址过程

DNS( Domain Name System)是“域名系统”的英文缩写,它用于TCP/IP网络,主要的功能就是将域名/网址转化为IP地址。

DNS寻址的具体过程:

  1. 浏览器在本地的hosts文件(windows中路径为C:\Windows\System32\drivers\etc)中寻找有无网址对应的IP,若找到就直接使用这个IP,解析结束

  2. 浏览器从本地的DNS缓存中寻找有无网址对应的IP,只要用到dns的地方都有可能缓存,如浏览器、操作系统,浏览器中的缓存优先级可能高于hosts文件。

  3. 如果hosts与本地DNS解析器缓存都没有相应的网址映射关系,浏览器会把请求发送给网卡配置信息里的dns服务器(可手动指定),在此我们叫它本地DNS服务器,此服务器收到查询时,如果要查询的域名,包含在本地配置区域资源中,则会返回解析结果给客户机,此解析具有权威性。如果要查询的域名,不由本地DNS服务器区域解析,但该服务器已缓存了此网址映射关系,则调用这个IP地址映射,完成域名解析,此解析不具有权威性。

  4. 如果本地DNS服务器上找不到域名对应的IP,则后续有两种可能的处理方式:①转发模式(递归查询),本地DNS服务器继续将请求向更上级的DNS服务器转发,直到找到IP ②非转发模式(迭代查询),本地DNS服务器返回一个更佳的查询地址

6.从输入URL到浏览器显示页面发生了什么

  1. DNS寻址
  2. 建立TCP连接
  3. 客户端发送HTTP请求
  4. 服务器处理请求并返回HTTP响应
  5. 浏览器解析响应结果并渲染成页面
  6. 断开TCP连接

二.操作系统

临界区是什么:

人们把每个进程中访问临界资源的那段代码称为临界区,每个进程在进入临界区前应先对欲访问的临界资源进行检查,看它是否被访问。若临界资源正在被其它进程访问,则本进程不能进入临界区。

在临界区前应当增加一段用于进行上述检查的代码,即进入区,相应地临界区后面也应当加上一段退出区来将临界区刚刚访问的资源恢复成未被访问的标志。

用户态和内核态是什么:

用户态和内核态是操作系统的两种运行状态。

  • 内核态:处于内核态的 CPU 可以访问任意的数据,包括外围设备,比如网卡、硬盘等,处于内核态的 CPU 可以从一个程序切换到另外一个程序,并且占用 CPU 不会发生抢占情况,一般处于特权级 0 的状态我们称之为内核态。

  • 用户态:处于用户态的 CPU 只能受限的访问内存,并且不允许访问外围设备,用户态下的 CPU 不允许独占,也就是说 CPU 能够被其他程序获取。

为什么要有用户态和内核态呢?应用程序有可能是恶意的

用户态和内核态是如何切换的:

只有中断才能使用户态进入内核态

中断包括三种:中断、异常、系统调用

进程和线程的区别:

  • 进程是系统进行资源分配和调度的一个独立单位,线程是CPU调度和分派的基本单位,不占有系统资源,而是与同属一个进程的其他的线程共享进程所拥有的全部资源。所以线程没有进程的独立性。

  • 线程创建、撤销和切换的代价比进程小

  • 线程因为共享内存,所以通信较为方便;进程通信比较困难(说完这个面试官一般就问进程的通信方式了233)

进程间通信的几种方式:

  • 共享内存:进程间本身是没有共享内存的,但操作系统可以在内存中划出一片区域供进程来交换信息。最有效,但是无法用于网络通信(不同计算机的进程肯定无法划分出共享内存)。

  • 管道通信:用一个pipe文件,写进程向pipe文件中写入数据,读进程从pipe文件中读取数据即可。这个文件也是在内存中的,可以分为匿名管道和有名管道。缺点是只能单向通信,且匿名管道只能用于父子进程等有亲缘关系的进程。

  • 消息队列:以消息为单位进行通信,操作系统提供一组原语让进程来通过消息队列传递消息。具体的通信细节是由操作系统控制的。计算机网络中的报文就是一种消息。可以在任意进程间通信,但效率较共享内存来说更低。

  • 套接字(Socket): 是不同计算机进程间的主流通信机制。

进程的生命周期:

进程具有三种基本状态:

  • 就绪状态(Ready):此时进程获得了其运行所需的所有计算机资源,只要再获得CPU就可以立即执行
  • 执行状态(Running):程序正在运行的状态
  • 阻塞状态(Block):正在执行的进程因为某些事件(如发出I/O申请)而无法继续执行的状态

状态的转换:

  • 处于就绪状态的进程获得CPU后转变为执行状态
  • 处于执行状态的进程因为时间片用完转变为就绪状态
  • 处于执行状态的进程遭遇某些事件无法继续进行(如进程发出I/O申请)转换为阻塞状态
  • 处于阻塞状态的进程解决了事件转换为就绪状态(如I/O完成)

进程还具有两种状态:

  • 创建状态:进程正在创建的状态,假如某项计算机资源无法获得就会导致无法转为就绪状态,比如内存不够
  • 终止状态:进程正在终结的状态,进程不能再被执行,但是PCB还需要清空,或者别的进程需要收集信息

操作系统还引入了一个对进程的重要操作————挂起操作,执行中的进程被挂起后将暂停执行,就绪状态的进程被挂起后将暂时不接受调度。与挂起操作对应的是激活操作。

被挂起的进程将进入静止状态,与之对应的是活动状态。

注:被挂起的进程其实被放进外存了

如何避免死锁:

死锁的定义:

一组死锁进程中,每组进程都在等待其它死锁进程所占用的资源,但由于这些进程都缺少资源无法运行,所以谁也不会释放资源,最终导致所有进程都被阻塞且不会被唤醒。

死锁产生的必要条件:

  • 互斥:资源必须是不可共享,需要互斥访问的

  • 请求和保持:进程在得不到自己想要的资源从而阻塞时,也不释放自己手中的资源

  • 不可抢占:进程的资源是不可抢占性的

  • 循环等待:形成一个循环链

死锁的解决办法:

  • 预防死锁:采取一些限制方法,破坏死锁的四个必要条件中的至少一个

    • 互斥条件是资源决定的,没法破坏

    • 破坏请求和保持条件:规定进程必须在开始运行前一次性申请所需的全部资源,缺点是浪费资源,资源利用率低;更好的方法是进程获取到部分资源就可以开始运行,在运行过程中逐步释放用完的资源。

    • 破坏不可抢占条件:规定到进程占用一些不可抢占资源,提出新的资源请求却得不到满足时要释放已经保持的资源。但这种方法代价很大,比如打印机如果在使用一段时间后被抢占则之前的工作去拿不失效。

    • 破坏循环等待条件:给所有资源分配一个编号,规定进程必须按序号递增的顺序来请求资源。

  • 避免死锁:和预防的区别在于不事先采取措施破坏死锁的必要条件,而是在资源分配中采用一定的办法(如银行家算法)防止进入死锁:

    系统判断若存在某种进程执行顺序不会导致死锁发生才分配资源。

  • 检测死锁:发生死锁后检测出来,从而能采取适当的措施解脱

  • 解除死锁:

    • 从其它进程中抢占足够的资源分配给死锁进程,从而解除死锁状态

    • 终止/撤销发生死锁的一个/多个进程,直到打破循环

三.Java

JDK 和 JRE的区别:

JRE指Java Runtime Environment,即Java运行时环境。JRE中包含了JVM和核心类库(在运行class文件时所必需的库),只要有JRE就可以将class文件运行起来

JDK指Java Development Kit,即Java开发工具。JDK中包含了JRE,同时还包含了编译java源码的编译器javac,jconsole和jvisualvm等用于程序调试和分析的工具,此外还包含了java程序编写所需的文档和demo例子程序。

JDK是开发工具,面向程序员;JRE则只能让Java程序编译后形成的字节码文件运行起来。

== 和 equals 的区别:

基本类型在进行==运算时,比较的就是值。如果两个值类型不同,还会先进行隐式的类型转换。对象(引用类型)在进行==运算时,比较的是内存地址,也就是除非是同一个new出来的对象,否则都返回false;

Object类中的equals方法:

    public boolean equals(Object obj) {
        return (this == obj);
    }

也就是说Object类中的equals方法和==没区别

但一些子类基本都重写了equals方法,如String类中会逐字符比较;Integer类中也是会比较intValue();

例:两个不同的String对象,值都为“123”,使用==会返回false,使用equals()方法会返回true

两个对象的 hashCode()相同,则 equals()是否相同?

hashCode()的生成非常复杂,它的作用是用来标识对象,同一个对象执行多次hashCode()方法得到的值一定是相同的,不同对象的hashCode()值则(极大概率)不同。

大部分时候,只要hashCode值相同就可以认为是同一个对象,那么equals值也肯定相同。但是不同对象的哈希码是有很小概率冲突的(哈希冲突),所以不能绝对的说一定相等。

final 在 java 中的作用:

  • 修饰基本数据类型时,表示其为常量
  • 修饰引用数据类型时(如对象),则该对象本身可以修改,但变量不能再指向其它对象。
  • 修饰方法时,表示该方法无法被重写
  • 修饰类时,表示该类无法被继承

java 中的 Math.round(-1.5) 等于多少?

-1

Math.round(-5.4)得到的结果是:-5
Math.round(-5.5)得到的结果是:-5
Math.round(-5.500001)得到的结果是:-6
Math.round(-5.6)得到的结果是:-6

String 属于基础的数据类型吗?

不属于,是java.lang包下的一个类

java 中操作字符串都有哪些类?它们之间有什么区别?

操作字符串的类有:String、StringBuffer、StringBuilder。

  • String:不可变字符串;另外两个类都有append方法来对字符串进行扩容。因为String是不可变的,因此也是线程安全的。

  • StringBuffer:很多方法都用synchronized修饰,线程安全。

  • StringBuilder:和StringBuffer的类继承关系基本一样,但是没用synchronized修饰,线程不安全,但效率高。

总结:线程安全性上String和StringBuffer都是安全的,StringBuilder则不安全;String由于不可变,如果字符串需要频繁地修改肯定效率不高;StringBuffer和StringBuilder都是可变的,后者没有实现线程安全所以效率更高。

String str="i"与 String str=new String(“i”)一样吗?

str = "i" 是让str指向了常量池中的"i"(如果常量池中没有则会创建),如果再令str2 = "i" 则二者指向的是同一个对象。

使用了new关键词则是在堆内存中创建了对象

抽象类必须要有抽象方法吗?

不是,抽象类可以有抽象方法

普通类和抽象类有哪些区别?

  • 抽象类不能实例化
  • 抽象类中可以有抽象方法,普通类不能有
  • 抽象类中的抽象方法不能用finalstaticprivate 来修饰(这些关键词修饰的方法都不能被重写)

抽象类能使用 final 修饰吗?

不能

接口和抽象类有什么区别?

  • 抽象类中可以包含非抽象的普通方法,接口中的所有方法必须都是抽象的。

  • 抽象类中的抽象方法的访问类型可以是public,protected和默认类型,但接口中的抽象方法只能是public类型的

  • 一个类可以实现多个接口,但只能继承一个抽象类

  • 接口中只能有常量

java 中 IO 流分为几种?

  • 按操作数据的单位分为字节流(8bit 一字节)和字符流(取决于文件编码方式);字节流一般用于处理二进制文件,字符流一般用于处理文本文件

  • 按数据的流向分为输入流和输出流

字节输入流对应的类:java.io.InputStream

字节输出流对应的类:java.io.OutputStream

字符输入流对应的类:java.io.Reader

字符输出流对应的类:java.io.Writer;

这四个类都是抽象类,不能直接实例化;这四个类派生出了四十多个子类,每个子类都已父类作为后缀名,如FileInputStream、FileReader等等

四.JVM

双亲委派机制:

Java源代码被编译器编译成.class为后缀的字节码文件,然后由ClassLoader(类加载器)负责将这些class文件给加载到JVM中去执行。

JVM中提供了三层的ClassLoader:

  • Bootstrap classLoader:主要负责加载核心的类库(java.lang.*等),构造
    ExtClassLoader和APPClassLoader。

  • ExtClassLoader:主要负责加载jre/lib/ext目录下的一些扩展的jar。

  • AppClassLoader:主要负责加载应用程序的主函数类

双亲委派机制:当某个类加载器需要加载某个.class文件时,它首先把这个任务委托给他的上级类加载器,递归这个操作,如果上级的类加载器没有加载,自己才会去加载这个类。

如何查看一个对象是用什么加载器加载出来的:对象.getClass().getClassLoader()

注:由于Bootstrap加载器是用C++写的,无法用上述方法获取到(会返回null)

双亲委派机制的作用:

1、防止重复加载同一个.class。通过委托去向上面问一问,加载过了,就不用再加载一遍。保证数据安全。
2、保证核心.class不能被篡改。通过委托方式,不会去篡改核心.clas,即使篡改也不会去加载,即使加载也不会是同一个.class对象了。不同的加载器加载同一个.class也不是同一个Class对象。这样保证了Class执行安全。

0

评论区