这里的答案都是本人做的,非标准答案。如果错误,请在评论里指正,一起讨论共同进步!谢谢!
1、大端与小端的概念?各自的优势是什么?
【答】大端与小端是用来描述多字节数据在内存中的存放顺序,即字节序。大端(Big Endian)是指低地址端存放高位字节,小端(Little Endian)是指低地址端存放低位字节。
2、TIME_WAIT状态的产生、危害、如何避免?
【答】TCP协议在关闭连接的四次挥手中,为了应对最后一个 ACK 丢失的情况,Client(即主动关闭连接的一方)需要维持 time_wait 状态并停留 2 个MSL的时间。
危害:Linux分配给一个用户的文件句柄是有限的,如果系统中存在大量的 time_wait 状态,一旦达到句柄数上限,新的请求就无法被处理了,而且大量 time_wait 连接占用资源影响性能。
如何避免:在/etc/sysctl.conf
文件中开启 net.ipv4.tcp_tw_reuse
重用和net.ipv4.tcp_tw_recycle
快速回收。
3、select / poll / epoll 的区别
select | poll | epoll |
---|---|---|
操作方式 | 遍历 | 遍历 |
底层实现 | 数组 | 链表 |
IO效率 | 每次调用都进行线性遍历,时间复杂度为O(n) | 每次调用都进行线性遍历,时间复杂度为O(n) |
最大连接数 | 1024(x86)或 2048(x64) | 无上限 |
fd拷贝 | 每次调用select,都需要把fd集合从用户态拷贝到内核态 | 每次调用poll,都需要把fd集合从用户态拷贝到内核态 |
4、系统调用与库函数的区别?
简单点说,库函数就是系统调用的上层封装,为了让应用程序在使用时更加方便。
5、守护、僵尸、孤儿进程的概念
wait
/waitpid
子进程,那么子进程的进程描述符仍保存在系统中,这样的进程称为僵尸进程。
6、TCP 和 UDP 的区别?
TCP是稳定、可靠、面向连接的传输层协议,它在传递数据前要三次握手建立连接,在数据传递时,有确认机制、重传机制、流量控制、拥塞控制等,可以保证数据的正确性和有序性。
UDP是无连接的数据传输协议,端与端之间不需要建立连接,且没有类似TCP的那些机制,会发生丢包、乱序等情况。
TCP是数据流模式,而UDP是数据报模式。
7、请画出 TCP 的头部。
1、new 和 malloc 的区别?
void*
指针;
2、指针和引用的区别?
3、为什么 TCP 叫数据流模式? UDP 叫数据报模式?
所谓的“流模式”,是指TCP发送端发送几次数据和接收端接收几次数据是没有必然联系的,比如你通过 TCP 连接给另一端发送数据,你只调用了一次 write,发送了100个字节,但是对方可以分10次收完,每次10个字节;你也可以调用10次 write,每次10个字节,但是对方可以一次就收完。
所谓的“数据报模式”,是指UDP发送端调用了几次 write,接收端必须用相同次数的 read 读完。UDP 是基于报文的,在接收的时候,每次最多只能读取一个报文,报文和报文是不会合并的,如果缓冲区小于报文长度,则多出的部分会被丢弃。
4、简述一下 TCP 的滑动窗口机制
【答】TCP是通过滑动窗口来进行流量控制。
我们知道,在TCP头部里有一个字段叫 Advertised-Window(即窗口大小)。这个字段是接收端告诉发送端自己还有多少缓冲区可以接收数据,于是发送端就可以根据这个剩余空间来发送数据,而不会导致接收端处理不过来。
下面是发送端的滑动窗口示意图:
接收端在给发送端回ACK中会汇报自己的 Advertised-Window 剩余缓冲区大小,而发送方会根据这个窗口来控制下一次发送数据的大小。下面是滑动后的示意图(收到36的ack,并发出了46-51的字节):
Silly Window Syndrome:即“糊涂窗口综合症”,当发送端产生数据很慢、或接收端处理数据很慢,导致每次只发送几个字节,也就是我们常说的小数据包 —— 当大量的小数据包在网络中传输,会大大降低网络容量利用率。比如一个20字节的TCP首部+20字节的IP首部+1个字节的数据组成的TCP数据报,有效传输通道利用率只有将近1/40。
5、TCP的拥塞控制机制是什么?请简单说说。
我们知道TCP通过一个定时器(timer)采样了RTT并计算RTO,但是,如果网络上的延时突然增加,那么,TCP对这个事做出的应对只有重传数据,然而重传会导致网络的负担更重,于是会导致更大的延迟以及更多的丢包,这就导致了恶性循环,最终形成“网络风暴” —— TCP的拥塞控制机制就是用于应对这种情况。
首先需要了解一个概念,为了在发送端调节所要发送的数据量,定义了一个“拥塞窗口”(Congestion Window),在发送数据时,将拥塞窗口的大小与接收端ack的窗口大小做比较,取较小者作为发送数据量的上限。
拥塞控制主要是四个算法:
慢启动:意思是刚刚加入网络的连接,一点一点地提速,不要一上来就把路占满。
拥塞避免:当拥塞窗口 cwnd 达到一个阈值时,窗口大小不再呈指数上升,而是以线性上升,避免增长过快导致网络拥塞。
拥塞发生:当发生丢包进行数据包重传时,表示网络已经拥塞。分两种情况进行处理:
等到RTO超时,重传数据包
在收到3个duplicate ACK时就开启重传,而不用等到RTO超时
快速恢复:至少收到了3个Duplicated Acks,说明网络也不那么糟糕,可以快速恢复。
6、为什么析构函数要设为虚函数?
【答】在多态中,当使用基类指针或引用操作派生类对象时,如果不把析构函数定义为 visual 函数,则 delete 销毁对象时,只会调用基类的析构函数,不会调用实际派生类对象的析构函数,这样可能造成内存泄露。
7、linux下你常用的命令有哪些?
【答】ll、pwd、touch、rm、mkdir、rmdir、mv、cp、ln
cat、less、more、tail、vim、vimdiff、grep
tar、rz、sz
df、du、free、top、ethtool、sar、netstat、iostat、ps
ifconfig、ping、talnet……
1、static关键字的作用?
在C语言中:
在C++语言中,仍然有上面的作业,但多了下面两个:
2、C++的内存分区?
【答】C++的内存分区共有五个:
3、C++对象的内存布局。
【答】影响对象大小的有如下因素:
当然,还会有编译器的影响(比如优化),还有字节对齐的影响。
在单继承的情况下,内存布局:
在多重继承的情况下,内存布局:
在虚继承的情况下,内存布局:
4、vector、map/multimap、unordered_map/unordered_multimap的底层数据结构,以及几种map容器如何选择?
【答】底层数据结构:vector基于数组,map/multimap基于红黑树,unordered_map/unordered_multimap基于哈希表。
根据应用场景进行选择:
5、栈溢出的原因及解决办法。
【答】栈的大小一般默认为1M左右,导致栈溢出的常见原因有两个:
解决办法:
6、内存泄漏怎么产生的?如何避免?
【答】我们所说的内存泄漏一般是指堆内存的泄漏,也就是程序在运行过程中动态申请的内存空间不再使用后没有及时释放,导致那块内存不能被再次使用。
更广义的内存泄漏还包括未对系统资源的及时释放,比如句柄、socket等没有使用相应的函数释放掉,导致系统资源的浪费。
解决方法:
7、TCP建立连接为什么需要三次?断开连接又为什么需要四次?
【答】“三次握手”的主要目的是为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误。
例如:client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。本来这是一个早已失效的报文段。但server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求。于是就向client发出确认报文段,同意建立连接。假设不采用“三次握手”,那么只要server发出确认,新的连接就建立了。由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送ack包。
“四次挥手”主要是为了确保数据能够完成传输。
因为TCP连接是全双工的(即数据可在两个方向上同时传递),关闭连接时,当收到对方的FIN报文通知时,它仅仅表示对方没有数据发送给你了;但未必你所有的数据都全部发送给对方了,所以你可以未必会马上会关闭SOCKET,也即你可能还需要发送一些数据给对方之后,再发送FIN报文给对方来表示你同意现在可以关闭连接了,所以它这里的ACK报文和FIN报文多数情况下都是分开发送的。
1、core产生的原因,如何调试定位问题?
【答】原因大致有:
调试: 如果产生了core文件:gdb ./test core1517
然后进行backtrace(bt命令);如果没有core文件,查看dmesg
。
2、死锁产生的四个条件,死锁发生后怎么检测和恢复?
【答】死锁的四个必要条件:
死锁发生后:
3、堆和栈的区别?
4、简单描述一下TCP三次握手和四次挥手的过程。
5、数据库索引的优缺点?
优点:提高数据检索的性能。
缺点:
6、数据库的三范式?
7、如何在一个不安全的环境中实现安全的数据通信?
要实现数据的安全传输,当然就要对数据进行加密了。
如果使用对称加密算法,加解密使用同一个密钥,除了自己保存外,对方也要知道这个密钥,才能对数据进行解密。如果你把密钥也一起传过去,就存在密码泄漏的可能。所以我们使用非对称算法,过程如下:
由于在非对称算法中,公钥加密的数据必须用对应的私钥才能解密,而私钥又只有接收方自己知道,这样就保证了数据传输的安全性。
1、说几个C++11的新特性。
2、C++ STL中vector内存用尽后,为啥每次是两倍增长,而不是3倍或其他倍数?
【解】 1, 2, 4, 8, 16, 32,……可以看到,每次需要申请的空间都无法用到前面释放的空间。所以其实2倍并不是最佳增长倍数,最佳增长倍数大约为黄金分割 1.618。 例如:Java中的ArrayList每次扩容为1.5倍。
3、阻塞IO、非阻塞IO、同步IO、异步IO的区别?
【解】这里讨论的是Linux环境下的network IO。
在Richard Stevens的《UNIX® Network Programming Volume 1, Third Edition: The Sockets Networking》的第6.2节介绍了五种IO Model,并说明了各种IO的特点和区别。
当一个网络IO的 read 操作发生时,它会经历两个阶段:
这些IO Model的区别就是在两个阶段上各有不同的情况:
阻塞IO(blocking IO):线程阻塞以等待数据,然后将数据从内核拷贝到进程,返回结果之后才解除阻塞状态。也就是说两个阶段都被block了。
非阻塞IO(non-blocking IO):当对一个非阻塞socket执行读操作时,如果kernel中的数据还没有准备好,那么它并不会block用户进程,而是立刻返回一个error。用户进程需要不断地主动进行read操作,一旦数据准备好了,就会把数据拷贝到用户内存。也就是说,第一阶段并不会阻塞线程,但第二阶段拷贝数据还是会阻塞线程。
IO复用(IO multiplexing):这种IO方式也称为event driven IO. 通过使用select/poll/epoll在单个进程中同时处理多个网络连接的IO。例如,当用户进程调用了select,那么整个进程会被block,通过不断地轮询所负责的所有socket,当某个socket的数据准备好了,select就会返回。这个时候用户进程再调用read操作,将数据从kernel拷贝到用户进程。在IO复用模型中,实际上对于每一个socket,一般都设置成为non-blocking,但是,整个用户进程其实是一直被block的,先是被select函数block,再是被socket IO第二阶段block。
同步IO(synchronous IO):POSIX中的同步IO定义是—— A synchronous I/O operation causes the requesting process to be blocked until that I/O operation completes。也就是说同步IO在IO操作完成之前会阻塞线程,按照这个定义,之前所述的blocking IO,non-blocking IO,IO multiplexing都属于synchronous IO。(non-blocking IO也属于同步IO是因为它在真正拷贝数据时也会阻塞线程)
异步IO(asynchronous IO):POSIX中的异步IO定义是—— An asynchronous I/O operation does not cause the requesting process to be blocked。在linux异步IO中,用户进程发起read操作之后,直接返回,去做其它的事。而另一方面,从kernel的角度,当它受到一个asynchronous read之后,kernel会等待数据准备完成,然后将数据拷贝到用户内存,当这一切都完成之后,kernel会给用户进程发送一个signal,告诉它read操作完成了。也就是说两个阶段都不会阻塞线程。它就像是用户进程将整个IO操作交给了他人(kernel)完成,然后他人做完后发信号通知。在此期间,用户进程不需要去检查IO操作的状态,也不需要主动的去拷贝数据。
4、分时系统与实时系统的区别?
5、除了sleep之外,usleep()也是linux系统调用,它号称自己是微秒级的,你相信它真的有这么快吗?为什么?
【解】usleep实际上达不到微秒级,主要是因为linux是分时系统,由于进程调度(上下文切换)和系统时间中断精度的原因。
6、简述一下ping的原理。
【解】格式:ping 192.168.0.5
简单地说,ping就是给目标IP地址发送一个 ICMP 回显请求,并要求对方返回一个 ICMP 回显应答来确定两台网络机器是否连通,时延是多少。
在 ICMP 逐层封装的过程中,需要知道源IP、源MAC地址、目的IP、目的MAC地址,前三者是已知的,只需要获取目的MAC地址即可:
7、进程调度算法有哪些?Linux使用的什么进程调度方法?
【解】进程调度算法有下面几种:
Linux系统中,进程分为实时和非实时两种:
实时进程(相对于普通进程优先级更高)
普通进程
1、static_cast 和 dynamic_cast 的区别。
【解】这两个都是C++中的RTTI的两个操作符,它们之间的主要区别是:
2、DNS使用什么协议?
【解】DNS使用TCP和UDP协议,具体是:
这是因为以太网(Ethernet)数据帧的长度必须在46-1500字节之间,这是由以太网的物理特性决定的。这个数据帧长度被称为链路层的MTU(最大传输单元)—— 实际Internet上的标准MTU值为576字节,也就是说链路层的数据区(不包括链路层的头部和尾部)被限制在576字节,所以这也就是网络层IP数据报的长度限制。
因为IP数据报的首部为20字节,所以IP数据报的数据区长度最大为556字节。而这个556字节就是用来放TCP报文段或UDP数据报的。我们知道UDP数据报的首部8字节,所以UDP数据报的数据区最大长度为548字节。—— 如果UDP数据报的数据区大于这个长度,那么总的IP数据包就会大于MTU,这个时候发送方IP层就需要分片(fragmentation),把数据报分成若干片,使每一片都小于MTU,而接收方IP层则需要进行数据报的重组。由于UDP的特性,当某一片数据传送中丢失时,接收方将无法重组数据报,从而导致丢弃整个UDP数据报。所以通常UDP的最大报文长度就限制为512字节或更小。
3、traceroute命令有什么作用?原理是什么?
【解】traceroute命令用于追踪从本机到指定主机的路由途径。
traceroute程序是利用 ICMP 及 IP 头部的 TTL(存活时间)来实现其功能的。每当数据包经过一个路由器,其存活时间就会减1。当其存活时间是0时,主机便取消数据包,并回复一个「ICMP time exceeded」数据包给发出者。
首先,traceroute发送一个TTL为1的数据包到目的地,当路径上的第一个路由器收到这个数据包时,将它的TTL减1。此时,TTL变为0了,所以该路由器会将此数据包丢掉,并送回一个「ICMP time exceeded」消息,traceroute 收到这个消息后,便知道这个路由器存在于这个路径上。接着traceroute 再送出另一个TTL是2 的数据包,发现第2个路由器…… traceroute 每次将送出的数据包的TTL加1来发现另一个路由器,这个重复的动作一直持续到数据包抵达目的地。
当数据包恰好抵达目的地时,由于traceroute所设置的端口是一个一般应用程序都不会用的号码,所以该主机会回送一个「ICMP port unreachable」的消息,而当traceroute 收到这个端口不可达的ICMP消息时,便知道目的地已经到达了。
4、什么是事务?事务有哪些特性?
【解】事务是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。
5、MySQL的引擎 InnoDB 和 MyISAM 的区别。