面经整理
一、计算机网络
0 - OSI七层模型和TCP/IP四层模型是什么?都有什么协议?
OSI 七层模型及其包含的协议如下:
- 物理层: 通过媒介传输比特,确定机械及电气规范,传输单位为bit,主要包括的协议为:IEE802.3 CLOCK RJ45
- 数据链路层: 将比特组装成帧和点到点的传递,传输单位为帧,主要包括的协议为MAC VLAN PPP
- 网络层:负责数据包从源到宿的传递和网际互连,传输单位为包,主要包括的协议为IP ARP ICMP
- 传输层:提供端到端的可靠报文传递和错误恢复,传输单位为报文,主要包括的协议为TCP UDP
- 会话层:建立、管理和终止会话,传输单位为SPDU,主要包括的协议为RPC NFS
- 表示层: 对数据进行翻译、加密和压缩,传输单位为PPDU,主要包括的协议为JPEG ASII
- **应用层: **允许访问OSI 环境的手段,传输单位为APDU,主要包括的协议为 FTP HTTP DNS
TCP/IP 4 层模型包括:
- 网络接口层:MAC VLAN
- 网络层: IP ARP ICMP
- 传输层: TCP UDP
- 应用层: HTTP DNS SMTP
1 - TCP是怎样建立连接的?三次握手
1.0 三次握手
最初两端的TCP进程都处于CLOSE(关闭)状态,开始建立连接,服务器Server的TCP服务器进程先创建传输控制块TCB(Transmission Control Block),准备接受客户端进程的连接请求。此时服务器进程处于LISTEN(收听)状态。客户端Client的TCP客户端进程也是首先创建TCB,在决定建立TCP连接时,向服务器Server发送连接请求(从而开始三次握手):
- 客户端向服务器发送连接请求报文段,将首部中的同步位SYN置为1,同时选择一个初始序号ISN(j)。此时客户端进入SYN-SENT(同步已发送) 状态。
- SYN报文段(即SYN=1的报文段)不能携带数据,但要消耗一个序号
- 服务器收到客户端的SYN报文后,会发送自己的SYN报文,在报文段中把SYN和ACK都置为1,同时也为自己选择一个初始序号ISN(k),把客户端的ISN+1(j+1)作为ACK的值,表示自己已经收到了客户端的ISN。这时TCP服务器进行进入SYN-RCVD(同步收到)状态。
- 同理,此报文段也不能携带数据。
- 客户端收到服务器的SYN报文后,还要向服务器发送 一个ACK报文,确认报文段中的ACK=1,也是一样把服务器的ISN+1(k+1)作为ACK的值,表示已经收到了服务端的SYN报文,这时TCP连接已经建立,客户端进入ESTABLISHED(已建立连接)状态。当服务器收到客户端的确认后,也进入ESTABLISHED(已建立连接)状态。
- TCP标准规定,ACK报文段可以携带数据,但如果不携带数据则不消耗序号
其中服务器给客户端发送的报文也可以拆成两个报文段,可以先发一个确认报文段(ACK=1,ack=j+1),再发送一个同步报文段(SYN=1,seq=k)。这样就变成了四次报文握手,但效果一样
1.1 ISN是固定的吗
三次握手的一个重要功能是客户端和服务端交换ISN(Intial Sequence Number),以便让对方知道接下来接受数据的时候如何按序列号组装数据
如果ISN是固定的,攻击者很容易猜出后续的确认号,因此ISN是动态生成的
1.2 什么是半连接队列?
服务器第一次接收到客户端的SYN之后,就会处于SYN_RCVD状态,此时双方还没有完全建立其连接,服务器会把此种状态下请求连接放在一个队列里,即半连接队列。
对应的是全连接队列,就是已经完成三次握手,建立起连接的就会放在全连接队列里。如果队列满了就有可能出现丢包的现象
1.3 三次握手过程中可以携带数据吗?
TCP规定,SYN报文段(即SYN=1的报文段)不能携带数据,但要消耗一个序号。所以第一次、第二次握手不可以携带数据,但第三次可以携带数据
如果SYN报文段可以携带数据,攻击者可以在第一次握手中的SYN报文中放入大量数据,因为攻击者根本不理会服务器的接收、发送能力是否正常,疯狂发送SYN报文,这会让服务器花费大量时间和内存空间来接收这些空报文。服务器更容易受到攻击。
对于第三次握手,此时客户端已经处于established状态,对于客户端来说,已经建立起了连接,并且也知道服务器的接收、发送能力是正常的,所以可以携带数据。
2 - TCP是怎样断开连接的?四次挥手
四次挥手
数据传输结束后,通信的双方都可释放连接,现在客户端和服务端都处于ESTABLISHED(已建立连接)状态。
第一次挥手:客户端向服务器发送一个FIN报文,首部的FIN=1,同时报文给自己指定一个序号(m),此时客户端进入FIN_WAIT_1 (终止等待1)状态,但客户端依然可以接收服务器发送来的数据。
- TCP规定,FIN报文段即使不携带数据,也要消耗一个序号。
第二次挥手:服务端收到了客户端的FIN报文,会发送ACK报文进行确认,把收到报文的序列号的值+1(m+1)作为ACK报文的序列号的值,表明已经收到了客户端的报文,服务器进入CLOSE-WAIT(关闭等待)状态
- TCP服务器进程这时应通知高层应用程序,客户端到服务端这个方向的连接就释放了,此时TCP连接处于半关闭(HALF-CLOSE)状态,即客户端已经没有数据要发送了,但服务器若发送数据,客户端仍要接收。客户端收到服务端的确认后,进入FIN-WAIT-2(终止等待2)状态。等待服务端发出的连接释放报文段。
第三次挥手:当服务器没有数据要发送了,也想要断开连接,会给客户端发送FIN报文,且指定一个序列号(n),服务器进入了LAST-ACK(最后确认)状态。
第四次挥手:客户端收到FIN之后,一样会发送一个ACK报文作为应答,且把服务端的序号+1(n+1)作为自己ACK报文的序号。然后进入TIME-WAIT(时间等待)状态,等待2MSL(MSL:报文段最大生存时间),然后关闭连接。
为什么TIME-WAIT状态 必须等待2MSL的时间呢?
- 为了保证A发送的最后一个ACK报文段能够到达B。这个ACK报文段有可能丢失,因而使处在LAST_ACK状态的B收不到对已发送FIN+ACK报文段的确认。B会超时重传这个FIN+ACK报文段,而A就能在2MSL时候内(超时+1MSL传输)收到这个重传的FIN+ACK报文段。接着A重传一次确认,重新启动2MSL计时器,最后A和B都正常进入CLOSED状态。如果A在TIME-WAIT状态不等待一段时间,而是在发送完ACK报文段后立即释放连接,那么就无法收到B重传的FIN+ACK报文段,因而也不会再发送一次确认报文段,这样B就无法按照正常流程进入CLOSED状态。
- 防止已失效的连接请求报文段出现在本连接中。A在发送完最后一个ACK报文段后,再经过2MSL,就可以使本连接持续的时间内所产生的所有报文段在网络中消失。这样就可以使下一个连接中不会出现这种旧的连接请求报文段。
2MSL 意义:
- 保证最后一次握手报文能到服务器,能进行超时重传。
- 2MSL 后,这次连接的所有报文都会消失,不会影响下一次连接。
TIME_WAIT的作用
大多数 BSD 派生的系统一样,Linux 系统里有一个硬编码的字段,名称为TCP_TIMEWAIT_LEN,其值为 60 秒。也就是说,Linux 系统停留在 TIME_WAIT 的时间为固定的 60 秒。
1 |
|
只有发起连接终止的一方会进入 TIME_WAIT 状态。
TIME_WAIT可以:
- 确保最后的 ACK 能让被动关闭方接收,从而帮助其正常关闭。
- TCP 假设报文会出错,需要重传。如果客户端的ACK 报文没有传输成功,那么服务器就会重新发送 FIN 报文。如果客户端 没有维护 TIME_WAIT 状态,而直接进入 CLOSED 状态,它就失去了当前状态的上下文,只能回复一个 RST 操作,从而导致被动关闭方出现错误。现在客户端知道自己处于 TIME_WAIT 的状态,就可以在接收到 FIN 报文之后,重新发出一个 ACK 报文,使得服务器可以进入正常的 CLOSED 状态。
- 为了让旧连接的重复分节在网络中自然消失。
- 2MSL 的时间是从客户端接收到 FIN 后发送 ACK 开始计时的;如果在 TIME_WAIT 时间内,因为客户端的 ACK 没有传输到服务器,客户端又接收到了服务器重发的 FIN 报文,那么 2MSL 时间将重新计时。道理很简单,因为 2MSL 的时间,目的是为了让旧连接的所有报文都能自然消亡,现在客户端重新发送了 ACK 报文,自然需要重新计时,以便防止这个 ACK 报文对新可能的连接化身造成干扰。
- 如果迷走报文到达时,发现 TCP 连接四元组(源 IP,源端口,目的 IP,目的端口)所代表的连接不复存在,那么这个报文会被丢弃。
- 经过 2MSL 这个时间,足以让两个方向上的分组都被丢弃,使得原来连接的分组在网络中都自然消失,再出现的分组一定都是新化身所产生的。
TIME_WAIT的危害?
- 第一是内存资源占用,但不是很严重,基本可以忽略。
- 第二是对端口资源的占用,一个 TCP 连接至少消耗一个本地端口。端口资源也是有限的,一般可以开启的端口为 32768~61000 ,也可以通过net.ipv4.ip_local_port_range指定,如果 TIME_WAIT 状态过多,会导致无法创建新连接。
如何优化TIME_WAIT?
net.ipv4.tcp_max_tw_buckets:
一个暴力的方法是通过 sysctl 命令,将系统值调小。这个值默认为 18000,当系统中处于 TIME_WAIT 的连接一旦超过这个值时,系统就会将所有的 TIME_WAIT 连接状态重置,并且只打印出警告信息。这个方法过于暴力,而且治标不治本,带来的问题远比解决的问题多,不推荐使用。
调低 TCP_TIMEWAIT_LEN:
重新编译系统这个方法是一个不错的方法,缺点是需要“一点”内核方面的知识,能够重新编译内核。
net.ipv4.tcp_tw_reuse:更安全的设置:
Linux 系统对于net.ipv4.tcp_tw_reuse的解释如下:
1 | Allow to reuse TIME-WAIT sockets for new connections when it is safe from protocol viewpoint. Default value is 0.It should not be changed without advice/request of technical experts. |
即从协议角度理解如果是安全可控的,可以复用处于 TIME_WAIT 的套接字为新的连接所用。
那么什么是协议角度理解的安全可控呢?主要有两点:
- 只适用于连接发起方(C/S 模型中的客户端);
- 对应的 TIME_WAIT 状态的连接创建时间超过 1 秒才可以被复用。
- 使用这个选项,还有一个前提,需要打开对 TCP 时间戳的支持,即net.ipv4.tcp_timestamps=1(默认即为 1)。
TCP 协议也在与时俱进,RFC 1323 中实现了 TCP 拓展规范,以便保证 TCP 的高可用,并引入了新的 TCP 选项,两个 4 字节的时间戳字段,用于记录 TCP 发送方的当前时间戳和从对端接收到的最新时间戳。由于引入了时间戳,前面提到的 2MSL 问题就不复存在了,因为重复的数据包会因为时间戳过期被自然丢弃。
总结:
TIME_WAIT的作用:
1) 确保对方能够正确收到最后的ACK,帮助其关闭;
2) 防迷走报文对程序带来的影响。
TIME_WAIT的危害:
1) 占用内存;
2) 占用端口。
3 - TCP三次握手和四次挥手的原因
三次握手的原因:
三次握手可以防止已经失效的连接请求报文突然又传输到服务器端导致的服务器资源浪费。
例如,客户端先发送了一个SYN,但是由于网络阻塞,该SYN 数据包在某个节点长期滞留。然后客户端又重传SYN 数据包并正确建立TCP 连接,然后传输完数据后关闭该连接。该连接释放后失效的SYN 数据包才到达服务器端。在二次握手的前提下,服务器端会认为这是客户端发起的又一次请求,然后发送SYN ,并且在服务器端创建socket 套接字,一直等待客户端发送数据。但是由于客户端并没有发起新的请求,所以会丢弃服务端的SYN 。此时服务器会一直等待客户端发送数据从而造成资源浪费。
四次挥手的原因:
因为当处于LISTEN状态的服务器端收到来自客户端的SYN报文(客户端希望新建一个TCP连接)时,它可以把ACK(确认应答)和SYN(同步序号)放在同一个报文里来发送给客户端。但在关闭TCP连接时,当收到对方的FIN报文时,对方仅仅表示对方已经没有数据发送给你了,但是自身可能还有数据需要发送给对方,则等你发送完剩余的数据给对方之后,再发送FIN报文给对方来表示你数据已经发送完毕,并请求关闭连接,所以通常情况下,这里的ACK报文和FIN报文都是分开发送的。
4 - 请问tcp 握手为什么两次不可以?为什么不用四次?
两次不可以:
- TCP 是全双工通信,两次握手只能确定单向数据链路是可以通信的,并不能保证反向的通信正常
详细解释:
这个问题的本质是:在信道不可靠的情况下, 通信双发需要就某个问题达成一致. 需要几次通信?
对于此问题,无论在消息中包含什么信息, 三次通信是理论上的最小值. 所以三次握手不是TCP本身的要求, 而是为了满足**”在不可靠信道上可靠地传输信息”**这一需求所导致的
具体来说:
- TCP连接的双方要确保各自的收发消息的能力都是正常的。
- 客户端第一次发送握手消息到服务端,服务端接收到握手消息后把ack和自己的syn一同发送给客户端,这是第二次握手,当客户端接收到服务端发送来的第二次握手消息后,客户端可以确认“服务端的收发能力OK,客户端的收发能力OK”,但是服务端只能确认“客户端的发送OK,服务端的接收OK”,
- 所以还需要第三次握手,客户端收到服务端的第二次握手消息后,发起第三次握手消息,服务端收到客户端发送的第三次握手消息后,就能够确定“服务端的发送OK,客户端的接收OK”,
- 至此,客户端和服务端都能够确认自己和对方的收发能力OK,TCP连接建立完成。
不用四次:
- 本来握手应该和挥手一样都是需要确认两个方向都能联通的,本来模型应该是:
- 客户端发送syn0 给服务器
- 服务器收到syn0,回复ack(syn0+1)
- 服务器发送syn1
- 客户端收到syn1,回复ack(syn1+1)
- 因为TCP是全双工的,上边的四步确认了数据在两个方向上都是可以正确到达的,但是2,3 步没有没有上下的联系,可以将其合并,加快握手效率,所有就变成了3 步握手。
5 - TCP协议是如何保证可靠传输的?
- (1)数据包校验:目的是检测数据在传输过程中的是否发生变化,若校验包有错,则丢弃报文段并且不给出响应,这时TCP发送端超时后重发数据
- (2)对失序数据包重排序:既然TCP报文段作为IP数据包来传输,而IP数据报的到达可能会失序,因此TCP报文段的到达也可能失序。TCP将对失序数据重新排序,然后才交给应用层
- (3)丢弃重复数据
- (4)应答机制:当TCP一端收到另一端的数据,它将发送一个确认。这个确认不是立即发送,通常会将推迟几分之一秒;
- (5)超时重发:当TCP发出一个段,会启动一个定时器,等待目的端确认收到这个报文段,如果不能及时收到一个确认,将重发这个报文段
- (6)流量控制:TCP连接的每一方都有固定大小的缓冲空间。TCP的接收端只允许另一端发送接收端缓冲区所能接纳的数据。TCP使用的流量控制协议是可变大小的滑动窗口协议。
- (7)拥塞控制算法(慢开始、拥塞避免、快重传、快恢复)
6 - TCP可靠性原理?
可靠传输有如下两个特点:
- 传输信道无差错,保证传输数据正确
- 不管发送方以多快的速度发送数据,接收方总是来得及处理收到的数据
- 首先,采用三次握手建立TCP连接,四次握手释放TCP连接,保证了传输信道是可靠的
- 其次,TCP采用了连续ARQ协议(回退N(Go-back-N),超时自动重传)来保证数据传输的正确性,使用滑动窗口协议来保证接收方能够及时处理所接收到的数据,进行流量控制
- 最后,TCP使用慢开始、拥塞避免、快重传、快恢复来进行拥塞控制,避免网络拥塞
7 - 谈谈你对流量控制的理解?
TCP利用窗口实现流量控制。流量控制是为了控制发送方发送速率,保证接收方来得及接收。接收方发送的确认报文中的窗口字段可以同来控制发送方窗口的大小,从而影响发送方的发送速率。将窗口字段设置为0,则发送方不能发送数据。
8 - 谈谈你对TCP滑动窗口的了解?
TCP利用滑动窗口实现流量控制。滑动窗口(Sliding Window)是一种流量控制技术。在早期的网络通信中,通信双方不会考虑网络的拥挤情况而直接发送数据。由于双方不知道网络拥塞状况,同时发送数据,导致中间节点阻塞丢包,谁也发不了数据,所有就有了滑动窗口机制来解决此问题
TCP中采用滑动窗口来进行传输控制,滑动窗口的大小意味着接收方还有多大的缓冲区可用于接收数据;发送方可以通过滑动窗口的大小来确定应该发送多少字节的数据。
当滑动窗口为0时,发送方一般不能再发送数据报,有两种情况除外:
一种情况是可以发送紧急数据,例如,允许用户终止在远端机上的运行进程。
一种情况是发送方可以发送一个1字节的数据报来通知接收方重新声明它希望接收的下一个字节及发送方的滑动窗口大小。
9 - 谈下对TCP拥塞控制的理解?
拥塞控制和流量控制不同:
- 拥塞控制是一个全局性的过程
- 流量控制是点对点通信量的控制
在某段时间,若对网络中某一资源的需求超过了该资源所能提供的可用部分,网络的性能就会变差,这种情况就叫拥塞。
拥塞控制就是为了防止过多的数据注入到网络中,这样就使网络中的路由器或链路不致于过载。拥塞避免所要做的都有一个前提,就是网络能够承受现有的网络负载,拥塞控制是一个全局性的过程,涉及到所有的主机、路由器,以及与降低网络传输性能有关的所有因素。相反,流量控制往往是点对点的通信量的控制,是个端到端的问题。流量控制所要做的就是抑制发送端发送数据的速率,以便于接收端来得及接收。
为了进行拥塞控制,TCP发送方要维持一个拥塞窗口(cwnd)。拥塞窗口的大小取决于网络的拥塞程度,并且动态变化。发送方让自己的发送窗口取拥塞窗口和接收方接收窗口中较小的一个。 swnd = min(cwnd, rwnd)
TCP的拥塞控制采用了四种算法 (慢开始、拥塞避免、快重传、快恢复),在网络层也可以使路由器采用适当的分组丢弃策略(如:主动队列管理 AQM),以减少网络拥塞的发生。
- 慢启动:定义拥塞窗口,一开始将该窗口大小设为
1
,之后每次收到确认应答(经过一个RTT
),将拥塞窗口大小乘2。如果一次性把大量数据注入网络,那么可能会引起网络阻塞,较好的方法是先探测一下,即由小到大逐渐扩大发送窗口。 - 拥塞避免:设置慢启动阈值,一般开始都设为
65536
。拥塞避免是指当拥塞窗口大小达到这个阈值,拥塞窗口的值不再指数上升,而是加法增加(每次确认应答/每个RTT,拥塞窗口大小+1
),以此来避免拥塞。 - 将报文段的超时重传看做拥塞,则一旦发生超时重传,需要先将阈值设为当前窗口大小的一半,并且将窗口大小设为初值1,然后重新进入慢启动过程。为了避免这种情况,从而有了快重传算法。
- 快重传:当接收方收到
M1
和M2
后,都分别及时发送确认,但是如果接收方没有收到M3
,却收到了M4
、M5
和M6
,但接收方收到后也仍然要再次分别发出对M2
的重复确认,这样发送方就收到了4个对M2
的确认,其中后三个是重复的确认。快重传算法规定,发送方只要一连收到3个重复确认,就知道接收方没有收到M3
因而应当立即进行快重传,这样就不会出现超时。 - 快恢复:当发送方知道只是丢失了个别的报文段,不会启动慢开始算法,而是执行快恢复算法。将阈值设为当前窗口大小的一半,同时设置拥塞窗口为阈值的大小,然后执行拥塞避免算法。
通过拥塞控制算法,在TCP 通信时,网络吞吐量呈现逐渐的上升,并且随着拥堵来降低吞吐量,再进入慢慢上升的过程,网络不会轻易的发生瘫痪。
10 - TCP拥塞控制如何实现的?
TCP发送方要维持一个拥塞窗口(cwnd),而发送窗口的值是 swnd = min(cwnd, rwnd),也就是拥塞窗口和接收窗口中的最小值。
拥塞控制是防止过多的数据注入网络,使得网络中的路由器或者链路过载。流量控制是点对点的通信量控制,而拥塞控制是全局的网络流量整体性的控制。发送双方都有一个拥塞窗口— cwnd。
(1)慢开始:
- 最开始发送方的拥塞窗口 cwnd 为1,由小到大逐渐增大发送窗口和拥塞窗口。每经过一个传输轮次,拥塞窗口cwnd 加倍。当cwnd 超过慢开始门限,则使用拥塞避免算法,避免cwnd 增长过大。
(2)拥塞避免:
- 每经过一个往返时间RTT,拥塞窗口cwnd 就增长1。
- 在慢开始和拥塞避免的过程中,一旦发现网络拥塞,就把慢开始门限设为当前值的一半,并且重新设置拥塞窗口 cwnd 为1,重新慢启动。(乘法减小,加法增大)
(3)快重传:
- 接收方每次收到一个失序的报文段后就立即发出重复确认,发送方只要连续收到三个重复确认就立即重传(尽早重传未被确认的报文段)。
(4)快恢复:
- 当发送方连续收到了三个重复确认,就乘法减半(慢开始门限减半),将当前的拥塞窗口 cwnd 设置为慢开始门限,并且采用拥塞避免算法(连续收到了三个重复请求,说明当前网络可能没有拥塞)。
- 采用快恢复算法时,慢开始只在建立连接和网络超时才使用。
11 - 什么是粘包?TCP粘包是怎么产生的?
什么是粘包?
如果客户端连续不断的向服务端发送数据包时,服务端接受的数据会出现两个数据报粘在一起的情况。
接收端收到了两个数据包,但是这两个数据包要么是不完整的,要么就是多出一块,这种情况即发生了拆包和粘包,拆包和粘包的问题导致接收端在处理的时候会非常困难,因为无法区分一个完整的数据包。
- TCP是基于字节流的,虽然应用层和TCP传输层之间的数据交互是大小不等的数据块,但是TCP把这些数据块仅仅看成一连串无结构的字节流,没有边界。
- 从TCP的帧结构上也可以看出,在TCP的首部没有表示数据长度的字段
基于以上两点,在使用TCP传输数据时,才有粘包或拆包现象发生的可能。一个数据包中包含了发送端发送的两个数据包的信息,这种现象即为粘包
12 - TCP粘包是怎么产生的?
发送方产生粘包
- 采用TCP协议传输数据的客户端与服务器经常是保持一个长连接的状态(一次连接发一次数据不存在粘包),双方在连接不断开的情况下,可以一直传输数据。但当发送的数据包过于小的时候,TCP协议默认会启用Nagle算法,将这些较小的数据包进行合并发送;这个合并过程就是在发送缓冲区中进行的,也就是说数据发送出来的时候它就已经是粘包的状态了。
接收方产生粘包
- 接收方采用TCP协议接收数据时的过程是这样的:数据到接收方,从网络模型的下方传递至传输层,传输层的TCP协议处理是将其放置接收缓冲区,然后由应用层来主动获取(C采用recv、read等函数);这时会出现一个问题,就是我们在程序中调用的读取数据函数不能及时的把缓冲区的数据拿出来,而下一个数据又到来并有一部分放入的缓冲区末尾,等我们读取数据时就是一个粘包。(放数据的速度 > 应用层拿数据速度)
13 - 怎么解决拆包和粘包?
分包机制一般有两个通用的解决方法:
- 特殊字符控制
- 在包头首部添加数据包的长度
如果使用netty框架的话,就有专门的编码器和解码器解决拆包和粘包的问题了
UDP没有粘包问题!
UDP没有粘包问题,但是有丢包和乱序问题。不完整的包是不会有的,收到的都是完全正确的包。传送的数据单位协议是UDP报文或用户数据报,发送的时候既不合并,也不拆分。
14 - 说一说TCP与UDP的特点?
TCP协议的主要特点:
- TCP是面向连接的运输层协议;面向连接就是双方在传输数据之前,必须建立一条通道,例如三次握手就是建立通道的一个过程,四次挥手则是结束销毁通道的一个过程
- 每一条TCP连接只能有两个端点,是点对点的
- TCP提供可靠的传输服务,传送的数据无差错、不丢失、不重复、按序到达
- TCP提供全双工的通信。允许通信双方的应用进程在任何时候都可以发送数据,因为两端都设有发送缓存和接收缓存
- 面向字节流。虽然应用程序与TCP交互是一次一个大小不等的数据库,但TCP把这些数据看成一连串无结构的字节流,它不保证接收方收到的数据块和发送方发送的数据块具有对应大小关系,例如发送方应用程序交给发送方的TCP10个数据块,但接收方的TCP可能只用了4个数据块就保证收到的字节流交付给上层的应用,但字节流完全一样。
UDP协议的主要特点:
- UDP是无连接的传输层协议
- UDP支持一对一、一对多、多对多的交互通信
- UDP是尽最大努力交付,但不保证可靠交付,不能保证数据的有序性
- UDP是面向报文的,对应用层交下来的报文,不合并,不拆分,只保留原报文的边界
- UDP没有拥塞控制,即时网络出现拥塞也不会降低发送速率
- UDP的首部开销小,只有8个字节
15 - 说一说TCP与UDP的区别?:
(1)连接:
- TCP 是面向连接的传输层协议,即传输数据之前必须先建立好连接。
- UDP是无连接的。
(2)服务对象:
- TCP 是点对点的两点间服务,即一条 TCP 连接只能有两个端点;
- UDP 支持一对一,一对多,多对一,多对多的交互通信。
(3)可靠性:
- TCP 是可靠交付:无差错,不丢失,不重复,按序到达。
- UDP 是尽最大努力交付,不保证可靠交付。
(4)拥塞控制,流量控制:
TCP 有拥塞控制和流量控制保证数据传输的安全性。
UDP 没有拥塞控制,网络拥塞不会影响源主机的发送效率。
(5) 报文长度:
- TCP 是动态报文长度,即 TCP 报文长度是根据接收方的窗口大小和当前网络拥塞情况决定的。
- UDP 面向报文,不合并,不拆分,保留上面传下来报文的边界。
(6)首部开销:
- TCP 首部开销大,首部 20 个字节。
- UDP 首部开销小,8 字节。(源端口,目的端口,数据长度,校验和)
(7)TCP传输速度比UDP慢,TCP是重量级协议、UDP是轻量级协议
16 - TCP和UDP适用场景有哪些?
TCP 是可靠的但传输速度慢,UDP 是不可靠的但传输速度快。因此 在选用具体协议通信时,应该根据通信数据的要求而决定。
文件传输、重要状态的 更新等适合使用TCP
视频传输、实时通信等使用UDP效果更好
17 - 基于TCP和UDP的常用协议有哪些?
TCP对应的应用层协议:
- HTTP :80端口 、HTTPS:443端口
- FTP:21端口,文件传输协议
- TELNET:23端口,远程终端协议,是一种用于远程登录的端口,用户可以以自己的身份远程连接到计算机上,通过这种端口可以提供一种基于DOS模式下的通信服务。
- SMTP:25端口,简单邮件传输协议,用于发送邮件
- POP3:110端口,用于接收邮件
UDP对应的应用层协议:
- TFTP:69端口,简单文件传输协议
- DNS:53端口,用于域名解析服务,将域名地址转换为IP地址
- SNMP:161端口:简单网络管理协议,用来管理网络设备
- DHCP:动态主机配置协议,DHCP服务器使用UDP端口67,DHCP客户端从UDP端口68发送DHCP发现报文
UDP的其他协议:RIP(路由信息协议),位于网络层
18 - 网络层如何知道报文应该给哪个应用程序,又如何区分UDP报文和TCP报文?
根据端口分区
看报文头部的协议标识字段,17是UDP,6是TCP
19 - 说一说 HTTP1.0、HTTP1.1、HTTP2.0的区别?
HTTP1.0
- HTTP1.0规定浏览器与服务器只保持短暂的连接,浏览器的每次请求都需要与服务器建立一个TCP连接,服务器完成请求处理后立即断开TCP连接。就像打电话一样,一次只能说一件事,说完就要挂断,又因为TCP连接建立一次需要三次握手,所以效率很低。
如果不想断开连接,需要在HTTP相应的Connection字段指定为keep-live
1 | connection:keep-alive; |
HTTP1.1
HTTP1.1引进了持久连接,TCP连接默认不关闭,可以被多个请求复用。客户端和服务端发现对方一段时间没有活动后,可以主动关闭连接;或者客户端在最后一个请求时,主动告诉服务端要关闭连接。
HTTP1.0就像打一次电话只能说一次事,HTTP1.1是打完电话先不直接挂断,而是持续一会,这期间如果有事情还可以再次沟通。
HTTP1.1还引入了管道机制,即在同一个TCP连接里,客户端可以同时发送多个请求,这样就进一步改进了HTTP协议的效率。
HTTP2.0
HTTP2.0采用了多路复用,即在一个连接里,客户端和浏览器都可以同时发送多个请求或回应,而且不用按顺序一一对应。能这样做有一个前提,就是HTTP2.0进行了二进制分帧,即会将所有传输的信息分割为更小的消息和帧,并对它们采用二进制格式的编码。
负责这个拆分、组装请求和二进制帧的一层就叫做二进制分帧层
也就是说,老板可以同时下达多个命令,员工也可以收到请求A和请求B,于是先回应A,结果发现处理A非常耗时,于是就发送A请求已经处理好的部分,接着回应B请求,完成后 ,再发送A请求剩下的部分。A请求的两部分响应再组合到一起发送给老板
除此之外还有一些其他的优化,比如Header压缩、服务端推送等
- Header压缩就是压缩老板和员工之间的对话
- 服务端推送就是员工事先把一些老板可能询问的事情提前发送到老板的手机上(缓存)。这样老板想要知道的时候就可以直接读取短信(缓存)了。
HTTP发展历程:
- HTTP 协议始于三十年前蒂姆·伯纳斯 - 李的一篇论文;
- HTTP/0.9 是个简单的文本协议,只能获取文本资源;
- HTTP/1.0 确立了大部分现在使用的技术,但它不是正式标准;
- HTTP/1.1 是目前互联网上使用最广泛的协议,功能也非常完善;
- HTTP/2 基于 Google 的 SPDY 协议,注重性能改善,但还未普及;
- HTTP/3 基于 Google 的 QUIC 协议,是将来的发展方向。
20 - HTTP协议有哪些特点?
HTTP是什么?
- **HTTP 是一个用在计算机世界里的协议,它确立了一种计算机之间交流通信的规范,以
及相关的各种控制和错误处理方式。 **(定义) - HTTP 专门用来在两点之间传输数据,不能用于广播、寻址或路由。
- HTTP 传输的是文字、图片、音频、视频等超文本数据。
- HTTP 是构建互联网的重要基础技术,它没有实体,依赖许多其他的技术来实现,但同
时许多技术也都依赖于它。
HTTP协议概念:
- HTTP 协议是 Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维网(WWW:World Wide Web)服务器传输超文本到本地浏览器的传送协议。
- HTTP 是一个基于 TCP/IP 通信协议来传递数据(HTML 文件,图片文件,查询结果等)。
- HTTP 是一个属于应用层的面向对象的协议,由于其简捷、快速的方式,适用于分布式超媒 体信息系统。
- HTTP协议工作于客户端-服务端架构为上。浏览器作为HTTP客户端通过URL向HTTP服务端(即 WEB 服务器)发送所有请求。Web 服务器根据接收到的请求后,向客户端发送响应信息。
HTTP协议特点:
- 简单快速:
- 客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有 GET、HEAD、POST。 每种方法规定了客户与服务器联系的类型不同。由于 HTTP 协议简单,使得 HTTP 服务器的程序规模小,因而通信速度很快。
- 灵活:
- HTTP 允许传输任意类型的数据对象。正在传输的类型由 Content-Type 加以标记
- 无连接:
- 无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应 答后,即断开连接。采用这种方式可以节省传输时间。
- 无状态:
- HTTP 协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如 果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方 面,在服务器不需要先前信息时它的应答就较快。
- 支持 B/S 及 C/S 模式
- 默认端口为80
- 基于TCP协议
21 - HTTP返回码
HTTP 协议的响应报文由状态行、响应头部和响应包体组成,其响应状态码总体描述如下:
- 1xx:指示信息–表示请求已接收,继续处理。
- 2xx:成功–表示请求已被成功接收、理解、接受。
- 3xx:重定向–要完成请求必须进行更进一步的操作。
- 4xx:客户端错误–请求有语法错误或请求无法实现。
- 5xx:服务器端错误–服务器未能实现合法的请求。
常见状态代码、状态描述的详细说明如下:
- 200 OK:客户端请求成功。
- 206 partial content 服务器已经正确处理部分GET 请求,实现断点续传或同时分片下载,该请求必须包含Range 请求头来指示客户端期望得到的范围
- 300 multiple choices(可选重定向):被请求的资源有一系列可供选择的反馈信息,由浏览器/用户自行选择其中一个。
- 301 moved permanently(永久重定向):该资源已被永久移动到新位置,将来任何对该资源的访问都要使用本响应返回的若干个URI 之一。
- 302 move temporarily(临时重定向):指页面暂时性转移,表示资源或页面暂时转移到另一个位置,常被用作网络劫持,容易导致网站降权,严重时网站会被封掉,不推荐使用
- 304:not modified :如果客户端发送一个待条件的GET 请求并且该请求以经被允许,而文档内容未被改变,则返回304,该响应不包含包体(即可直接使用缓存)。
- 403 Forbidden:服务器收到请求,但是拒绝提供服务。
- 404 :服务器无法根据客户端的请求找到资源(网页)。通过此代码,网站设计人员可设置 您所请求的资源无法找到” 的个性页面
22 - HTTP如何实现长连接?在什么时候会超时?
通常在头部(请求和响应头)设置Connection: keep-alive,HTTP1.0协议支持,但默认是关闭,从HTTP1.1协议开始,连接默认都是长连接
长连接什么时候会超时?
- HTTP一般会有httpd守护进程,里面可以设置 keep-alive timeout,当TCP连接闲置时间超过这个时间就会关闭,可以在HTTP的header里面设置超时时间
- TCP的 keep-alive 包含三个参数,支持在系统内核的 net.ipv4 里面设置:当TCP连接之后,设置了tcp_keepalive_time时间,则会发送侦测包,如果没有收到对方的ACK,那么每隔tcp_keepalive_intvl再发一次,直到发送了tcp_keepalive_probes,就会丢弃该链接
- tcp_keepalive_time = 1800
- tcp_keepalive_intvl = 15
- tcp_keepalive_probes = 5
- 实际上HTTP没有长短连接,只有TCP有,TCP长连接可以复用一个TCP连接来发起多次HTTP请求,这样就可以减少资源消耗,比如一次请求HTML,可能还需要请求后续的 JS/CSS/图片等。(重要!!!)
23 - HTTP方法有哪些?
客户端发送的请求报文第一行为行为请求,包含了方法字段:
- GET:获取资源,当前网络绝大部分使用的都是GET
- POST:传输实体主体
- HEAD:获取报文首部,和GET方法类似,但是不返回报文实体主体部分
- PUT:上传文件,由于自身不带验证机制,任何人都可以上传文件,因此存在安全性问题,一般不使用该方法
- PATCH:对资源进行部分修改。PUT也可以用于修改资源,但是只能完全替代原始资源,PATCH允许部分修改
- OPTIONS:查询指定的URL支持的方法
- CONNECT:要求在与代理服务器通信时建立隧道,使用SSL(Secure Sockets Layer,安全套接层)和TLS(Transport Layer Security,传输层安全)协议把通信内容加密后经网络隧道传输。
- TRACE:追踪路径,服务器会将通信返回给客户端。发送请求时,在Max-Forwards首部字段中填入数值,每经过一个服务器就减1,当数值为0时就停止传输。通常不会使用TRACE,因为其易受到XST攻击(Cross-Site Tracing,跨站追踪)。
24 - forward 和 redirect 的区别?
Forward 和 Redirect 代表了两种请求转发方式:直接转发和间接转发。
- 直接转发方式(Forward):客户端和浏览器只发出一次请求,Servlet、HTML、JSP或其他信息资源,由第二个信息资源响应该请求,在请求对象request中,保存的对象对于每个信息资源是共享的。
- 间接转发方式(Redirect):实际是两次HTTP请求,服务端在响应第一次请求的时候,让浏览器再向另外一个URL发出请求,从而达到转发的目的
25 - GET 和 POST 的区别
概括:
对于GET 方式的请求,浏览器会把http header 和data 一并发送出去,服务器响应200(返回数据)
而对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)
区别:
- (1)get 参数通过 url 传递,post 放在 request body 中。
- (2)get 请求在 url 中传递的参数是有长度限制的,而 post 没有。
- (3)get 比 post 更不安全,因为参数直接暴露在 url 中,所以不能用来传递敏感信息。
- (4)get 请求只能进行 url 编码,而 post 支持多种编码方式。
- (5)get 请求会浏览器主动 cache,而 post 支持多种编码方式。
- (6)get 请求参数会被完整保留在浏览历史记录里,而post 中的参数不会被保留。
- (7)GET 和POST 本质上就是TCP 连接,并无差别。但是由于HTTP 的规定和浏览器/服务器的限制,导致他们在应用过程中体现出一些不同。
- (8)GET 产生一个TCP 数据包;POST 产生两个TCP 数据包。
26 - GET请求中URL编码的意义?
在GET请求中会对URL中非西方文字进行编码,这样做是为了避免歧义
对一些特殊字符如&,解析时会产生歧义,比如将 name1=va&lu=e1
编码成 name1=va%26lu%3D
,这样服务端就会把%后的字节当成普通的字节,不会把它当成各个参数或键值对的分隔符。
27 - HTTP的过程是什么?
HTTP 协议定义 Web 客户端如何从 Web 服务器请求 Web 页面,以及服务器如何把 Web 页面传 送给客户端。HTTP 协议采用了请求/响应模型。客户端向服务器发送一个请求报文,请求报文包 含请求的方法、URL、协议版本、请求头部和请求数据。服务器以一个状态行作为响应,响应的 内容包括协议的版本、成功或者错误代码、服务器信息、响应头部和响应数据。
(1)客户端连接到Web服务器:
一个HTTP 客户端,通常是浏览器,与Web 服务器的HTTP 端口(默认为80)建立一个TCP套接字连接。例如,http://www.baidu.com。
(2)发送HTTP请求:
通过TCP 套接字,客户端向Web 服务器发送一个文本的请求报文,一个请求报文由4 部分组成:
- 请求行
- 请求头部
- 空行
- 请求数据
(3)服务器接受请求并返回HTTP响应:
Web 服务器解析请求,定位请求资源。服务器将资源复本写到TCP 套接字,由客户端读取。一个响应由4 部分组成:
- 状态行
- 响应头部
- 空行
- 响应数据
(4)释放连接TCP 连接:
- 若connection 模式为close,则服务器主动关闭TCP 连接,客户端被动关闭连接,释放TCP连接;
- 若connection 模式为keepalive,则该连接会保持一段时间,在该时间内可以继续接收请求;
(5)客户端浏览器解析HTML 内容:
- 客户端浏览器首先解析状态行,查看表明请求是否成功的状态代码。
- 然后解析每一个响应头,响应头告知以下为若干字节的HTML 文档和文档的字符集。
- 客户端浏览器读取响应数据HTML,根据HTML 的语法对其进行格式化,并在浏览器窗口中显示。
28 - 在浏览器输入URL地址到显示主页的过程?
大概过程:
(1)浏览器向DNS 服务器请求解析该URL 中的域名所对应的IP 地址;
(2)解析出IP 地址后,根据该IP 地址和默认端口80,和服务器建立TCP 连接;
(3)浏览器发出读取文件(URL 中域名后面部分对应的文件)的HTTP 请求,该请求报文作为TCP 三次握手的第三个报文的数据发送给服务器;
(4)服务器对浏览器请求作出响应,并把对应的html 文本发送给浏览器;
(5)释放TCP 连接;
(6)浏览器将该html 文本解析后显示网页内容;
细致过程(笔试原题,排序):
1、浏览器输入URL,先解析URL地址是否合法
2、浏览器检查是否有缓存(浏览器缓存 - 系统缓存 - 路由器缓存)。如果有,直接显示。没有,进行(3)
3、在发送HTTP请求前,需要域名解析(DNS解析),解析获取对应的IP地址
4、浏览器向服务器发起TCP连接,进行TCP连接的三次握手
5、握手成功后,浏览器向服务器发送HTTP请求,请求数据包
6、服务器收到请求,进行处理后将数据发送给浏览器(请求报文作为TCP 三次握手的第三个报文的数据发送给服务器)
7、浏览器收到HTTP响应
8、浏览器解析响应,如果响应可以缓存则存入缓存
9、浏览器发送请求获取嵌入在HTML的资源(HTML、CSS、JS等),对于未知类型,会弹出对话框
10、浏览器发送异步请求
11、页面全部渲染结束显示网页
29 - 搜索 www.baidu.com,会用到计算机网络中的那些层?每层的作用?
全过程:
1、域名解析:浏览器获得URL地址,向操作系统请求该URL对应的IP地址,操作系统查询DNS(首先查询本地HOST文件,没有则查询网络)获得对应的IP地址
2、确认IP和端口号(不注明端口号则默认为80端口)后,则可以向该IP地址对应的服务器的该端口号发起TCP连接请求
3、服务器接收到TCP连接请求后,回复可以连接请求
4、浏览器收到回传的数据后,还会向服务器发送数据包,表示三次握手结束
5、三次握手成功后,开始通讯,根据HTTP协议的要求,组织一个请求的数据包,里面包含请求的资源路径、你的身份信息等,例如,www.abc.com/images/1/表示的资源路径是images/1/,发送后,服务器响应请求,将数据返回给浏览器,数据可以是根据HTML协议组织的网页,里面包含页面的布局、文字等等,也可以是图片或者脚本程序等,如果资源路径指定的资源不存在,服务器就会返回404错误,如果返回的是一个页面,则根据页面里的一些外链URL地址,重复上述步骤,再次获取
6、渲染页面,并开始响应用户的操作
7、窗口关闭时,浏览器终止与服务器的连接
用到的层和协议:
浏览器中输入URL
浏览器要将URL 解析为IP 地址,解析域名就要用到DNS 协议,首先主机会查询DNS 的缓存,如果没有就给本地DNS 发送查询请求。DNS 查询分为两种方式,一种是递归查询,一种是迭代查询。如果是迭代查询,本地的DNS 服务器,向根域名服务器发送查询请求,根域名服务器告知该域名的一级域名服务器,然后本地服务器给该一级域名服务器发送查询请求,然后依次类推直到查询到该域名的IP 地址。DNS 服务器是基于UDP的,因此还会用到UDP 协议。
得到 IP 地址后,浏览器就要与服务器建立一个HTTP 连接,因此要用到 HTTP 协议,HTTP 协议报文格式上面已经提到。HTTP 生成一个get 请求报文,将该报文传给传输层处理,所以还会用到TCP 协议。如果采用HTTPS 还会使用HTTPS 协议先对HTTP数据进行加密。传输层如果有需要先将HTTP 数据包分片,分片依据路径MTU 和MSS。TCP 的数据包然后会发送给网络层,用到IP协议。网络层通过路由选路,一跳一跳发送到目的地址。当然在一个网段内的寻址是通过以太网协议实现(也可以是其他物理层协议,比如PPP,SLIP),以太网协议需要知道目的IP 地址的物理地址,需要ARP 协议。
每层的作用:
1 - 应用层:DNS 、HTTP 、HTTPS :
应用层是体系结构中的最高层。应用层确定进程之间通信的性质以满足用户的需要。这里的进程就是指正在运行的程序。应用层不仅要提供应用进程所需要的信息交换和远地操作,而且还要作为互相作用的应用进程的用户代理,来完成一些为进行语义上有意义的信息交换所必须的功能。应用层直接为用户的应用进程提供服务
2 - 传输层:TCP、UDP:
传输层的任务就是负责主机中两个进程之间的通信。因特网的传输层可使用两种不同协议:即面向连接的传输控制协议TCP,和无连接的用户数据报协议UDP。面向连接的服务能够提供可靠的交付,但无连接服务则不保证提供可靠的交付,它只是“尽最大努力交付”。这两种服务方式都很有用,备有其优缺点。在分组交换网内的各个交换结点机都没有传输层。
3 - 网络层:IP、ARP:
网络层负责为分组交换网上的不同主机提供通信。在发送数据时,网络层将运输层产生的报文段或用户数据报封装成分组或包进行传送。在TCP/IP 体系中,分组也叫作IP 数据报,或简称为数据报。网络层的另一个任务就是要选择合适的路由,使源主机运输层所传下来的分组能够交付到目的主机。
4 - 数据链路层:
当发送数据时,数据链路层的任务是将在网络层交下来的IP 数据报组装成帧,在两个相邻结点间的链路上传送以帧为单位的数据。每一帧包括数据和必要的控制信息(如同步信息、地址信息、差错控制、以及流量控制信息等)。控制信息使接收端能够知道—个帧从哪个比特开始和到哪个比特结束。控制信息还使接收端能够检测到所收到的帧中有无差错。
5 - 物理层:
物理层的任务就是透明地传送比特流。在物理层上所传数据的单位是比特。传递信息所利用的一些物理媒体,如双绞线、同轴电缆、光缆等,并不在物理层之内而是在物理层的下面。因此也有人把物理媒体当做第0 层。
30 - HTTPS的工作过程?
HTTPS协议 = HTTP协议 + SSL/TLS协议
SSL(Secure Socket Layer 安全套接层)
TLS(Transport Layer Security 安全传输层协议)
由于HTTPS的推出受到了很多人的欢迎,在SSL更新到3.0时,IETF对SSL3.0进行了标准化,并添加了少数机制(但是几乎和SSL3.0无差异),标准化后的IETF更名为TLS1.0(Transport Layer Security 安全传输层协议),即 TLS就是SSL的3.1新版本
1、浏览器往服务器的443端口发起请求,请求里携带了浏览器支持的加密算法和哈希算法。
2、服务器收到请求,选择浏览器支持的加密算法和哈希算法,并将自己的身份信息(地址等)以证书的形式发送给浏览器,
3、客户端收到网站的证书之后要:
- 验证证书的合法性
- 如果验证通过,浏览器会生成一个随机数R,并用证书中的公钥进行加密,将加密的R传送给服务器
4、服务器接收客户端传来的信息:
- 用自己的私钥解密得到R,再用以R为密钥使用对称加密算法加密网页内容并传输给浏览器。
5、客户端以R为密钥使用之前约定好的解密算法获取网页内容
31 - HTTP 和 HTTPS 的区别?
HTTP 和 HTTPS的基本概念
- 超文本传输协议(Hyper Text Transfer Protocol,HTTP):是互联网上应用最为广泛的一种网络协议,是一个客户端和服务器端请求和应答的标准(TCP),用于从WWW服务器传输超文本到本地浏览器的传输协议,它可以使浏览器更加高效,使网络传输减少。
- HTTPS (全称:Hyper Text Transfer Protocol over SecureSocket Layer):是以安全为目标的HTTP通道,简单讲是HTTP的安全版,即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL。
- HTTPS协议的主要作用可以分为两种:
- 一种是建立一个信息安全通道,来保证数据传输的安全;
- 另一种就是确认网站的真实性。
- HTTPS协议的主要作用可以分为两种:
HTTPS 和 HTTP 的区别主要如下:
- 开销:HTTPS协议需要到CA申请证书,一般免费证书较少,因而需要一定费用。
- 端口不同:HTTP和HTTPS使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
- 安全性:HTTP的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比HTTP协议安全。
- 资源消耗:HTTP是超文本传输协议,信息是明文传输;HTTPS则是具有安全性的SSL加密传输协议,需要消耗更多的CPU和内存资源
- 在OSI模型中,HTTP工作于应用层,而HTTPS工作于传输层;
33 - HTTPS的优缺点?
HTTPS 优点:
- HTTPS 传输数据过程中使用密钥进行加密,所以安全性更高
- HTTPS 协议可以认证用户和服务器,确保数据发送到正确的用户和服务器
HTTPS 缺点:
HTTPS 握手阶段延时较高:由于在进行HTTP 会话之前还需要进行SSL 握手,因此HTTPS 协议握手阶段延时增加
HTTPS 部署成本高:一方面HTTPS 协议需要使用证书来验证自身的安全性,所以需要购买CA证书;另一方面由于采用HTTPS 协议需要进行加解密的计算,占用CPU 资源较多。
34 - 什么是数字签名?
为了避免数据在传输过程中被替换,比如黑客修改了报文内容,但是用户并不知道,所以需要让发送端做一个数字签名,把数据的摘要信息进行一个加密,比如MD5,得到一个签名,和数据一起发送。然后接收端把数据摘要进行MD5加密,如果和签名一样,则说明数据是正确的
35 - 什么是数字证书?
对称加密中,双方使用公钥进行解密。虽然数字签名可以保证数据不被替换,但数据是由公钥加密的,如果公钥也被替换,则仍然可以伪造数据,因为用户不知道对方提供的公钥是真是假。为了保证发送方的公钥是真的,CA证书机构会负责颁发一个证书,里面的公钥确保是真的,用户请求服务器时,服务器将证书给用户,这个证书是经由系统内置证书的备案过的。
36 - 谈谈你对停止等待协议(数据链路层)的理解?
停止等待协议是为了实现可靠传输的,它的基本原理就是每发完一个分组就停止发送,等待对方确认,在收到确认后再发下一个分组。在停止等待协议中,若接收方收到重复分组,就丢弃该分组,但同时还要发送确认。主要包括以下几种情况:
- 无差错情况
- 出现差错情况(超时重传)
- 确认丢失和确认迟到
37 - 谈谈你对ARQ协议(数据链路层)的理解?
自动重传请求协议 ARQ
停止等待协议中超时重传是指只要超过一段时间仍然没有收到确认,就重传之前发过的分组。因此每发送完一个分组就需要设置一个超时计时器,其重传时间应该比数据在分组传输的平均往返时间更长一些。这种自动重传方式称为自动重传请求ARQ
连续ARQ协议
连续ARQ可提高信道利用率。发送方维持一个发送窗口,凡是位于窗口内的分组可以连续发送出去,而不需要等待对方确认。接收方一般采用累计确认,对按序到达的最后一个分组发送确认,表明到这个分组为止是所有分组都已经正确收到。
38 - ARP协议(地址转换协议)的工作原理
ARP协议完成了IP地址与物理地址的映射。
ARP(地址解析)协议是一种解析协议,本来主机是完全不知道这个IP对应的是哪个主机的哪个接口,当主机要发送一个IP包的时候,会首先查一下自己的ARP高速缓存表(最近数据传递更新的IP-MAC地址对应表),如果查询的IP-MAC值对不存在,那么主机就向网络广播一个ARP请求包,这个包里面就有待查询的IP地址,而直接收到这份广播的包的所有主机都会查询自己的IP地址,如果收到广播包的某一个主机发现自己符合条件,那么就回应一个ARP应答包(将自己对应的IP-MAC对应地址发回主机),源主机拿到ARP应答包后会更新自己的ARP缓存表。源主机根据新的ARP缓存表准备好数据链路层的的数据包发送工作。
39 - DNS的解析过程?
- 请求一旦发起,若是chrome浏览器,先在浏览器找之前有没有缓存过的域名所对应的IP地址,有的话,直接跳过dns解析,若是没有,就会找硬盘的hosts文件,查找hosts文件中是否有对应的IP地址
- 如果本地的hosts文件没有对应的IP地址,浏览器会发出一个DNS请求到本地DNS服务器,本地DNS服务器一般是网络接入服务器商提供,比如中国电信,中国移动等。
- 查询输入的网址的DNS请求到达本地DNS服务器之后,本地DNS服务器会首先查询它的缓存记录,如果缓存中有此条记录,就可以直接返回结果,此过程是递归查询。如果没有,本地DNS服务器还要向DNS根服务器进行查询。
- 根域名服务器收到本地域名服务器发出的迭代查询请求报文时,要么给出所要查询的IP地址,要么告诉本地服务器:”你下一步应当向哪一个域名服务器进行查询。”然后让本地服务器进行后续的查询。本地DNS服务器继续向域服务器发出请求,比如请求的对象是.com域服务器。.com域服务器收到请求之后,也不会直接返回域名和IP地址的对应关系,而是告诉本地DNS服务器,你的域名的解析服务器的地址。
- 最后,本地DNS服务器向域名的解析服务器发出请求,这时就能收到一个域名和IP地址对应关系,本地DNS服务器不仅要把IP地址返回给用户电脑,还要把这个对应关系保存在缓存中,以备下次别的用户查询时,可以直接返回结果,加快网络访问。
主机向本地域名服务器的查询一般都是采用递归查询。
本地域名服务器向根域名服务器的查询是迭代查询。
40 - 谈谈你对域名缓存的了解?
为了提高DNS查询效率,并减轻服务器的负荷和减少因特网上的DNS查询报文的数量,在域名服务器中广泛应用了高速缓存,用来存放最近查询过的域名以及从何处获得域名映射信息的记录
41 - IP地址有哪些分类?
A类地址(1~126):网络号占前8位,以0开头,主机号占24位
B类地址(128~191):网络号前16位,以10开头,主机号占后16位
C类地址(192~223):网络号前24位,以110开头,主机号占后8位
D类地址(224~239):以1110开头,保留位多播地址
E类地址(240~255):以1111开头,保留位今后使用
42 - 特殊网络地址:
(1)127.0.0.1:
127是一个保留地址,该地址是指电脑本身,主要作用是预留下作为测试使用,即Windows下的localhost
(2)**10.*.*.*,172.16.*.*――172.31.*.*,192.168.*.***:
上面三个网段是私有地址,可以用于自己组网使用,这些地址主要用于企业内部网络中,但不能够在Internet网上使用
(3)0.0.0.0
它表示的是这样一个集合,所有不清楚的主机和目的网络。这里的不清楚是指在本机的路由表里没有特定条目指明如何到达。
(4)255.255.255.255
受限制的广播地址
(5)224.0.0.0—239.255.255.255
这是一组组播地址,需要注意它与广播地址的区别,其中224.0.0.1特指所有的主机,224.0.0.2特指所有的路由器,224.0.0.5指所有的OSPF路由器地址,224.0.0.13指PIMV2路由器的地址。
43 - 什么是SQL注入?举个例子
SQL注入就是通过SQL命令插入到 Web表单提交 或 输入域名 或 页面请求的字符串,最终达到欺骗服务器执行恶意的SQL命令。
如果在一个登录界面,要求输入用户名或密码,可以这样输入:
1 | 用户名:'or 1 = 1 -- |
从理论上来说后台会验证如下SQL语句:
1 | String sql = "select * from user_table where username= ' " + userName +" ' and password='" +password +" ''"; |
当输入上面的用户名后,SQL语句变为
1 | SELECT * FROM user_table WHERE username = '' or 1 = 1 -- and password=' ' |
此语句一定可以执行成功,后面密码编程注释。用户轻易骗过系统,获取合法身份
解决方法:使用正则表达式过滤传入参数
44 - 什么是XSS攻击?
XSS攻击是指恶意攻击者利用网站没有对用户提交数据进行转义处理或过滤不足的缺点,进而添加一些脚本代码嵌入到web页面中去,使别的用户访问都会执行相应的嵌入代码,从而盗取用户资料、利用用户身份进行某种动作或对访问者进行病毒侵害的一种攻击方式
45 - Cookie 和 Session 有什么区别?
1、由于HTTP协议是无状态的协议,所以服务端需要记录用户的状态时,就需要某种机制来识别具体的用户,这个机制就是Session。典型的应用场景:购物车
当点击下单按钮时,由于HTTP是无状态的,所以并不知道是哪个用户操作 的,所以服务端要为特定的用户创建特点的Session,用于标识这个用户,并跟踪这个用户,才知道其购物车中的物品
Session是保存在服务端的,有一个唯一标识。在服务端保存Session的方法很多,内存、数据库、文件都有,集群的时候也要考虑Session的转移,在大型的网站,一般会有专门的Session服务器集群,用来保存用户会话,这个时候Session信息都是放在内存的,使用一些缓存服务比如Memcached之类的来存放。
2、那服务端如何识别特定用户?这时需要用到Cookie。每次HTTP请求的时候,客户端都会发送相应的Cookie信息到服务端。实际上大多数的应用都是用Cookie来实现Session追踪的,第一次创建Session的时候,服务端会在HTTP协议中告诉客户端,需要在Cookie里面记录一个Session ID,以后每次请求把这个会话ID发送到服务器,服务器就能识别特定用户了。
3、Cookie可以保存账号信息,访问网站的时候,网站页面的脚本可以读取这个信息,自动填写用户名
总结:
- Session是在服务端保存的一个数据结构,用来追踪用户的状态,这个数据可以保存在集群、数据库、文件中。
- Cookie是客户端保存用户信息的一种机制,用来记录用户的一些信息,也是实现Session的一种方式
46 - Session的工作原理?
Session的工作原理是客户端登录完成之后,服务器会创建对应的Session,Session创建完之后,会把Session的ID发送给客户端,客户端再存储到浏览器中。这样客户端每次访问服务器时,都会带着SessionID,服务器拿到SessionID之后,在内存找到与之对应的Session 这样就可以正常工作了。
47 - Udp如何实现可靠性
- 1.udp可以增加消息编号;
- 2.对每个消息编号提供ACK,在udp应用层增加应答机制;
- 3.没有应答的增加重传机制
- 4.增加缓存,ACK完的才从缓存中清除
二、网络编程
1 - socket 编程步骤
服务器的工作流程:
- (1)创建 socket:创建服务端的socket。
- (2)绑定 bind:把服务端用于通信的地址和端口绑定到socket上。
- (3)监听 listen:把socket设置为监听模式。
- (4)接受连接 accept:接受客户端的连接。
- (5)通信 recv( ) / send( ) :与客户端通信,接收客户端发过来的报文后,回复处理结果,重复此过程。
- (6)关闭 close( ):关闭socket,释放资源。
客户端工作流程:
- (1)创建 socket:创建客户端的socket。
- (2)发送连接 connect( ):向服务器发起连接请求
- (3)通信 recv( ) / send( ):与服务端通信,发送一个报文后等待回复,然后再发下一个报文。重复此过程,直到全部的数据被发送完。
- (4)关闭 close( ):关闭socket,释放资源。
2 - tcp三次握手的过程中,accept发生在三次握手的哪个阶段?
客户端的connect引起三次握手
服务器在socket、bind、listen后,阻塞在accept,三次握手完成后,accept返回一个fd,因此accept发生在三次握手后。
3 - 请问server 端监听端口,但还没有客户端连接进来,此时进程处于什么状态?
这个取决于看服务端的编程模型:
- 正常处于阻塞状态,
- 如果使用了epoll,select 等这样的 io 复用情况下,处于运行状态
4 - IO模型有哪几种?
- 多路复用IO
- 阻塞IO
- 非阻塞IO
- 信号驱动IO
- 异步IO
5 - 什么是IO多路复用?
I/O多路复用的本质是使用select ,poll 或 epoll函数,挂起进程,当一个或多个IO事件发生之后,将控制返回给用户进程。
以服务器编程为例,传统的多进程(多线程)并发模型,在处理用户连接时都是开启一个新的线程或进程去处理一个新的连接,而IO多路复用则是可以在一个进程(线程)中同时监听多个网络IO事件,也就是多个文件描述符
6 - IO多路复用的优缺点?
优点:
- 相比基于进程的模型,IO多路复用给程序员更多的程序行为控制
- IO多路复用只需要一个进程就可以处理多个事件,单个进程使得数据共享变得更容易,调试也更容易
- 在单一的进程上下文中,不会有多进程多线程模型的切换开销
缺点:
- 业务逻辑处理困难,编程困难
- 不能充分利用多核处理器
7 - 说一说select的缺点?
每次调用select,都需要把监听的文件描述符集合 fd_set从用户态拷贝多内核态,从算法角度来说就是$O(N)$的时间开销
每次调用select返回之后都需要遍历所有文件描述符,判断哪些文件描述符有读写事件发生,也是$O(N)$的时间开销
内核对被监控的文件描述符的集合大小做了限制,并且这个是通过宏控制的,大小不可改变,为1024。这一点和上一个缺点是矛盾的,文件描述符设大了,遍历时间就长,其效率也会下降
8 - 说一说 poll模型的缺点?
- poll和select本质上没有差别,管理多个描述符也是进行轮询,根据描述符的状态进行处理,但是poll没有最大文件描述符数量的限制。
- select采用fdset(fdset采用了bitmap),poll采用了数组,所以表示的描述符比select大
- poll和select同样存在一个缺点就是,文件描述符的数组被整体复制于用户态和内核态的地址空间之间,而不管这些文件描述符是否有事件,它们的开销随着文件描述符数量的增加而线性增大。
- poll返回后,也需要遍历整个描述符的数组才能得到有事件的描述符
9 - 说一说epoll的好处 以及 LT和ET?
- epoll解决了select和poll在文件描述符集合拷贝和遍历上的问题,能够在一个进程中监听多个文件描述符,并且十分高效
- 在内核当中epoll是以红黑树的方式组织监听事件的,所以查询开销是 $O(\log{n})$。采用回调的方式检测就绪事件,时间复杂度是$O(1)$
- 在注册监听事件时从用户态将数据传入内核态;当返回时需要将就绪队列的内容拷贝到用户空间
LT(Level Trigger) 水平触发: 效率会低于ET触发,尤其在高并发大流量的情况下。但是LT对代码编写要求比较低,不容易出现问题。LT模式服务编写上的表现是:只要有数据没有被获取,内核就不断通知你,因此不用担心时间丢失的情况。
- 水平触发中只要输入缓冲中还剩有数据,就将以事件方式再次注册。接下来通过如下对话介绍边缘触发的事件特性。
ET(Edge Trigger) 边缘触发: 效率非常高,在高并发大流量的情况下,会比LT少很多epoll的系统调用,因此效率高。但是对编程要求高,需要细致的处理每个请求,否则容易发生丢失事件的情况
- 边缘触发中输入缓冲收到数据时仅注册1 次该事件。即使输入缓冲中还留有数据,也不会再进行注册。
10 - TCP通信中,select到读事件,但是读到的数据量是0,为什么?如何解决?
- select 返回 0 代表超时,返回 1代表出错
- select到读时间,但是读到的数据量为0,说明对方已经关闭了socket的读端。本端关闭读即可
- 当select出错时,会将接口设置为可读又可写。这时候就可以通过判断select的返回值是否为-1确定有没有出错
11 - connect方法会阻塞,请问有什么方法可以避免其长时间阻塞?
- 最常用最有效的方法是加定时器
- 也可以采用非阻塞模式
- 或者考虑采用异步传输机制,同步传输与异步传输的主要区别在于同步传输中,如果调用recvfrom后会一致阻塞运行,从而导致调用线程暂时运行;异步传输则立即返回
12 - 网络中,如果客户端突然掉线或重启,服务端怎么样才能立刻知道?
若客户端掉线或重启,服务端会收到复位信号
13 - socket编程,如果client断电了,服务器如何快速知道?
有数据流动的情况下,可以使用定时器。如果没有数据流动,使用socket选项SO_KEEPALIVE,做心跳检测
14- 子网 210.27.48.21/30有多少个可用地址?分别是?
30表示网络号是30位,剩下2位中11是广播地址,00是组播地址,只有01和10可以作为主机地址。
如果广播或组播地址也可用,就是4个
15 - TTL是什么?有什么用处?通常哪些工具会用到?
TTL (Time To Live),没经过一个路由TTL会减1,如果变成0,包就会被丢弃。其作用是防止包在有回路的网络上死转,浪费网络资源。ping和traceroute都用了TTL
16 - 路由表的作用?linux中如何配置一条默认路由?
路由表是用来决定如何将包从一个子网传送到另一个子网的
在Linux中用 route add default gw <默认路由器IP>
配置一条默认路由
17 - 如何测试两台主机是否连通?
使用ping命令从一台机器ping另一台机器,如果ping不通,用traceroute可以确定是哪个路由器不能连通,然后再找其他问题
18 - fork一子进程后,父进程的全局变量能不能使用?
fork后子进程将拥有父进程的几乎一切资源,父子进程都各自有各自的全局变量,不能通用。不同于线程,对于线程,各个线程共享全局变量
19 - 网络编程常用工具
ping 可以用来帮助我们进行网络连通性的探测。
ifconfig,用来显示当前系统中的所有网络设备。
netstat 和 lsof 可以查看活动的连接状况。
tcpdump 可以对各种奇怪的环境进行抓包,进而帮我们了解报文,排查问题。
三、操作系统
1 - 操作系统的特点
- 并发性
- 共享性
- 虚拟性
- 异步性
2 - 并发和并行
- 并发(concurrency):指宏观上看起来两个程序在同时运行,比如说在单核cpu 上的多任务。但是从微观上看两个程序的指令是交织着运行的,你的指令之间穿插着我的指令,我的指令之间穿插着你的,在单个周期内只运行了一个指令。这种并发并不能提高计算机的性能,只能提高效率。
- 并行(parallelism):指严格物理意义上的同时运行,比如多核cpu,两个程序分别运行在两个核上,两者之间互不影响,单个周期内每个程序都运行了自己的指令,也就是运行了两条指令。这样说来并行的确提高了计算机的效率。所以现在的cpu 都是往多核方面发展。
3 - 同步、异步、阻塞、非阻塞的概念
- 阻塞和非阻塞:
- 阻塞:调用者在事件没有发生的时候,一直在等待事件发生,不能去处理别的任务这是阻塞。
- 非阻塞:调用者在事件没有发生的时候,可以去处理别的任务这是非阻塞。
- 同步和异步:
- 同步:调用者要一直等待返回结果,得到通知后才能进行后续的执行,这种情况是同步。
- 异步:调用者不用自己去查看事件有没有发生,而是等待着注册在事件上的回调函数通知自己,这种情况是异步。
4 - 进程与线程的概念
- 进程:是系统进行资源调度和分配的基本单位,且每个进程拥有独立的地址空间,进程实现了操作系统的并发,是系统中并发执行的单位。
- 线程:是进程的子任务,是CPU调度和分派的基本单位,用于保证程序的实时性,实现进程内部的并发;
5 - 进程与线程的区别
答案一:
- 单位:进程是资源分配的最小单位,线程是CPU调度的最小单位。两者均可并发执行。
- 从属:一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。线程依赖于进程而存在。
- 资源:进程之间的资源是独立的,进程在执行过程中拥有独立的内存单元,而多个线程共享进程的内存。
- 资源分配给进程,同一进程的所有线程共享该进程的所有资源。
- 同一进程中的多个线程共享代码段(代码和常量),数据段(全局变量和静态变量),扩展段(堆存储)。但是每个线程拥有自己的栈段,栈段又叫运行时段,用来存放所有局部变量和临时变量。
- 系统开销:在创建或撤销进程时,系统都要为之分配或回收资源,系统开销显著大于创建或撤销线程的开销。
- 在进行进程切换时,设计到整个当前进程CPU环境的保存以及新被调度运行的进程的CPU环境的设置。
- 而线程切换只需要保存和设置少量寄存器的内容,并不涉及存储管理方面的操作。
- 切换进程的开销也远大于切换线程的开销。
- 进程编程调试简单可靠性高,但是创建、销毁、切换开销大;线程正相反,但是编程调试相对复杂
- 进程之间不会相互影响,一个进程崩溃后,在保护模式下不会对其他进程产生影响,但是一个线程崩溃会导致整个进程崩溃。所以多进程比多线程健壮。
答案二:根本区别就是多进程每个进程有自己的地址空间,线程则是共享地址空间。
- 速度:线程创建速度快,线程间通信快、切换快,因为它们在同一地址空间内
- 资源利用率:线程的资源利用率比较好也是因为它们在同一地址空间
- 同步问题:线程使用公共变量/内存时需要使用同步机制,也是因为它们在同一地址空间内。
6 - 多线程与多进程的不同?
- 进程是资源分配的最小单位,而线程时CPU 调度的最小单位。
- 多线程之间共享同一个进程的地址空间,线程间通信简单,同步复杂,线程创建、销毁和切换简单,速度快,占用内存少,适用于多核分布式系统,但是线程间会相互影响,一个线程意外终止会导致同一个进程的其他线程也终止,程序可靠性弱。
- 多进程间拥有各自独立的运行地址空间,进程间不会相互影响,程序可靠性强,但是进程创建、销毁和切换复杂,速度慢,占用内存多,进程间通信复杂,但是同步简单,适用于多核、多机分布。
7 - 多线程与多进程的应用场景
- 需要频繁创建销毁的优先用线程;
- 需要进行大量计算的优先使用线程;
- 强相关的处理用线程,弱相关的处理用进程;
- 多线程模型主要优势为线程间切换代价较小,因此适用于I/O 密集型的工作场景,因此I/O密集型的工作场景经常会由于I/O 阻塞导致频繁的切换线程。同时,多线程模型也适用于单机多核分布式场景。
- 多进程模型,适用于CPU 密集型。同时,多进程模型也适用于多机分布式场景中,易于多机扩展。
8 - 进程的状态转换
进程包括三种状态:就绪、运行、阻塞
就绪 –> 运行:对就绪状态的进程,当进程调度程序按一种选定的策略从中选中一个就绪进程,为之分配处理机后,该进程便由就绪状态变为执行状态
运行 –> 阻塞:正在执行的进程因发生某等待事件而无法运行,则进程由执行状态变为阻塞状态,如进程提出输入/输出请求而变成带带外部设备传入信息的状态;进程申请资源(主存空间或外部设备)得不到满足时编程等待资源状态,进程运行中出现了故障(程序出错或主存储器读写错误等)编程等待干预状态等;
阻塞 –> 就绪:处于阻塞状态的进程,其等待的事件已经发生,如输入/输出完成;资源得到满足;或错误处理完毕时,处于等待状态的进程并不马上转入运行状态,而是先转入就绪状态,再由系统进程调度程序在适当的时候将改进成转为执行状态。
运行 –> 就绪 :正在执行的进程,因时间片用完而被暂停运行;或在采用抢占式优先级调度算法的系统中,当有更高优先级的进程要运行而被迫让出处理机时,该进程便从运行状态转变为就绪状态
9 - 进程的调度算法有哪些?
- 先来先服务调度算法
- 时间片轮转调度算法
- 短作业优先调度算法
- 最短剩余时间优先调度算法:
- 是针对最短进程优先增加了抢占机制的版本
- 高响应比优先调度算法:
- 主要用于作业调度,该算法是对 先来先服务调度算法 和 短作业优先调度算法 的一种综合平衡,同时考虑每个作业的等待时间和估计的运行时间
- 优先级调度算法
10 - 进程间的通信方式有哪些?
- 管道
- 系统IPC (消息队列、信号量、共享内存)
- 套接字socket
10.1 - 管道
管道主要包括普通管道和命名管道:管道可用于具有亲缘关系的父子进程间的通信,有名管道除了具有管道所具有的功能外,它还允许无亲缘关系进程的通信。
普通管道PIPE:
- 半双工(数据只能在一个方向上流动),具有固定的读端和写端
- 只能用于具有亲缘关系的进程间通信(也就是父子进程或兄弟进程之间)
- 它可以看成是一种特殊的文件,对于它的读写也可以使用普通的read、write等函数。但是它不是普通的文件,不属于其他任何文件系统,并且只存在于内存中。
int pipe(int fd[2]);
当一个管道建立时,会创建两个文件文件描述符,要关闭管道只需将这两个文件描述符关闭即可。
命名管道FIFO:
- 可以在无关的进程之间交换数据
- 有路径名与之相关联,以一种特殊设备文件形式存在于文件系统中
int mkfifo(const char* pathname,mode_t mode);
10.2 - 系统IPC(Inter-Process Communication)
消息队列:
- 消息队列是消息的链表,存放在内核中。一个消息队列由一个标识符来标识(即队列ID)。
- 消息队列是面向记录的,其中的消息具有特定的格式以及特定的优先级;
- 消息队列独立于发送与接收进程。进程终止时,消息队列及其内容并不会被删除;
- 消息队列可以实现消息的随机查询。
信号量 semaphore:
- 信号量是一个计数器,信号量用于实现进程间的互斥与同步,而不是用于存储进程间通信数据;
- 信号量用于进程间同步,若要在进程间传递数据需要结合共享内存;
- 信号量基于操作系统的PV操作,程序对信号量的操作都是原子操作;
- 每次对信号量的PV操作不仅限于对信号量值+1或-1而是可以加减任意正整数;
- 支持信号量组。
共享内存 Shared Memory:
- 共享内存指两个或多个进程共享一块指定的存储区,不同进程可以即时看到对方进程中对共享内存中数据的更新;
- 因为多个进程可以同时操作,所以需要进行同步;
- 信号量和共享内存通常结合在一起使用,信号量用来同步对共享内存的访问;
- 共享内存是最快的一种进程通信方式,因为进程是直接对内存进行存取。
10.3 - 套接字 SOCKET
socket也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同主机之间的进程通信。
11 - 线程通信方式
Linux
- 信号:类似进程间的信号处理
- 锁机制:互斥锁、读写锁、自旋锁
- 条件变量:使用通知的方式解锁,与互斥锁配合使用
- 信号量:包括无名线程信号量和命名线程信号量
Windows:
- 全局变量:需要有多个线程来访问一个全局变量时,通常会在这个全局变量上加volatile声明,防止编译器对此变量进行优化
- Message消息机制:常用的Message通信的接口主要有两个:
- PostMessage 为线程向主窗口发消息
- PostThreadMessage 是任意两个线程之间的通信接口
- CEvent:CEvent为MFC中的一个对象,可以通过对CEvent的触发状态进行改变,从而实现线程间的通信和同步,是实现线程直接同步的一种方法
12 - 线程同步的方式有哪些?
(1)临界区:
通过多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问;
(2)信号量:
信号量是一种特殊的变量,可用于线程同步。它只取自然数值,并且只支持两种操作:
- P(V):如果信号量大于 0 ,执行 -1 操作;若S减1后仍大于或等于0,则进程继续执行;若S减1后小于0,则该进程被阻塞后放入等待该信号量的等待队列中,然后转进程调度。
- V(V):V+1;若结果大于0,则进程继续执行;若相加后结果仍小于或等于0,则从该信号的等待队列中释放一个等待进程,然后再返回原进程继续执行或转进程调度。
其系统调用为:
sem_wait(sem_t *sem):
以原子操作的方式将信号量-1
,如果信号量值小于0
,则sem_wait
将被阻塞,直到这个信号量具有非0 值
。sem_post(sem_t *sem):
以原子操作将信号量值+1
。当信号量大于0
时,其他正在调用sem_wait
等待信号量的线程将被唤醒。
(3)互斥量:
互斥量又称互斥锁,主要用于线程互斥,不能保证按序访问,可以和条件锁一起实现同步。当进入临界区时,需要获得互斥锁并且加锁;当离开临界区时,需要对互斥锁解锁,以唤醒其他等待该互斥锁的线程。其主要的系统调用如下:
- **pthread_mutex_init: **初始化互斥锁
- pthread_mutex_destroy:销毁互斥锁
- pthread_mutex_lock:以原子操作的方式给一个互斥锁加锁,如果目标互斥锁已经被上锁,**pthread_mutex_lock **调用将阻塞,直到该互斥锁的占有者将其解锁。
- **pthread_mutex_unlock: **以一个原子操作的方式给一个互斥锁解锁。
(4)事件(信号),Wait/Notify:
通过通知操作的方式来保持多线程同步,还可以方便的实现多线程优先级的比较操作
(5)条件变量:
条件变量,又称条件锁,用于在线程之间同步共享数据的值。条件变量提供一种线程间通信机制:当某个共享数据达到某个值时,唤醒等待这个共享数据的一个/多个线程。即,当某个共享变量等于某个值时,调用signal/broadcast。此时操作共享变量时需要加锁。其主要的系统调用如下:
- **pthread_cond_init: **初始化条件变量
- pthread_cond_destroy:销毁条件变量
- pthread_cond_signal:唤醒一个等待目标条件变量的线程。哪个线程被唤醒取决于调度策略和优先级。
- pthread_cond_wait:等待目标条件变量。需要一个加锁的互斥锁确保操作的原子性。该函数中在进入
wait
状态前首先进行解锁,然后接收到信号后会再加锁,保证该线程对共享资源正确访问。
14 - 线程产生的原因?
进程可以使多个程序能并发执行,以提高资源的利用率和系统的吞吐量;但是进程具有一些 缺点:
- 进程在同一时间只能干一件事。
- 进程在执行的过程中如果阻塞,整个进程就会挂起,即使进程中有些工作不依赖于等待的资源,仍然不会执行。
因此,操作系统引入了比进程粒度更小的线程,作为并发执行的基本单位,从而减少程序在并发执行时所付出的时空开销,提高并发性。
和进程相比,线程的优势如下:
- 资源开销小:在linux 系统下,启动一个新的进程必须分配给它独立的地址空间,建立众多的数据表来维护它的代码段、堆栈段和数据段,这是一种”昂贵”的多任务工作方式。
- 由于多个线程共享同一个进程虚拟空间,线程之间通信更加方便,切换效率更快,比进程更具有更高的性能。
除以上优点外,多线程程序作为一种多任务、并发的工作方式,还有如下优点:
- 使多CPU 系统更加有效。操作系统会保证当线程数不大于CPU 数目时,不同的线程运行于不同的CPU 上。
- 改善程序结构。一个既长又复杂的进程可以考虑分为多个线程,成为几个独立或半独立的运行部分,这样的程序才会利于理解和修改
15 - 线程切换时需要保存哪些上下文?SP、PC、EAX 这些寄存器的作用?
线程在切换的过程中需要保存:
- 当前线程Id
- 线程状态
- 堆栈
- 寄存器状态
其中寄存器主要包括SP PC EAX 等寄存器,其主要功能如下:
- SP: 堆栈指针,指向当前栈的栈顶地址
- PC: 程序计数器,存储下一条将要执行的指令
- EAX: 累加寄存器,用于加法乘法的缺省寄存器
16 - 单核机器上写多线程程序,是否需要考虑加锁,为什么?
在单核机器上写多线程程序,仍然需要线程锁。因为线程锁通常用来实现线程的同步和通信。在单核机器上的多线程程序,仍然存在线程同步的问题。因为在抢占式操作系统中,通常为每个线程分配一个时间片,当某个线程时间片耗尽时,操作系统会将其起,然后运行另一个线程。如果这两个线程共享某些数据,不使用线程锁的前提下,可能会导致共享数据修改引起冲突。
17 - 游戏服务器应该为每个用户开辟一个线程还是一个进程?
- 游戏服务器应该为每个用户开辟一个进程。因为同一进程间的线程会相互影响,一个线程死掉会影响其他线程,从而导致进程崩溃。因此为了保证不同用户之间不会相互影响,应该为每个用户开辟一个进程
18 - 互斥锁(mutex)机制,互斥锁和读写锁的区别?
互斥锁 mutex:用于保证在任何时刻,都只能有一个线程访问该对象。当获取锁操作失败时,线程会进入睡眠,等待锁释放时被唤醒。
读写锁 rwlock:分为读锁和写锁。处于读操作时,可以允许多个线程同时获得读操作。但是同一时刻只能有一个线程可以获得写锁。其它获取写锁失败的线程都会进入睡眠状态,直到写锁释放时被唤醒。注意:写锁会阻塞其它读写锁。当有一个线程获得写锁在写时,读锁也不能被其它线程获取;写者优先于读者(一旦有写者,则后续读者必须等待,唤醒时优先考虑写者)。适用于读取数据的频率远远大于写数据的频率的场合。
互斥锁和读写锁的区别:
- 读写锁区分读者和写者,而互斥锁不区分
- 互斥锁同一时间只允许一个线程访问该对象,无论读写;读写锁同一时间内只允许一个写者,但是允许多个读者同时读对象。
19 - 介绍几种典型的锁?
读写锁
- 多个读者可以同时进行读
- 写者必须互斥(只允许一个写者写,写时不能读,后续读者必须等待,唤醒时优先考虑写者)
互斥锁
互斥锁用于控制多个线程对他们之间共享资源互斥访问的一个信号量。也就是说是为了避免多个线程在某一时刻同时操作一个共享资源。
- 一次只能一个线程拥有互斥锁,其他线程只能等待
- 互斥锁是在抢锁失败的情况下主动放弃CPU进入睡眠状态直到锁的状态改变时再唤醒,而操作系统负责线程调度,为了实现锁的状态发生改变时唤醒阻塞的线程或进程,需要把锁交给操作系统管理,所以互斥锁在加锁操作时设计上下文的切换。
- 互斥锁的实际效率还是可以接受的,加锁时间大概100ns左右,而实际互斥锁的一种可能的实现锁先自旋一段时间,当自旋的时间超过阈值之后再将线程投入到睡眠中,因此在并发运算中使用互斥锁(每次占用锁的时间很短)的效果不亚于使用自旋锁
条件锁
条件锁就是所谓的条件变量,某一个线程因为某个条件为满足时可以使用条件变量使该程序处于阻塞状态。一旦条件满足以“信号量”的方式唤醒一个因为该条件而被阻塞的线程。最为常见就是在线程池中,起初没有任务时任务队列为空,此时线程池中的线程因为“任务队列为空”这个条件处于阻塞状态。一旦有任务进来,就会以信号量的方式唤醒一个线程来处理这个任务。
- 互斥锁一个明显的缺点锁它只有两种状态:锁定和非锁定。而条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁的不足,他常和互斥锁一起使用,以免出现
自旋锁
如果线程无法取得锁,并不会立刻放弃CPU时间片,而是一直循环尝试获取锁,直到获取为止。如果别的线程长时间占有锁,那么自旋就是在浪费CPU做无用功,但是自旋锁一般应用于加锁时间很短的场景,这时效率锁比较高的。
20 - 进程终止的方式
- 正常退出:自愿
- 错误退出:自愿
- 严重错误:非自愿
- 被其他进程杀死:非自愿 kill
21 - 守护进程、僵尸进程、孤儿进程都是什么?
守护进程
指在后台运行的,没有控制终端与之相连的进程。它独立于控制终端,周期性地执行某种任务。Linux的大多数服务器就是用守护进程的方式实现的,如Web服务器进程HTTP等
孤儿进程
如果父进程先退出,子进程还没退出,那么子进程的父进程将变为init进程。(注:任意一个进程都必须有父进程)
一个父进程退出,而它的一个或多个子进程还在运行,那么这些子进程将成为孤儿进程。孤儿进程将被init进程(pid = 1)所收养,并由init进程对它们完成状态进行收集工作。
僵尸进程
如果子进程先退出,父进程还没有退出,那么子进程必须等到父进程捕获到了子进程的退出状态才真正结束,否则这个时候子进程就成了僵尸进程。
设置僵尸进程的目的是维护子进程的信息,以便父进程在以后某个时候获取。这些信息至少包括进程ID,进程的终止状态,以及该进程使用CPU的时间,所以当终止子进程的父进程调用wait或waitpid时就可以得到这些信息。
如果一个进程终止,而该进程有子进程处于僵尸状态,那么它的所有僵尸子进程的父进程ID将被置为1(init进程)。接管这些子进程的init进程将清理它们(也就是说init进程将wait它们,从而去除它们的僵尸状态)。
22 - 如何避免僵尸进程?
- 通过
signal (SIGCHLD, SIG_IGN )
通知内核对子进程的结束不关心,由内核回收。如果不想让父进程挂起,可以再父进程中加入一条语句:signal (SIGCHLD, SIG_IGN )
;表示父进程忽略 SIGCHLD信号,该信号是子进程退出的时候向父进程发送的。 - 父进程调用 wait / waitpid 等函数等待子进程结束,如果尚无子进程退出 wait 会导致父进程阻塞。waitpid可以通过传递 WNOHANG使父进程不阻塞立即返回。
23 - 什么是死锁?
由于系统中存在一些不可剥夺资源,当两个或两个以上进程在执行过程中,因争夺资源而造成的相互等待,使每个进程都无法向前推进的现象,即死锁
24 - 产生死锁的原因?
- 竞争资源
- 例如:系统中只有一台打印机,可供进程A使用,假定A已占用打印机,而B继续要求打印机打印则会被阻塞
- 系统资源可分两类
- 可剥夺资源:CPU、主存等
- 不可剥夺资源:磁带机、打印机等
- 进程推进顺序不当
- 例如:进程A和进程B相互等待对方的数据
25 - 死锁发生的条件有哪些?
死锁发生的四个必要条件如下:
- 互斥条件:进程对所分配到的资源不允许其他进程访问,若其他进程访问该资源,只能等待,直至占有该资源的进程使用完成后释放该资源;
- 请求和保持条件:进程获得一定的资源后,又对其他资源发出请求,但是该资源可能被其他进程占有,此时请求阻塞,但该进程不会释放自己已经占有的资源;
- 不可剥夺条件:进程已获得的资源,在未完成使用之前,不可被剥夺,只能在使用后自己释放;
- 环路等待条件:进程发生死锁后,必然存在一个进程-资源之间的环形链。
26 - 如何解决死锁?
- 预防死锁:破坏四个必要条件中的一个或多个来预防死锁
- 避免死锁:在资源动态分配的过程中,用某种方式防止系统进入不安全的状态
- 检测死锁:运行时产生死锁,及时发现死锁,将程序解脱出来
- 解除死锁:发生死锁后,撤销进程,回收资源,分配给正在阻塞状态的进程。
27 - 如何预防死锁?
- 破坏 请求和保持条件:
- 一次性分配所有资源,这样就不会再有请求了
- 只要有一个资源得不到分配,就不给这个进程分配其他资源
- 破坏 不可剥夺资源:
- 当进程新的资源未得到满足时,释放已占有的资源,从而破坏不可剥夺的条件
- 破坏 环路等待条件:
- 资源有序分配法:系统给每类资源赋予一个序号,每个进程按编号递增的请求资源,释放则相反,从而破坏环路等待的条件
28 - 如何避免死锁?
安全状态:如果死锁没有发生,并且及时所有进程突然请求对资源的最大需求,也仍然存在某种调度次序能够使得每一个进程运行完毕,则成该状态是安全的。
使用银行家算法检测系统是否处于安全状态,如果每次资源的分配回导致系统进入不安全状态,则不进行分配。
29 - 如何解除死锁?
资源剥夺:挂起某些死锁进程,并抢占它的资源,将这些资源分配给其他死锁进程
撤销进程:强制撤销部分、甚至全部死锁进程并剥夺这些进程的资源(撤销的原则可以按照进程优先级和撤销进程代价的高低进行)
进程回退:让一个或多个进程回退到足以避免死锁的地步。进程回退时自愿释放资源而不是被剥夺。要求系统保持进程的历史信息,设置还原点。
30 - 物理地址、逻辑地址、虚拟内存的概念?
物理地址:
它是地址转换的最终地址,进程在运行时执行指令和访问数据最后都要通过物理地址从主存中存取,是内存单元的真正地址
逻辑地址:
是指用户看到的地址。逻辑地址并不一定是元素存储的真实地址,即数组元素的物理地址(在内存条中的所处的位置)并非是连续的,只是通过操作系统通过地址映射,将逻辑地址映射成连续的,这样使用更符合人们的直观思维
虚拟内存:
虚拟内存是一种内存管理技术,它会使程序自己认为自己拥有一块很大且连续的内存,然而,这个程序在内存中不是连续的,并且有些还会在磁盘上,在需要时进行数据交换。
31 - 分页和分段的区别?
- 段是信息的逻辑单位,它是根据用户的需要划分的,因此段是对用户可见的;页是信息的物理单位,是为了管理主存的方便而划分的,对用户是透明的;
- 段的大小不固定,有它所完成的功能决定;页的大小固定,由系统决定
- 段向用户提供二维地址空间;页向用户提供的是一维地址空间
- 段是信息的逻辑单位,便于存储保护和信息共享,页的保护和共享收到限制
32 - 说一说虚拟地址空间的好处和坏处?
虚拟内存技术使得不同进程在运行过程中,它所看到的是自己独自占有了当前系统的4G 内存。所有进程共享同一物理内存,每个进程只把自己目前需要的虚拟内存空间映射并存储到物理内存上。事实上,在每个进程创建加载时,内核只是为进程“创建”了虚拟内存的布局,具体就是初始化进程控制表中内存相关的链表,实际上并不立即就把虚拟内存对应位置的程序数据和代码(比如.text .data 段)拷贝到物理内存中,只是建立好虚拟内存和磁盘文件之间的映射就好(叫做存储器映射),等到运行到对应的程序时,才会通过缺页异常,来拷贝数据。还有进程运行过程中,要动态分配内存,比如malloc 时,也只是分配了虚拟内存,即为这块虚拟内存对应的页表项做相应设置,当进程真正访问到此数据时,才引发缺页异常。
虚拟内存的好处
- 扩大地址空间;
- 内存保护:每个进程运行在各自的虚拟内存地址空间,互相不能干扰对方。虚存还对特定的内存地址提供写保护,可以防止代码或数据被恶意篡改。
- 公平内存分配。采用了虚存之后,每个进程都相当于有同样大小的虚存空间。
- 当进程通信时,可采用虚存共享的方式实现。
- 当不同的进程使用同样的代码时,比如库文件中的代码,物理内存中可以只存储一份这样的代码,不同的进程只需要把自己的虚拟内存映射过去就可以了,节省内
- 虚拟内存很适合在多道程序设计系统中使用,许多程序的片段同时保存在内存中。当一个程序等待它的一部分读入内存时,可以把CPU 交给另一个进程使用。在内存中可以保留多个进程,系统并发度提高
- 在程序需要分配连续的内存空间的时候,只需要在虚拟内存空间分配连续空间,而不需要实际物理内存的连续空间,可以利用碎片
虚拟内存的代价:
- 虚存的管理需要建立很多数据结构,这些数据结构要占用额外的内存
- 虚拟地址到物理地址的转换,增加了指令的执行时间。
- 页面的换入换出需要磁盘I/O,这是很耗时的
- 如果一页中只有一部分数据,会浪费内存。
33 - 置换算法有哪些?
当访问一个内存中不存在的页,并且内存已满,则需要从内存中调出一个页或将数据送至磁盘对换区,替换一个页,这种现象叫做缺页置换。当前操作系统最常采用的缺页置换算法如下:
- 最佳置换(OPT)算法:从主存中移出永远不再需要的页面;如无这样的页面存在,则选择最长时间不需要访问的页面。
- 先进先出(FIFO)算法:置换最先调入内存的页面,即置换在内存中驻留时间最久的页面。按照进入内存的先后次序排列成队列,从队尾进入,从队首删除。
- 最近最少使用(LRU)算法: 置换最近一段时间以来最长时间未访问过的页面。根据程序局部性原理,刚被访问的页面,可能马上又要被访问;而较长时间内没有被访问的页面,可能最近不会被访问。
- 时钟(CLOCK)置换算法
当前最常采用的就是LRU 算法。
34 - 缺页中断是什么?
产生缺页中断的原因是什么?
malloc()
和mmap()
等内存分配函数,在分配时只是建立了进程虚拟地址空间,并没有分配虚拟内存对应的物理内存。当进程访问这些没有建立映射关系的虚拟内存时,处理器自动触发一个缺页异常。
缺页中断:在请求分页系统中,可以通过查询页表中的状态位来确定所要访问的页面是否存在于内存中。每当所要访问的页面不在内存时,会产生一次缺页中断,此时操作系统会根据页表中的外存地址在外存中找到所缺的一页,将其调入内存。
缺页本身是一种中断,与一般的中断一样,需要经过4 个处理步骤:
- 1、保护CPU 现场
- 2、分析中断原因
- 3、转入缺页中断处理程序进行处理
- 4、恢复CPU 现场,继续执行
缺页中断是由于所要访问的页面不存在于内存时,由硬件所产生的一种特殊的中断,因此,与一般的中断存在区别:
- 1、在指令执行期间产生和处理缺页中断信号
- 2、一条指令在执行期间,可能产生多次缺页中断
- 3、缺页中断返回时,执行产生中断的一条指令,而一般的中断返回是,执行下一条指令。
35 - 常见的内存分配错误有哪些?
(1)内存分配失败,却使用了它
(2)内存虽然分配成功,但没有初始化就引用它
(3)内存分配成功并且已经初始化,但是操作时越界
(4)忘记释放内存,造成内存泄露
(5)释放了内存后又使用它
36 - 内存交换中,被换出的进程保存在哪里?
保存在磁盘里,也就是外存中。
具有对换功能的操作系统中,通常把磁盘空间分为文件区和对换区两部分。对换区的IO速度比文件区更快
- 文件区主要用于存放文件,追求存储空间的利用率,因此对文件区空间的管理采用离散分配方式;
- 对换区空间只占磁盘空间的小部分,被换出的进程数据就存放在对换区。
由于对换区的速度直接影响到系统的整体速度,因此对换区空间的管理主要追求换入换出的速度,因此通常对换区采用连续分配方式。
37 - 抖动是什么现象?
刚刚换出的页面又要马上换入内存,刚刚换入的页面马上又要换出外存。这种频繁的页面调度行为称之为抖动,或是颠簸现象。产生抖动的主要原因是进程频繁访问的页面数目高于可用的物理块数(分配给进程的物理块不够)
为进程分配的物理块太少,会使进程发生抖动现象。为进程分配的物理块太多,又会降低系统整体的并发度,降低某些资源的利用率,为了研究应该为每个进程分配多少个物理块,Denning提出了进程工作集的概念。
38 - 逻辑地址转物理地址
一句话来说:逻辑地址左移四位加偏移地址就是物理地址
逻辑地址 = 段地址:偏移地址
具体运算:段地址×16(左移四位,也就是2的四次方,相当于乘16)+偏移地址=物理地址(可以理解为段地址末尾补一个零)
逻辑地址是 1000H:0001H
那么物理地址为1000H×16+0001H=10001H
因为地址本身一般都是十六进制数,所以只需要把段地址左移一位末尾补0再和偏移地址加起来就是物理地址
39 - 页表寻址
页式内存管理,内存分成固定长度的一个个页片。
操作系统为每一个进程维护了一个从虚拟地址到物理地址的映射关系的数据结构,叫页表,页表的内容就是该进程的虚拟地址到物理地址的一个映射。
页表中的每一项都记录了这个页的基地址。通过页表,由逻辑地址的高位部分先找到逻辑地址对应的页基地址,再由页基地址偏移一定长度就得到最后的物理地址,偏移的长度由逻辑地址的低位部分决定。
一般情况下,这个过程都可以由硬件完成,所以效率还是比较高的。页式内存管理的优点就是比较灵活,内存管理以较小的页为单位,方便内存换入换出和扩充地址空间。
Linux 的四级页表机制:
64位CPU出现后,硬件可以支持4级页表,即PML4
- 4 级页表分别是:PGD -> PUD -> PMD -> PTE
字段 | 描述 | 位数 |
---|---|---|
PML4 (Page Map Level 4) | 指向一个PDPT(页目录指针表) | 位47~39 |
PGD(Page Global Directory) 全局页目录表索引 |
指向PDPT中4个项中的一个 | 位38~30 |
PMD(Page Middle Directory) 页中间目录索引 |
指向页目录中512项中的一个 | 位29~21 |
PTE(Page Table Entry) 页表入口索引 |
指向页表中512项中的一个 | 位20~12 |
page offset 页内偏移 | 4KB页中的偏移 | 位11~0 |
40 - 外中断和异常有什么区别?
外中断是指CPU执行指令以外的事件引起,如I/O完成中断,表示设备输入/输出处理已经完成,处理机能够发送下一个输入/输出请求。此外还有时钟中断、控制台中断等
异常是由CPU执行指令的内部事件引起,如非法操作码、地址越界、算术溢出等
41 - 什么是用户态和内核态?为什么要有这两种状态?
用户态和内核态是操作系统的两种运行状态:
- 内核态:处于内核态的CPU可以访问任意的数据,包括外围设备,如网卡、硬盘等,处于内核态的CPU可以从一个程序切换到另一个程序,并且占用CPU不会发生抢占情况,一般处于特权级0的状态称之为内核态。
- 用户态:处于用户态的CPU只能受限的访问内存,并且不允许访问外围设备,用户态下的CPU不允许独占,也就是说CPU能够被其他程序获取。
计算机有一些比较危险的操作,比如设置时钟、内存清理、这些都需要在内核态下完成,如果随意进行操作,系统很容易崩溃
42 - 用户态和内核态之间是如何切换的?
所有的用户进程都是运行在用户态的,但是用户进程的访问能力有限,一些必要重要的事件,比如从硬盘读取数据,从键盘获取数据的操作则是只有内核态才能做的事情,而这些数据却又对用户程序非常重要,所以就涉及到两种模式的转换。即:
用户态 –> 内核态 –> 用户态
而唯一能够操作这些操作的只有系统调用,而能够执行系统调用的只有操作系统,一般 用户态 –> 内核态 的转换 称之为 trap进内核,即陷阱指令
执行系统调用完成后,将还原用户模式寄存器,然后再以用户态运行。
43 - 什么是缓冲区溢出?有什么危害?
缓冲区是暂时置放输出或输入数据的内存。
缓冲区溢出是指当计算机向缓冲区填充数据时超出了缓冲区本身的容量,溢出的数据覆盖在合法的数据之上。
造成缓冲区溢出的主要原因是程序中没有仔细检查用户输入是否合理。
计算机中,缓冲区造成的危害主要有以下两点:
- 程序崩溃导致拒绝服务
- 跳转并执行一段恶意代码
44 - 原子操作是如何实现的?
处理器使用基于对 缓存加锁 或 总线加锁 的方式来实现 多处理器之间的原子操作
四、Linux
你用过的 Linux 常用命令有哪些?(按重要先后顺序排列)
Part1. 常用部分
1 - chmod 权限
Linux系统中一切都是文件。Linux使用不同的字符来区分不同的文件:
普通文件 | 目录文件 | 链接文件 | 块设备文件 | 字符设备文件 | 管道文件 |
---|---|---|---|---|---|
- | d | l | b | c | p |
其中最常用的是普通文件和目录文件,其操作有:
每个文件都有所属的所有者和所有组,并规定了文件的所有者、所有组以及其他人对文件的 可读(r)、可写(w)、可执行(x)权限。所以文件的读、写、执行权限可以简写为rwx,也可以用数字4、2、1来表示。文件所有者,所示组及其他用户权限之间无关联
文件权限的数字表示法基于字符(rwx)的权限计算而来,其目的是简化权限的表示方式。例如,若某个文件的权限为7,则代表可读、可写、可执行(4+2+1);若权限为6,则代表可读、可写(4+2)。
举例说明:现在有这样一个文件,其所有者拥有可读、可写、可执行的权限,其文件所属组拥有可读、可写的权限;其他人只有可读的权限。那么,这个文件的权限就是rwxrw-r–,数字法表示即为764。
最左边,开头d代表是目录文件,-代表是普通文件,之后是权限,例如 server文件,-rwxr-xr-x 为 普通文件(-)、所有者可读可写可执行(rwx)、所属主可读可执行、其他用户可读可执行。后面的数字是文件个数 ,第一个root是所属主,第二个root是所属组,然后是文件大小,日期
对server执行 chmod 777 后,权限变成rwxrwxrwx
如果对一个目录赋权要加 -R,递归执行,如对 freecplus目录执行赋权,即 chmod -R 777 freecplus
还有采取另一种方式,格式为 chmod [ugoa…][[±=][rwxX]…] file..
,
- u 表示该档案的拥有者,g 表示与该档案的拥有者属于同一个群体(group)者,o 表示其他以外的人,a 表示这三者皆是。
- +表示增加权限、- 表示取消权限、= 表示唯一设定权限。
- r 表示可读取,w 表示可写入,x 表示可执行,
- 创建一个普通文件szzsleep,权限为rw-r–r–
- 用a+x,即所有者、所有组、其他人都添加 x 执行权限,变成 rwxr-xr-x
- 再用o-x,将其他用户的 x 执行权限删除
2 - grep 搜索内容
grep (global search regular expression(RE) and print out the line,全面搜索正则表达式并把行打印出来)是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来。
格式: grep “内容” 文件名
内容和文件名均可写作正则表达式
1 | grep 'test' d* # 显示所有以d开头的文件中包含 test的行 |
3 - find 搜索文件
格式:find 目录名 -name 文件名 -print
- 目录名:待搜索的目录,搜索文件的时候,除了这个目录名,还包括它的各级子目录。
- 文件名:待搜索的文件名匹配的规则。
1 | find /tmp -name *.c -print # 从/tmp目录开始搜索,把全部的*.c文件显示出来 |
4. cat、more、tail 显示文本文件内容
cat 文件名
:cat命令一次显示整个文件的内容
more 文件名
:more命令分页显示文件的内容,按空格键显示下一页,按b键显上一页,按q键退出。
tail -f 文件名
:tail -f用于显示文本文件的最后几行,如果文件的内容有增加,就实时的刷新。对程序员来说,tail -f极其重要,可以动态显示后台服务程序的日志,用于调试和跟踪程序的运行。
Part2. 网络(按重要顺序排序)
常用命令 | 作用 |
---|---|
ifconfig | 查看网络接口属性 |
ip addr | 查看ip地址 |
ipconfig eh0 192.168.1.1 netmask 255.255.255.255 | 配置ip地址 |
netstat | 查看各种网络相关信息 |
netstat -lntp | 查看所有监听端口 |
netstat -antp | 查看已经建立的TCP连接 |
netstat -lutp | 查看TCP/UDP的状态信息 |
route -n | 查看路由表 |
Part3. 进程管理与系统命令
常用命令 | 作用 |
---|---|
ps -ef | 查看所有进程 |
ps -ef |grep expression | 用正则表达式过滤出所需要的进程 |
kill -s name | kill指定名称进程 |
kill -s pid | kill指定pid的进程 |
top | 实时显示进程状态 |
iostate | 查看io读写/cpu使用情况 |
sar -u 1 10 | 查询cpu使用情况(1秒1次,共10次) |
sar -d 1 10 | 查询磁盘性能 |
Part4. 系统服务
常用命令 | 作用 |
---|---|
systemctl status <服务名> | 查看某个服务 |
systemctl start <服务名> | 启动某个服务 |
systemctl stop <服务名> | 终止某个服务 |
systemctl restart <服务名> | 重启某个服务 |
systemctl enable <服务名> | 开启自启动 |
systemctl disable <服务名> | 关闭自启动 |
chkconfig –list | 列出系统服务 |
使用systemctl命令 配置防火墙的过程如下
查看防火墙的命令:
- 1)查看防火墙的版本。firewall-cmd –version
- 2)查看firewall的状态。firewall-cmd –state
- 3)查看firewall服务状态(普通用户可执行)。systemctl status firewalld
- 4)查看防火墙全部的信息。firewall-cmd –list-all
- 5)查看防火墙已开通的端口。firewall-cmd –list-port
- 6)查看防火墙已开通的服务。firewall-cmd –list-service
- 7)查看全部的服务列表(普通用户可执行)。firewall-cmd –get-services
- 8)查看防火墙服务是否开机启动。 systemctl is-enabled firewalld
配置防火墙的命令:
1)启动、重启、关闭防火墙服务。
- systemctl start firewalld # 启动
- systemctl restart firewalld # 重启
- systemctl stop firewalld # 关闭
2)开放、移去某个端口。
- firewall-cmd –zone=public –add-port=80/tcp –permanent # 开放80端口
- firewall-cmd –zone=public –remove-port=80/tcp –permanent # 移去80端口
3)开放、移去范围端口。
- firewall-cmd –zone=public –add-port=5000-5500/tcp –permanent # 开放5000-5500之间的端口
- firewall-cmd –zone=public –remove-port=5000-5500/tcp –permanent # 移去5000-5500之间的端口
4)开放、移去服务。
- firewall-cmd –zone=public –add-service=ftp –permanent # 开放ftp服务
- firewall-cmd –zone=public –remove-service=ftp –permanent # 移去http服务
5)重新加载防火墙配置(修改配置后要重新加载防火墙配置或重启防火墙服务)。
- firewall-cmd –reload
6)设置开机时启用、禁用防火墙服务。
- systemctl enable firewalld # 启用服务
- systemctl disable firewalld # 禁用服务
你用过的 Linux 常用命令有哪些?(按重要先后顺序排列)
- 首先是一些文件和目录操作的命令,比如:
- cd 、pwd、 ls、
- 创建 touch 、mkdir,删除 rm、移动或重命名 rm,复制cp
- cat、more、tail 查看文件内容
- 还有一些重要的命令,如chmod 权限管理、grep 搜索内容、find 搜索文件
- 还有一些和网络相关的命令
- ipconfig 查看网络接口属性,配置ip地址
- netstat 查看各种网络相关信息
- route 查看路由
- ping
- 进程管理的常用命令有:
- ps -ef 查看所有进程信息
- kill 杀死进程
- 系统方面常用的有:
- top 可以动态显示cpu、内存、进程等情况
- iostat 可以查看io读写/cpu使用情况
- sar 查询cpu、磁盘使用情况
- env 可以查看环境变量
- date 显示日期
- 还有一些服务的常用命令
- systemctl 管理服务
- firewall-cmd 防火墙
- vsftpd 文件传输
- 一些软件安装管理的
- rpm、yum、dpkg、apt-get用于安装管理软件
- 解压缩有:
- tar -xvf xxx.tar 解压tar包
- zip、unzip
- gzip与gunzip
五、数据库
1- 说一说对MySQL架构的了解?
MySQL可以分为 Server层 和 存储引擎两部分。
Server层:包括连接器、查询缓存、分析器、优化器、执行器等,涵盖MySQL的大多数核心服务功能,以及所有的内置函数(如日期、时间、数字、加密函数等),所有跨存储引擎的功能都在这一层实现,比如存储过程、触发器、视图等。
存储引擎:负责数据的存储和提取,其架构是插件式的,支持InnoDB、MyISAM等多个存储引擎。MySQL5.5.5版本后默认存储引擎是InnoDB
2 - 数据库三大范式是什么?
- 第一范式——无重复的列(原子性):强调的是列的原子性,数据表的每一列都是不可分割的原子数据项
- 第二范式——要求实体的属性完全依赖于主关键字(唯一性):所谓完全依赖是指不能存在依赖主关键字一部分的属性
- 第二范式(2NF)要求数据库表中的每个实例或行必须可以被惟一地区分。为实现区分通常需要为表加上一个列,以存储各个实例的惟一标识。这个惟一属性列被称为主关键字或主键、主码。
- 第三范式——任何主属性不依赖于其他非主属性(每列都与主键有直接关系,不存在传递依赖)
- 第三范式(3NF)要求一个数据库表中不包含已在其它表中已包含的非主关键字信息。
3 - 一条SQL语句在数据库框架中的执行流程?
- 应用程序把查询SQL语句发送给服务器执行;
- 查询缓存,如果缓存是打开的,服务器在收到查询请求后,并不会直接去数据库查询,而是在数据库的查询缓存中找是否有相同的查询数据,如果存在,直接返回给客户端。只有缓存不存在时,才会进行下面的操作
- 查询优化处理,生成执行计划。包括解析SQL、预处理、优化SQL、执行计划
- MySQL根据相应的执行计划完成整个查询
- 将查询结果返回给客户端
4 - 谈谈你对MVCC的了解?
MVCC(Multi-Version Concurrency Control, 多版本并发控制),数据库并发场景:
- 读——读:不存在任何问题,也不需要并发控制
- 读——写:有线程安全问题,可能会造成事务隔离性问题,可能遇到脏读,幻读,不可重复读
- 写——写:有线程安全问题,可能会存在更新丢失的问题
MVCC 可以为数据库解决以下问题:
- 在并发读写数据库时,可以做到在读操作时不用阻塞写操作,写操作也不用阻塞读操作,提高了数据库并发的读写性能
- 可以解决脏读、不可重复读、幻读等事务隔离问题,但不能解决更新丢失问题。
5 - 查询性能的优化方法?
- 减少请求的数据量
- 只返回必要的列:最好不要使用 SELECT * 语句
- 只返回必要的行:使用 LIMIT 语句来限制返回的数据
- 缓存重复查询的数据:使用缓存可以避免在数据库中进行查询,特别在要查询的数据经常被重复查询时,缓存带来的查询性能是非常明显的
- 减少服务端扫描的行数:
- 使用索引来覆盖查询
6 - 谈谈你对索引的理解?
索引的出现是为了提高数据的查询效率,就像书的目录一样。
索引也会带来负面影响:
- 创建索引和维护索引需要消耗时间,这个时间随着数据量的增加而增加
- 索引需要占用物理内存,不光是表需要占用数据空间,每个索引也需要占用物理空间
- 当对表进行增删改查的时候,索引也要动态维护,降低了数据的维护速度
建立索引的原则:
- 在最频繁使用的、用以缩小查找返回的字段建立索引
- 在频繁使用的、需要排序的字段上建立索引
不适合建索引的情况:
- 对于查询中很少涉及的列或重复值比较多的列,不适合建立索引
- 对于一些特殊的数据类型,不适合建立索引,比如文本字段 (text)等
7 - 索引的分类?
- 数据结构角度
- 树索引 $O(\log{n})$
- Hash索引
- 物理存储角度:
- 聚簇索引
- 非聚簇索引
- 逻辑角度
- 普通索引
- 唯一索引
- 主键索引
- 联合索引
- 全文索引
8 - 谈谈你对哈希索引的理解?
哈希索引能以 $O(1)$ 时间进行查找,但失去了有序性。无法用于排序与分组,只支持精确查找,无法用于部分查找和范围查找
InnoDB存储引擎有一个特殊功能叫 “自适应哈希索引” ,当某个索引值被使用的非常频繁时,会在B+树索引之上再创建一个哈希索引,这样就让B+Tree索引具有哈希索引的一些优点,实现快速的哈希查找
9 - 谈谈你对聚簇索引的理解?
聚簇索引是对磁盘上实际数据重新组织,然后按指定的一个或多个列的值排序的算法。
聚簇索引的特点是存储数据的顺序和索引顺序一致。
一般情况下主键会默认创建聚簇索引,而且一张表只允许存在一个聚簇索引
10 - 谈谈你对覆盖索引的认识?
覆盖索引是select的数据列只用从索引中就能够取得,不必读取数据行,换句话说查询列要被所建的索引覆盖。覆盖索引优点有:
- 索引通常远小于数据行的大小,只读取索引能大大减少数据访问量
- 一些存储引擎(例如:MyISAM)在内存中只缓存索引,而数据依赖于操作系统来缓存,因此,只访问索引可以不使用系统调用,系统调用通常比较费时
- 对于InnoDB引擎,若辅助索引能够覆盖查询,则无需访问主索引
11 - 怎么知道创建的索引有没有被使用到?或者说怎么才可以知道这条语句运行很慢的原因?
使用Explain命令查看语句的执行计划,MySQL在执行某个语句之前,会将该语句过一遍查询优化器,之后会拿到对语句的分析,也就是执行计划,其中包含了很多信息。可以通过其中和索引有关的信息来分析是否命中了索引,例如:possible_key、key、key_len等字段,分别说明了此语句可能会使用的索引、实际使用的索引以及索引的长度
12 - 什么情况下索引会失效?即查询不走索引?
1、索引列参与表达式计算
1 | SELECT 'sname' FROM 'stu' WHERE 'age' + 10 = 30; |
2、函数运算:
1 | SELECT 'sname' FROM 'stu' WHERE LEFT('date',4) < 1900; |
3、%语句% 模糊查询:
1 | SELECT * FROM 'manong' WHERE 'uname' LIKE '%码农%' -- 走索引 |
4、字符串与数字比较不走索引:
1 | CREATE TABLE 'a' ('a' char(10)); |
5、查询条件中有or,即时其中有条件带索引也不会使用
1 | SELECT * FROM dept WHERE dname='xxx' or loc='xx' or deptno=45; |
6、正则表达式不使用索引
7、MySQL内部优化器会对SQL语句进行优化,如果优化器估算使用全表扫描比使用索引快,则不使用索引。
13 - 索引的底层使用的是什么数据结构?
索引的数据结构和具体存储引擎的实现有关,常用的有Hash索引,B+树索引等
InnoDB存储引擎默认索引实现为 B+树索引
14 - 谈谈你对B+树的理解?
- B+树是基于B树和叶子节点顺序访问指针进行实现的,它具有B树的平衡性,并且通过顺序访问指针来提高查询的性能。
- B+树中,节点中的key从左到右非递减排列,如果某个指针的左右相邻key_i 和 key_i+1,且不为NULL,则该指针指向节点的所有key大于等于key_i且小于等于key_i+1
- 进行查找操作时,首先在根节点进行二分查找,找到一个key所在的指针,然后递归地在指针所指向的节点进行查找,直到查找到叶子节点,然后在叶子节点上进行二分查找,找出key所定义的data
- 插入、删除操作会破坏平衡树的平衡性,因此在插入删除操作后、需要对树进行一个分裂、合并、旋转等操作来维护平衡性。
15 - InnoDB存储引擎选用B+树而不是B树的原因?
用B+树不用B树考虑的是 IO 对性能的影响,B树的每个节点都存储数据,而B+树只有叶子节点才存储数据,所以查找相同数据量的情况下,B树的高度更高,IO更频繁。
数据库索引是存储在磁盘上的,当数据量过大时,就不能把整个索引uqanbu加载到内存了,只能逐一加载每一个磁盘页(对应索引树的节点)
16 - InnoDB 和 MyISAM的比较?
InnoDB | MyISAM | |
---|---|---|
事务 | 支持 | 不支持 |
全文索引 | 不支持 | 支持 |
数据量过大时使用count() | 瞬间返回,因为MyISAM会直接存储总行数 | 需要按行扫描再返回结果 |
外键 | 支持 | 不支持 |
锁 | 支持表锁、行锁,默认行锁 | 只支持表锁 |
17 - 说一下MySQL的行锁和表锁?
MyISAM只支持表锁,InnoDB支持表锁和行锁,默认为行锁。
表锁:开销小,加锁快,不会出现死锁。锁定力度大,发生锁冲突的概率高,并发度低
行锁:开销大,加锁慢,会出现死锁。锁力度小,发生锁冲突的概率低,并发度最高
18 - 描述下事务的特性?
- 原子性:事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用
- 一致性:执行事务前后,数据从一个一致性状态转换到另一个一致性状态
- 隔离性:并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间数据库是独立的
- 持久性:一个事务被提交后。它对数据库中数据的改变是持久的,即时数据库发生故障也不应该对其有任何影响
19 - 什么叫脏读、不可重复读和幻读?
- 脏读:表示一个事务能够读取另一个事务中还未提交的数据。
- 比如:某个事物尝试插入记录A,此时该事务还未提交,然而另一个事务尝试读取到了这个记录A
- 不可重复读:是指一个事务内,多次读取一个数据
- 幻读:指一个事务内多次查询返回的结果集不一样。
- 比如:同一个事务A第一次查询的时候有n个记录,但是第二次同等条件下查询却有n+1条记录。
- 原因:发生幻读的原因也是另外一个事务新增或删除或修改了第一个事务的结果集里的数据,同一个记录的数据内容被修改了,所有数据行的记录就变多或变少了。
20 - 谈谈你对事务隔离级别的理解?
1、READ_UNCOMMITTED(未提交读):最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读、不可重复读
2、READ_COMMITTED(提交读):允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读、不可重复读仍有可能发生
3、REPEATABLE_READ(可重复读):对同一字段的多次读取结果都是一致的,除非数据是被本事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
4、SERIALIZABLE(串行化):最高隔离级别,完全服从ACID的隔离级别。所有的事务依次执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以阻止脏读、不可重读读、幻读。但是这将严重影响程序的性能,通常情况都不会使用该级别。
ACID,是指数据库管理系统(DBMS)在写入或更新资料的过程中,为保证事务(transaction)是正确可靠的,所必须具备的四个特性:原子性(atomicity,或称不可分割性)、一致性(consistency)、隔离性(isolation,又称独立性)、持久性(durability)。
21 - 主从复制是什么?主从复制中涉及到哪三个线程?
主从复制是什么?
主从复制是用来建立一个和主数据库完全一样的数据库环境,称为从数据库;主数据库一般是实时的业务数据库,从数据库的作用和使用场合一般有几个:
- 一是作为后备数据库,主数据库服务器故障后,可切换到从数据库继续工作;
- 二是可在从数据库作备份、数据统计等工作,这样不影响主数据库的性能;
主从复制中涉及到哪三个线程?
- binlog线程:负责将主服务器上的数据更改写入二进制日志(Binary log)中
- I/O线程:负责从主服务器上读取二进制日志,并写入从服务器的重放日志(Relay log)中
- SQL线程:负责读取重放日志并重放其中的SQL数据
22 - 谈谈你对数据库读写分离的理解?
读写分离常用代理方式实现,代理服务器接收应用层传来的读写请求,然后决定转发到哪个服务器。主服务器处理写操作以及实时性要求比较高的读操作,而从服务器处理读操作。
读写分离能提高性能,是因为:
- 主从服务器负责各自的读和写,极大程度缓解了锁的争用
- 从服务器可以使用MyISAM,提高查询性能以及节约系统开销
- 增加冗余,提高可用性
23 - MySQL默认的隔离级别是什么?
MySQL:REPEATABLE_READ (repeatable_read)
ORACLE:READ_COMMITTED (read_committed)
24 - InnoDB 存储引擎的锁算法有哪些?
- Record Lock:单个行记录上的锁
- Gap Lock:间隙锁,锁定一个范围,不包括记录本身
- Next_key Lock: Record + Gap 锁定一个范围,包括记录本身
25 - MySQL问题排查都有哪些手段?
- 使用 show processlist 命令查看当前所有连接信息
- 使用 Explain 命令查询SQL语句执行计划
- 开启慢查询日志,查看慢查询的SQL
26 - MySQL中CHAR和VARCHAR的区别?
- char的长度是不可变的,用空格填充到指定长度大小,而varchar的长度是可变的。
- char的存取速度还是要比varchar要快得多
- char的存储方式是:对英文字符(ASCII)占用1个字节,对一个汉字占用两个字节。varchar的存储方式是:对每个英文字符占用2个字节,汉字也占用2个字节。
27 - 谈谈你对水平切分和垂直切分的理解?
水平切分
- 水平切分是将同一个表中的记录拆分到多个结构相同的表中。当一个表的数据不断增多时,水平切分是必然的选择,它可以将数据分布到集群的不同节点上,从而缓解单个数据库的压力
垂直切分
- 垂直切分是将一张表按列切分成多个表,通常是按照列的关系密集程度进行切分,也可以利用垂直切分将经常被使用的列和不经常被使用的列切分到不同的表中。例如:将原来的电商数据库垂直切分成商品数据库、用户数据库等。
28 - 存储过程的优缺点?
优点
1、重复使用。存储过程可以重复使用,从而可以减少数据库开发人员的工作量。
2、减少网络流量。存储过程位于服务器上,调用的时候只需要传递存储过程的名称以及参数就可以了,因此降低了网络传输的数据量。
3、安全性。参数化的存储过程可以防止SQL注入式攻击,而且可以将Grant、Deny以及Revoke权限应用于存储过程。
简单讲:
1.存储过程只在创造时进行编译,以后每次执行存储过程都不需再重新编译,而一般SQL语句每执行一次就编译一次,所以使用存储过程可提高数据库执行速度。
2.当对数据库进行复杂操作时(如对多个表进行Update,Insert,Query,Delete时),可将此复杂操作用存储过程封装起来与数据库提供的事务处理结合一起使用。
3.存储过程可以重复使用,可减少数据库开发人员的工作量
4.安全性高,可设定只有某些用户才具有对指定存储过程的使用权
有一点需要注意的是,一些网上盛传的所谓的存储过程要比sql语句执行更快的说法,实际上是个误解,并没有根据,包括微软内部的人也不认可这一点,所以不能作为正式的优点,希望大家能够认识到这一点。
缺点
1、调试麻烦,但是用 PL/SQL Developer 调试很方便!弥补这个缺点。
2、移植问题,数据库端代码当然是与数据库相关的。但是如果是做工程型项目,基本不存在移植问题。
3、重新编译问题,因为后端代码是运行前编译的,如果带有引用关系的对象发生改变时,受影响的存储过程、包将需要重新编译(不过也可以设置成运行时刻自动编译)。
4、 如果在一个程序系统中大量的使用存储过程,到程序交付使用的时候随着用户需求的增加会导致数据结构的变化,接着就是系统的相关问题了,最后如果用户想维护该系统可以说是很难很难、而且代价是空前的,维护起来更麻烦。
29 - 给定a、b两个文件,各存放50亿个url,每个url占64字节,内存限制4gb,找出a、b文件共同的url
思路1
先计算总数据,看看能不能一次性放到内存里:
50亿 = 5,000,000,000 约等于5G
总大小:5G * 64B = 32GB ,远大于4GB
只能使用哈希表将文件切分成小文件:
文件的数量怎么确定?切成小文件后,内存里需要同时 存放a和b的两个小文件,才能进行比较。那一个小文件的最大大小为2G,32/2 = 16,但是机器运行还需要内存,所以切分成20份,两个小文件占用内存3.2G,一个1.6GB
思路2
(1)对a 、b、hash(url)%20,分为20个小文件里
hash映射函数可以有多种选择
最简单的就是按首字母分类,分成26个喜爱哦文件,但是不能保证每个文件大小相等,也不符合20个小文件的设定
可以取前4个字节的int和%20,分配到20个小文件里
(2)因为使用同一个hash函数映射规则的原因,a,b切分后相同的URL存在对应的小文件里,即a0只需要和b0不急,a1和b1比较即可
(3)同时加载每一对小文件(如a0和b0),如果有相同的URL,则输出到文件中记录,全部比较完成后,文件中就是所有相同的记录
30 - B树
B树(B-树)是一种平衡多路查找数,B树中所有节点的子树个数的最大值称为B树的阶,用m表示,一颗m阶的B树,如果不为空,必须满足以下特性:
- 树中每个节点至多有m-1个关键字,有m颗子树(叶结点也算B树的子树)
- 除根节点以外,所以非叶节点至少含有 $\lceil m/2 \rceil - 1$个关键字,即 $\lceil m/2 \rceil $ 颗子树。(根节点的关键字可以小于$\lceil m/2 \rceil -1$,可以没有子树,如果有子树,则至少有两颗)
- 所有叶节点都在同一层上(各个子树没有高度差,绝对平衡)。叶结点不带信息,可以看成查找失败的节点
- 所有非叶子节点的结构为下图:
- 其中 $K_i(i = 1,2,3,…,n)$ 为节点的关键字,且满足 $K_1<K_2<K_3<..<K_n$,$P_i(i=0,1,2,3…,n)$ 为指向子树根节点的指针
一颗含有n个关键字的m阶B树(最小高度和最大高度不包括叶结点):
- 有多少个叶节点?
- n+1
- 最小高度是多少?
- 最胖的树最矮,让每个节点有m-1个关键字,即 $h\ge \log_m{(n+1)}$
- 最大高度是多少?
- 最瘦的树最高,让树中每个节点有 $\lceil m/2 \rceil - 1$个关键字 ,根节点只有一个关键字即可
- $h \le \log_k{\frac{n+1}{2}} +1 = \log_{\lceil m/2 \rceil}{\frac{n+1}{2}}+1$
31 - B+树
在B+树中查找某个关键字,可以从根节点开始,采用分块查找的方法,也可以直接从叶节点开始,采用顺序查找的方法
B+树中,上面存放索引的叫分支节点,最后一层叶结点是存放数据的
定义:
一颗m阶的B+树,如果不为空,就必须满足以下特性:
- 树中的每个节点至多有m个关键字,即m颗子树。(结点的关键字个数与子树数量相同)
- 除根节点外,所有非节点至少含有$\lceil m/2 \rceil$个关键字,即$\lceil m/2 \rceil$颗子树。(根节点关键字的个数可以小于$\lceil m/2 \rceil$,可以没有子树,如果有子树,则至少有两颗)。
- 所有叶节点包含了全部关键字和关键字指向记录的指针,叶节点内的关键字有序排列,叶结点之间也是有序排列,指针相连
- 所有非终端节点可以看成索引,仅包含了其子树中最大或最小关键字的值
32 - B树与B+树的差异
m阶的B树和B+树的差异(以5阶为例):
(1)B+树由分块查找进化而来;B树由二叉排序树进来而来
(2)在B+树中,每个非根节点关键字的取值范围是 $3 \le n \le 5$,有n颗子树;在B树中,每个非根节点的取值范围是$2 \le n \le 4$,有n+1颗子树
(3)在B+树中,仅叶子节点包含信息,非叶子节点仅起索引作用;在B树中,全部节点的关键字都包含信息。
(4)在B+树中,叶结点包含了全部的关键字,非叶节点中出现的关键字一定会出现在叶子结点中;在B树中,任何节点的关键字都不会重复。
(5)B+树支持顺序查找和多路查找;B树只支持多路查找
33 - Drop、Delete、Truncate的区别
- Delete 用来删除表的全部或者一部分数据行,执行Delete之后,用户需要提交(commmit)或者回滚(rollback)来执行删除或者撤销删除,会触发这个表上所有的delete触发器。
- Truncate删除表中的所有数据,这个操作不能回滚,也不会触发这个表上的触发器,Truncate比Delete更快,占用的空间更小。
- Drop命令从数据库中删除表,所有的数据行,索引和权限也会被删除,所有的DML触发器也不会被触发,这个命令也不能回滚。
在不再需要一张表的时候,用Drop;在想删除部分数据行时候,用Delete;在保留表而删除所有数据的时候用Truncate。
34 - 悲观锁和乐观锁的原理以及应用场景?
悲观锁
- 先获取锁,再进行业务操作,一般就是利用类似 SELECT … FOR UPDATE 这样的语句,对数据加锁,避免其他事务意外修改数据。
- 当数据库执行SELECT … FOR UPDATE时会获取被SELECT中的数据行的行锁,SELECT FOR UPDATE获取的行锁会在当前事务结束时自动释放,因此必须在事务中使用。
乐观锁
先进行业务操作,只在最后实际更新数据时检查数据是否被更新过
Java 并发包中的AtomicFieldUpdater 类似,也是利用 CAS 机制,并不会对数据加锁,而是通过对比数据的时间戳或者版本号,来实现乐观锁需要的版本判断。
六、Redis
七、测试
1 - 软件开发需要哪些知识?需要具备什么能力?
首先肯定需要软件测试的基础理论知识,如黑盒测试、白盒测试等,熟悉软件开发的整个生命周期,以及伴随着这个开发流程的各个测试环节
还要有全面的计算机知识:
编程语言:C、C++、java,还要掌握一门python、lua、shell脚本语言用于自动化测试
计算机的基础知识,如操作系统、Linux、计算机网络、数据库等
会使用自动化测试工具:
- 如Selenium(Web自动化测试工具),
- Appium(移动端自动化测试开源工具 ),‘
- Jmeter(Web应用程序的负载测试,可以进行接口测试,性能测试)
- Monkey(稳定性测试)
- LoadRunner(性能测试,是一种预测系统行为和性能的负载测试工具。通过以模拟上千万用户实施并发负载及实时性能监测的方式来确认和查找问题)
单元测试框架,如Junit、Pytest
需要具备的能力:
善于分析,而且要有一定的洞察力:通过分析代码的业务流程和逻辑,能发现其中隐藏的问题,问题发现的越早,解决的成本越低,这样问题越有价值。
还要有专业技术能力,就是刚刚所说的那些具备的知识,(测试基础知识、计算机知识、熟练运用测试工具)没有这些,发现问题就无从谈起,专业的技术能力是能让测试者分析问题发现问题的基础、基石。而且没有过硬的专业技术能力,再跟开发人员进行沟通的时候,可能连自己都说不清,也会不硬气,只有懂得深,自己明白问题的前因后果,才能跟别人解释清楚。
逻辑思考能力:软件开发中会有很多可行性逻辑分析,代码中也会有很多逻辑的判断,逻辑思考能力强也是能尽早发现问题的关键
沟通表达能力和团队协作能力:在发现问题后要能和开发人员、产品人员以及上下级进行有效的沟通,专业技术能力也是沟通表达能力的基石,只有自己深刻理解问题才能说的出来,说的清楚。软件的测试和开发通常是按照W模型的方法进行结合,测试和开发同步进行,这就需要团队的高效协作,从而实现项目的快速推进。
2 - 软件测试的核心竞争力是什么?
测试人员的核心竞争力在于提早发现问题,并能够发现别人无法发现的问题。
- 早发现问题:问题发现的越早,解决的成本越低。如果一个需求在还未实现的时候就能发现需求的漏洞,那么这种问题的价值是最高的。
- 发现别人无法发现的问题:所有人都能发现的问题,你发现了,那就证明你是可以被替代的。别人发现不了,而你可以发现,那么你就是无法被替代。
3 - 测试和开发需要怎么结合才能使软件的质量得到更好的保障?
测试和开发应该按照W模型的方式进行结合,测试和开发同步进行,能够尽早发现软件缺陷,降低软件开发的成本。
W 模型强调:测试伴随着整个软件开发周期,而且测试的对象不仅仅是程序,需求、设计等同样要测试,也就是说,测试与开发是同步进行的。有利于尽早地全面的发现问题。
例如,需求分析完成后,测试人员就应该参与到对需求的验证和确认活动中,以尽早地找出缺陷所在。同时,对需求的测试也有利于及时了解项目难度和测试风险,及早制定应对措施,这将显著减少总体测试时间,加快项目进度。
W 模型中测试的活动与软件开发同步进行,测试的对象不仅仅是程序,还包括需求和设计,
因此能够尽早发现软件缺陷,降低软件开发的成本。
4 - 单元测试、集成测试、系统测试、验收测试、回归测试
(1)单元测试:完成最小的软件设计单元(模块)的验证工作,目标是确保模块被正确的编码通常情况下是白盒的,对代码风格和规则、程序设计和结构、业务逻辑等进行静态测试,及早的发现和解决不易显现的错误。
(2)集成测试:通过测试发现与模块接口有关的问题。目标是把通过了单元测试的模块拿来,构造一个在设计中所描述的程序结构,应当避免一次性的集成(除非软件规模很小),而采用增量集成。
自顶向下集成:模块集成的顺序是首先集成主模块,然后按照控制层次结构向下进行集成,
自底向上集成:从原子模块开始来进行构造和测试,
(3)系统测试:是基于系统整体需求说明书的黑盒类测试,要覆盖系统所有联合的部件。目的是验证系统是否满足了需求规格的定义,找出与需求规格不相符合或与之矛盾的地方。而且是在系统实际运行环境下来进行测试。
(4)回归测试:回归测试是指在发生修改之后重新测试先前的测试用例以保证修改的正确性。理论上,软件产生新版本,都需要进行回归测试,根据修复好了的缺陷再重新进行测试。回归测试的目的在于验证以前出现过但已经修复好的缺陷不再重新出现。
(5)验收测试:验收测试是指系统开发生命周期方法论的一个阶段,这时相关的用户或独立测试人员根据测试计划和结果对系统进行测试和接收。它让系统用户决定是否接收系统。它是一项确定产品是否能够满足合同或用户所规定需求的测试。
验收测试包括Alpha 测试和Beta 测试:
- Alpha 测试:是由用户在开发者的场所来进行的,在一个受控的环境中进行。
- Beta 测试:由软件的最终用户在一个或多个用户场所来进行的,开发者通常不在现场,用户记录测试中遇到的问题并报告给开发者,开发者对系统进行最后的修改,并开始准备发布最终的软件。
5 - 单元测试、集成测试、系统测试、验收测试、回归测试这几步中最重要的是哪一步?
这些测试步骤是分别在软件开发的不同阶段对软件进行测试的,
我认为最重要的是系统测试,它主要是验证软件的功能是否,而且此时单元测试和集成测试已完成,能够对软件所有功能进行功能测试,覆盖系统所有的联合部件,是针对整个产品系统进行的测试,能够验证系统是否满足了需求,因此我认为系统测试很重要。
6 - 请说一说黑盒与白盒的测试方法
黑盒测试概念:
黑盒测试也称功能测试或数据驱动测试
它是在已知道软件有什么功能的情况下,通过测试来检测每个功能是否都能正常使用
在测试时,把程序看作一个不能打开的黑盆子,在完全不考虑程序内部结构和内部特性的情况下,测试者在程序接口进行测试,
黑盒测试只检查程序功能是否按照需求规格说明书的规定正常使用,程序是否能适当地接收输入数锯而产生正确的输出信息,并且保持外部信息(如数据库或文件)的完整性。
黑盒测试测试方法:
“黑盒”法是穷举输入测试,只有把所有可能的输入都作为测试情况使用,才能以这种方法查出程序中所有的错误。实际上测试情况有无穷多个,因此不仅要测试所有合法的输入,而且还要对那些不合法但是可能的输入进行测试。
常用的黑盒测试方法有:等价类划分法;边界值分析法;因果图法;场景法;正交实验设计法;判定表驱动分析法;错误推测法;功能图分析法。
白盒测试概念:
白盒测试也称为结构测试或逻辑驱动测试,是针对被测单元内部是如何进行工作的测试。
白盒测试根据程序的控制结构设计测试用例,检查程序内部逻辑结构,对所有的逻辑路径进行测试,是一种穷举路径的测试方法,但即使每条路径都测试过了,但仍然有可能存在错误。
- 因为穷举路径测试无法检查出程序本身是否违反了设计规范,即程序是否是一个错误的程序;穷举路径测试不可能检查出程序因为遗漏路径而出错;穷举路径测试发现不了一些与数据相关的错误。
白盒测试需要遵循的原则有:
- 保证一个模块中的所有独立路径至少被测试一次;
- 所有逻辑值均需要测试真(true)和假(false)两种情况;
- 检查程序的内部数据结构,保证其结构的有效性;
- 在上下边界及可操作范围内运行所有循环。
白盒测试方法:
静态测试:不用运行程序的测试,包括代码检查、静态结构分析、代码质量度量、文档测试等等,它可以由人工进行,充分发挥人的逻辑思维优势,也可以借助软件工具(Fxcop)自动进行。
动态测试:需要执行代码,通过运行程序找到问题,包括功能确认与接口测试、覆盖率分析、性能分析、内存分析等。
7 - 手动测试与自动化测试的缺点
手工测试的缺点:
- 重复的手工回归测试,代价昂贵、容易出错。
- 依赖于软件测试人员的能力。
手工测试的优点:
- 测试人员具有经验和对错误的猜测能力。
- 测试人员具有审美能力和心理体验。
- 测试人员具有是非判断和逻辑推理能力。
自动化测试的缺点:
- 不能取代手工测试,工具本身并无想像力
- 手工测试比自动测试发现的缺陷更多
- 对测试质量的依赖性极大
自动化测试的优点:
- 对程序的回归测试更方便,特别是在程序修改比较频繁时,效果是非常明显的。
- 可以运行更多更繁琐的测试,可以执行一些手工测试困难或不可能进行的测试。比如,对于大量用户的测试,不可能同时让足够多的测试人员同时进行测试,但是却可以通过自动化测试模拟同时有许多用户,从而达到测试的目的。
- 更好地利用资源。将繁琐的任务自动化,可以提高准确性和测试人员的积极性,将测试技术人员解脱出来投入更多精力设计更好的测试用例
- 测试具有一致性和可重复性。由于测试是自动执行的,每次测试的结果和执行的内容的一致性是可以得到保障的,从而达到测试的可重复的效果。
- 增加软件信任度。由于测试是自动执行的,所以不存在执行过程中的疏忽和错误,完全取决于测试的设计质量。一旦软件通过了强有力的自动测试后,软件的信任度自然会增加。
8 - 自动化的测试有什么意义?需要做什么?
自动化测试的意义在于:
- 可以对程序的新版本自动执行回归测试
- 可以执行手工测试困难或者不可能实现的测试,如压力测试,并发测试等
- 能够更好的利用资源,节省时间和人力
执行自动化测试之前首先判断这个项目适不适合推广自动化测试,然后对项目做需求分析,指定测试计划,搭建自动化测试框架,设计测试用例,执行测试,评估结果。