1、http和https的区别?
安全,HTTPS是身披SSL外壳的HTTP,利用SSL/TLS建立全信道,加密数据包
2、C++虚函数的原理
https://leetcode-cn.com/leetbook/read/cpp-interview-highlights/efvzbt/
3、C++智能指针
函数结束时自动释放内存空间,不需要手动释放内存空间
std::auto_ptr 具有排他所有权的性质,意思是赋值或者复制都会改变所有权
std::share_ptr
std::weak_ptr
std::unique_ptr
4、struct和class的区别
C | C++ | |
成员函数 | 不能 | 可以 |
静态成员 | 不能 | 可以 |
防控属性 | 默认public,不能修改 | public\private\protected |
继承关系 | 不可以继承 | 可从其他类或结构体继承 |
初始化 | 不能直接初始化数据成员 | 可以 |
5、new和malloc的区别以及底层实现
- 属性:new/delete是C++关键字,需要编译器支持。malloc、free是库函数,需要头文件支持
- 参数:使用new操作符申请内存分配时无需指定内存块的大小,编译器会根据类型自行计算。而malloc则需要显示地指出所需内存的尺寸
- 返回类型:new操作符内存分配成功时,返回的是对象类型的指针,类型严格与对象匹配,无须进行类型转换,故new是符合类型安全性的操作符。而malloc内存分配成功返回void *,需要通过强制类型转换将void*指针转换成我们需要的类型。
- 分配失败:new内存分配失败时,会抛出bad_alloc异常。malloc分配内存失败时返回NULL
- 自定义类型:new先会调用operator new函数,申请足够的内存(通常底层用malloc实现)。然后调用类型的构造函数,初始化成员变量,最后返回自定义类型指针。Delete先调用析构函数,然后调用operator delete函数释放内存(通常底层实现使用free)
- malloc/free是库函数,只能动态地申请和释放内存,无法强制要求其做自定义类型对象构造和析构工作。
- 重载:C++允许重载new/delete操作符,new在内存上为对象调用构造函数完成初始化工作,并返回此地址。而malloc不允许重载
- new操作符从自由存储区(free store)上为对象动态分配内存空间,而malloc函数从堆上动态分配内存。自由存储区是C++基于new操作符的一个抽象概念,凡是通过new操作符进行内存申请,该内存即为自由存储区。而堆是操作系统的术语,是操作系统维护的一块内存,用于程序的内存动态分配,C语言使用malloc从堆上分配内存,使用free释放已分配的对应内存。自由存储区不等于堆。布局new可以不在堆中。
https://blog.csdn.net/nie19940803/article/details/76358673
6、重写与重载的区别
重写:
- 发生在父类与子类之间
- 方法名,参数列表,返回类型(通过子类中方法的返回类型是父类中返回类型的子类)必须相同
- 访问修饰符的限制一定大于被重写方法的访问修饰符(public>protected>default>private)
- 重写方法一定不能抛出新的检查异常或者比被重写方法申明更加宽泛的检查型异常(里氏代换原则)
重载:
- 重载overload是一个类中多态性的一种表现
- 重载要求同名方法的参数列表不同(参数类型,参数个数甚至是参数顺序)
- 重载的时候,返回值类型可以相同也可以不相同。无法以返回值类型来区分重载和重写
方法的重载和重写都是实现多态的方式,区别在于前者实现的是编译时的多态性,而后者实现的是运行时的多态性。重载发生在一个类中,同名的方法如果有相同的参数列表(参数类型不同、参数个数不同或者两者都不同)则视为重载;重写发生在子类和父类之间,重写要求子类被重写方法与父类被重写方法有相同的参数列表,有兼容的返回类型,比父类被重写方法更好访问,重载对返回类型没有特殊要求,不能根据返回类型进行区分。
规则上的不同:
- 重写的规则:
- 参数列表必须完全与被重写的方法相同
- 返回的类型必须一直与被重写的方法的返回类型相同
- 访问修饰符的限制一定要大于被重写方法的访问修饰符
- 重写方法一定不能抛出新的检查异常或者比被重写方法申明更加宽泛的检测型异常
- 重载的规则:
- 必须具有不同的参数列表
- 可以有不同的访问修饰符
- 可以抛出不同的异常
类关系上的区别:
重写是子类和父类之间的关系,是垂直关系;
重载是同一个类中方法之间的关系,是水平关系;
https://www.cnblogs.com/klb561/p/14282047.html
7、几种树
一棵m阶的B+树和m阶的B树的异同点在于:
- 有n棵子树的结点中含有n-1 个关键字; (此处颇有争议,B+树到底是与B 树n棵子树有n-1个关键字 保持一致,还是不一致:B树n棵子树的结点中含有n个关键字,待后续查证。
- 所有的叶子结点中包含了全部关键字的信息,及指向含有这些关键字记录的指针,且叶子结点本身依关键字的大小自小而大的顺序链接。 (而B 树的叶子节点并没有包括全部需要查找的信息)
- 所有的非终端结点可以看成是索引部分,结点中仅含有其子树根结点中最大(或最小)关键字。 (而B 树的非终节点也包含需要查找的有效信息)
为什么说B+-tree比B 树更适合实际应用中操作系统的文件索引和数据库索引?
- B+-tree的磁盘读写代价更低
- B+-tree的查询效率更加稳定
- 数据库索引采用B+树的主要原因是 B树在提高了磁盘IO性能的同时并没有解决元素遍历的效率低下的问题。正是为了解决这个问题,B+树应运而生。B+树只要遍历叶子节点就可以实现整棵树的遍历。而且在数据库中基于范围的查询是非常频繁的,而B树不支持这样的操作(或者说效率太低)。
B+Tree在数据库索引上拥有独特优势的原因(为什么比红黑树更合适)
8、cookies和session的区别
- cookie保存在客户端,session数据保存在服务器端
- cookie不安全,别人可通过模仿存放在本地的cookie进行欺骗,考虑安全应当使用session
- session会在一定时间内保存在服务器上,当访问增多,会比较占用服务器的性能,考虑到减轻服务器的性能方面,应当使用cookie
- 单个cookie保存的数据不能超过4k,很多浏览器都限制一个站点最多保存20个cookie。
9、STL容器
- Vector:底层数据结构为数组,支持快速随机访问
- List:底层数据结构为双向链表,支持快速增删
- Deque:底层数据结构为一个中央控制器和多个缓冲区,详见《STL》p146,支持首位(中间不能)快速增删,也支持也随访问
- Stack:底层一般用list、deque实现,封闭头部即可,不用vector的原因应该是容量大小有限制,扩容耗时
- Queue:底层实现一般是list、deque,封闭头部即可,不用vector的原因应该是容量大小有限制,扩容耗时(stack和queue其实是适配器,不叫容器,一位内是对容器的封装)
- Priority_queue:底层数据结构一般为vector,堆heap为处理规则来管理底层容器实现
- Set:底层数据结构为红黑树,有序,不重复
- Multiset:底层数据数据结构为红黑树,有序,可重复
- Map:底层数据结构为红黑树,有序,不重复
- Multimap:底层数据结构为红黑树,有序,可重复
- Hash_set:底层数据结构为hash表,无序,不重复
- Hash_multiset:底层数据结构为hash表,无序,可重复
- Hash_map:底层数据结构为hash表,无序,不重复
- Hash_multimap:底层数据结构为hash表,无序,可重复
10、TCP三次握手、四次挥手
三次握手的作用:
- 双方都能明确自己和对方的收发能力是正常的
- 利用数据包的选项来传输特殊的信息,交换初始序列号ISN
第一次握手:客户端发送网络包,服务端收到了。这样服务端就能得出结论:客户端的发送能力、服务端的接收能力是正常的。
第二次握手:服务端发包,客户端收到了。这样客户端就能得出结论:服务端的接收、发送能力,客户端的接收、发送能力是正常的。(下一次“响应“是由第一次的请求触发,因此每次握手还可以得到额外的结论)
第三次握手:客户端发包,服务端收到了。这样服务端可得出:客户端的发送、接收能力是正常的。
两次达不到让双方都得出自己、对方的接收、发送能力是正常的结论!
四次挥手:
TCP连接是双向传输的对等模式,就是双方都可以同时向对方发送或接收数据。当有一方要关闭连接时,会发送指令告知对方,我要关闭连接了。这时对方会回一个ACK,此时一个方向的连接关闭,但是另一个方向仍然可以继续传输传输数据,等到发送完了所有的数据后,会发送一个FIN段来关闭此方向上的连接。接收方发送ACK确认关闭连接。
当TCP执行一个主动关闭,并发回最后一个ACK,该连接必须在TIME_WAIT状态停留的时间为2倍的MSL。这样可让TCP再次发送最后的ACK以防这个ACK丢失(另一端超时并重发最后的FIN)。
存在这个规则导致一个后果就是在这个2MSL的时间内,该地址上的链接(客户端地址、端口和服务器端的地址、端口)不能被使用。
SYN flood攻击:
发送端为了将多个发往接收端的包,更加高效的的发给接收端,于是采用了优化算法(Nagle算法),将多次间隔较小、数据量较小的数据,合并成一个数据量大的数据块,然后进行封包。
TCP粘包就是指发送方发送的若干包数据到达接收方时粘成了一包,从接收缓冲区来看,后一包数据的头紧接着前一包数据的尾,出现粘包的原因是多方面的,可能是来自发送方,也可能是来自接收方。
(2条消息) 如何解决tcp通信中的粘包问题?_m0_37829435的博客-CSDN博客_tcp粘包问题
11、TCP流量控制和拥塞控制
TCP/IP(Transmission Control Protocol/Internet Protocol,传输控制协议/网际协议)是指能够在多个不同网络间实现信息传输的协议簇。TCP/IP协议不仅仅指的是TCP 和IP两个协议,而是指一个由FTP、SMTP、TCP、UDP、IP等协议构成的协议簇, 只是因为在TCP/IP协议中TCP协议和IP协议最具代表性,所以被称为TCP/IP协议。
ARP协议
即地址解析协议,是根据IP地址获取MAC地址的一个网络层协议。其工作原理如下:ARP首先会发起一个请求数据包,数据包的首部包含了目标主机的IP地址,然后这个数据包会在链路层进行再次包装,生成以太网数据包,最终由以太网广播给子网内的所有主机,每一台主机都会接收到这个数据包,并取出标头里的IP地址,然后和自己的IP地址进行比较,如果相同就返回自己的MAC地址,如果不同就丢弃该数据包。ARP接收返回消息,以此确定目标机的MAC地址;与此同时,ARP还会将返回的MAC地址与对应的IP地址存入本机ARP缓存中并保留一定时间,下次请求时直接查询ARP缓存以节约资源。
12、进程、线程、协程 区别?
https://blog.csdn.net/daaikuaichuan/article/details/82951084
https://studygolang.com/articles/23615?fr=sidebar
协程,英文Coroutines,是一种基于线程之上,但又比线程更加轻量级的存在,这种由程序员自己写程序来管理的轻量级线程叫做『用户空间线程』,具有对内核来说不可见的特性。
因为是自主开辟的异步任务,所以很多人也更喜欢叫它们纤程(Fiber),或者绿色线程(GreenThread)。正如一个进程可以拥有多个线程一样,一个线程也可以拥有多个协程。
协程的目的就是当出现长时间的I/O操作时,通过让出目前的协程调度,执行下一个任务的方式,来消除ContextSwitch上的开销。(个人认为不用协程的话,线程和进程设置成非阻塞或者异步,不是一样的吗?是不是说怎样都会有上下文切换,而协程的切换开销最小)
- 线程的切换由操作系统负责调度,协程由用户自己进行调度,因此减少了上下文切换,提高了效率。
- 线程的默认Stack大小是1M,而协程更轻量,接近1K。因此可以在相同的内存中开启更多的协程。
- 由于在同一个线程上,因此可以避免竞争关系而使用锁。
- 适用于被阻塞的,且需要大量并发的场景。但不适用于大量计算的多线程,遇到此种情况,更好实用线程去解决。
比较项 | 线程 | 协程 |
占用资源 | 初始单位为1MB,固定不变 | 初始一般为2KB,可随需要增大 |
调度所属 | 由操作系统内核完成 | 由用户完成 |
切换开销 | 设计模式切换(从用户态切换到内核态)、16个寄存器、PS、SP…等寄存器的刷新等 | 占用资源少,不会带来严重的性能问题 |
性能问题 | 相比协程,资源占用太高,频繁创建销毁会带来严重的性能问题 | 资源占用小,不会带来严重的性能问题 |
数据同步 | 需要用锁等机制确保数据的一致性和可见性 | 不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好,所以执行效率比多线程高很多 |
协程和线程的比较
极高的执行效率:因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就越明显;
不需要多线程的锁机制:因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多。
https://blog.csdn.net/qq_34276797/article/details/118890030
13、大数据场景问题
常用的到概念:hash、堆排序、归并排序、快速排序、tire树、hash_map、mapreduce、Bloom filter、bitmap
14、设计模式(常考点)
15、大端小端 链接
大端模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中
小端模式,是指数据的低位保存在内存的低地址中,而数据的高位保存在内存的高地址中。
// 判断系统是大端还是小端:通过联合体,因为联合体的所有成员都从低地址开始存放
int fun1()
{
// 联合体允许在相同的内存位置存储不同的数据类型
union test
{
int i;
char c;
};
test t;
t.i = 1;
return t.c==1; // 大端==1 小端!=1
}
16、Raft、Paxos
17、如何在main函数前调用
(1条消息) 如何在main函数之前调用其他函数 ?_`Nobody的博客-CSDN博客_main函数调用其他函数
C语言中如何在main函数开始前执行函数 - 原来... - 博客园 (cnblogs.com)
18、extern “C”的作用
- 在C++文件中指定某些文件或代码以C的方式进行编译
- extern是C/C++语言中表明函数和全局变量的作用范围的关键字,该关键字告诉编译器,其申明的函数和变量可以在本模块或其他模块中使用。
19、levelDB读写流程
20、mysql InnoDB
MySQL存储引擎InnoDB与Myisam的六大区别 | 菜鸟教程 (runoob.com)
21、UDP如何实现可靠传输?
参考:UDP如何实现可靠传输? - 知乎 (zhihu.com)
让接收方收到UDP之后回复个确认包,发送方收到不到确认包就要重发(即超时重传),每个包有递增的序号,接收方发现中间丢失了包就要发重传请求,当网络太差时候频繁丢包,防止越丢包越重传的恶行循环,要有个发送窗口限制,发送窗口的大小根据网络储阿生农户情况调用。
就是再应用层重新实现TCP
22、线程池、进程池实现
23、读写锁实现
24、负责的kubernetes和kubeedge高可用部分
25、kubernetes和kubeedge高可用部分
Haproxy keepalived 浮动IP
Haproxy+Keepalived高可用环境部署梳理(主主和主从模式) - 云+社区 - 腾讯云 (tencent.com)
各自作用:
1)Keepalived 的作用是检测web服务器的状态,如果有一台web服务器死机,或工作出现故障,Keepalived将检测到,并将有故障的web服务器从系统中剔除, 当web服务器工作正常后Keepalived自动将web服务器加入到服务器群中,这些工作全部自动完成,不需要人工干涉,需要人工做的只是修复故障的 web服务器。
2)HAProxy 提供高可用性、负载均衡以及基于TCP和HTTP应用的代理,支持虚拟主机,它是免费、快速并且可靠的一种解决方案。HAProxy 特别适用于那些负载特大的 web 站点, 这些站点通常又需要会话保持或七层处理。HAProxy 运行在当前的硬件上,完全可以支持数以万计的并发连接。并且它的运行模式使得它可以很简单安全的整 合进您当前的架构中, 同时可以保护你的 web 服务器不被暴露到网络上。
vip即虚拟ip,是附在主机网卡上的,即对主机网卡进行虚拟,此IP仍然是占用了此网段的某个IP。
利用Haproxy+Keepalived基于完整开源软件的架构可以为你提供一个负载均衡及高可用的服务器。
Keepalived是一个基于VRRP协议来实现的WEB 服务高可用方案
利用Haproxy+Keepalived基于完整开源软件的架构可以为你提供一个负载均衡及高可用的服务器。
Keepalived是一个基于VRRP协议来实现的WEB 服务高可用方案
26、四种cast
- Static_cast<T>()
- Const_cast<T>()
- Dynamic_cast<T>()
- Reinterpret_cast<T>()
https://www.cplusplus.com/doc/tutorial/typecasting/
27、Select、poll、epoll对比
https://www.bookstack.cn/read/libevent/f29427637899ad10.md
https://zhuanlan.zhihu.com/p/64746509
27、TCP和UDP区别?
UDP:无连接,尽最大努力交付,面向报文(UDP对应用层交下来的报文,既不合并,也不拆分,而是保留这些报文的边界。没有拥塞控制。支持一对一、一对多、多对多的交付通信。UDP的首部开销小,只有8字节,而TCP是20字节。
TCP:TCP是面向连接的运输层协议,每一条TCP连接只能有两个端点(endpoint),每一条TCP连接只能是点对点的(一对一),TCP提供可靠交付的服务,提供全双工通信,面向字节流(TCP中的流(stream)指的是流入到进程或从进程流出的字节序列。面向字节流的含义是:虽然应用程序和TCP的交互是一次一个数据块,(大小不等),但TCP把应用程序交下来的数据看成仅仅是一连串的无结构的字节流。
28、Git分支管理
https://www.runoob.com/git/git-branch.html
29、C++ explicit
explicit关键字只需用于类内的单参数构造函数前面。由于无参数的构造函数和多参数的构造函数总是显示调用,这种情况在构造函数前加explicit无意义。
google的c++规范中提到explicit的优点是可以避免不合时宜的类型变换,缺点无。所以google约定所有单参数的构造函数都必须是显示的,只有极少数情况下拷贝构造函数可以不声明称explicit。例如作为其他类的透明包装器的类。
effective c++中说:被声明为explicit的构造函数通常比其non-explicit兄弟更受欢迎。因为它们禁止编译器执行非预期(往往也不被期望)的类型转换。除非我有一个好理由允许构造函数被用于隐式类型转换,否则我会把它声明为explicit,鼓励大家遵循相同的政策。
30、多线程下的volatile作用
当两个线程都要用到某一个变量且该变量的值会被改变时,应该用 volatile 声明,该关键字的作用是防止优化编译器把变量从内存装入 CPU 寄存器中。如果变量被装入寄存器,那么两个线程有可能一个使用内存中的变量,一个使用寄存器中的变量,这会造成程序的错误执行。volatile 的意思是让编译器每次操作该变量时一定要从内存中真正取出,而不是使用已经存在寄存器中的值
31、Muduo和Asio对比
32、rocketmq/architecture.md at master · apache/rocketmq · GitHub
33、码农有道
34、对象创建限制在堆或栈(具体参考leetcode C++面试突击)
限制在堆:可能会将对象创建在栈上是因为:没用new关键字,调用了默认的构造函数,可以利用单例模式中的方法,将构造函数和析构函数声明为protected,然后指定一个静态函数来new对象。
限制在栈:将operator new() 和 operator delete()设置为私有
35、无论read和send是阻塞I/O,还是非阻塞I/O都是同步调用。
因为在read调用时,内核将数据从内核空间拷贝到用户空间的过程都是需要等待的,也就是说这个过程是同步的,如果内核实现的拷贝效率不高,read调用就会在这个同步过程中等待比较长的时间。
而真正的异步I/O是 内核数据准备好 和 数据从内核态拷贝到用户态 这两个过程都不用等待。应用程序并不需要主动发起拷贝动作。
Reactor是非阻塞同步网络模式,感知的是就绪可读写事件
Proactor是异步网络模式,感知的是已完成的读写事件
Reactor可以理解为 来了事件操作通知应用进程,让应用进程来处理,而Proactor可以理解为 来了事件操作系统来处理,处理完再通知应用进程。Reactor模式是基于待完成的I/O事件,而Proactor则是基于已完成的I/O事件。
From 小林coding 《原来8张图,就能学废Reactor和Proactor》
36、decltype关键字
declare type类型推导,和auto的功能一样,都用来在编译时期进行自动类型推导。如果希望从表达式中推断出要定义的变量的类型,但是不想用该表达式的值初始化变量,这时就不能再用auto。Decltype的作用是选择并返回操作数的数据类型
auto var = var1 + var2;
decltype(var1 + var2) var1 = 0;
auto要求变量必须初始化,因为它是根据初始化的值推导出变量的类型,而decltype不要求,定义变量的时候可初始化也可以不初始化。
37、lambda表达式(匿名函数)
[capture list] (parameter list) -> return type
{
Function body;
};
Capture list: 捕获列表,指lambda所在函数中定义的局部变量列表,通常为空
Return type、parameter list、function body:分别表示返回值类型、参数列表、函数体
38、TCP可靠传输的工作原理
停止等待协议
ARQ
39、HTTP1~HTTP3的区别和联系
一文读懂 HTTP/1HTTP/2HTTP/3 - 知乎 (zhihu.com)
https://blog.csdn.net/xiaoming100001/article/details/81109617
40、(4条消息) InnoDB对MVCC的实现_Hopefully Sky的博客-CSDN博客_innodb mvcc
https://www.imooc.com/article/294754
41、分布式CAP
42、分布式事务(1)---2PC和3PC原理 - 雨点的名字 - 博客园 (cnblogs.com)
分布式一致性算法2PC和3PC_fcj的技术博客_51CTO博客
这篇文章中总结了为什么在2PC的基础上提出3PC,主要原因是,2PC会出现同步阻塞为题,如果在precommit阶段,某个参与者宕机,其他参与者就会陷入不知道是回滚还是提交日志的尴尬境地,3PC中引入了超时中断。
43、为什么析构函数必须是虚函数?
(7条消息) 内存泄漏-由于基类的析构函数没有声明为虚函数而导致的内存泄露_rabies的博客-CSDN博客
44、内存映射
45、Linux小内存分配slab->分配并释放内存中的小对象
http://www.wowotech.net/memory_management/426.html
https://blog.csdn.net/lukuen/article/details/6935068
46、读写流程
Bigtable
GFS
Mapreduce
47、互斥锁、读写锁、自旋锁
48、Kubernetes本质之Linux Namespace、Linux Cgroups 和 rootfs
49、(6条消息) 线程池原理及C语言实现线程池_青城山小和尚-CSDN博客_c 线程池
50、Linux文件系统是如何工作的?
51、
- grep 更适合单纯的查找或匹配文本
- sed 更适合编辑匹配到的文本
- awk 更适合格式化文本,对文本进行较复杂格式处理