持续更新!!!!!
网络部分
1.问,四次挥手的过程,和双方状态变化?
挥手这前,两边都是established状态,客户端发起断开请求,向服务器发送fin请求,状态变为fin_wait_1。服务器对断开请求进行响应,发送ack报文,状态变为closed_wait,等服务器要发送到客服端的数据发送完毕,服务器也发起断开连接的请求,向客户端发送fin,状态变为last_ack,客户端这边先是收到ack报文,状态变为fin_wait_2,接着收到服务端的断开请求,进行响应,进行最后一次握手,发送ack,状态变为time_wait,等待2msl(报文最大生存时间),最后状态为closed,服务端收到客户端的ack报文,最后状态也为closed,此时双方的连接都断开了
2.为什么要四次握手?
因为断开连接不是一方断开就行了,tcp通信是双向通信,所以要两边都断开,而两次挥手对应一次断开连接,所以要四次挥手
3.一定要三次握手才能连接吗?其他次数呢?
大于等于三次都可以,但三次就可以完成了,多次握手只会浪费资源,降低效率,而小于三次,假如为一次的话,一来不能验证双方接收功是否正常,二来服务器非常容易被搞崩溃,因为客户端只要无限向服务端发送syn连接请求报文,服务端就得一直进行连接,显然不合适。
那两次呢,一来还是不能验证功能是否完整,比如只握两次手,不能验证服务端不能验证自己是否能发,和客户端是否能收,二来还是同样的原因,容易崩溃。
三次是建立通信验证功能完整的最小次数。综上所述,是三次握手最合适
4.tcp和udp的区别,谈谈呗?
一,tcp是面向连接的传输层协议,在通信之前要建立一个通信通道,三次握手就是建立这个通道的过程,而四次挥手就是销毁这个通道的过程。而udp是无连接的传输层协议,在通信之前无需,建立连接。
二,tcp只有两个端点,所以通信只能一对一,而udp可以支持一对一,一对多,多对多通信。
三,tcp是可靠传输,保证传输的报文数据,无差错,不重复,按序到达,而udp是不可靠传输,只能努力交付报文数据,不保证数据的完整性,可靠性。
四,udp的传输速度大于tcp的速度
五,tcp有流量控制和拥塞控制,udp没有
刘,tcp首部有20个字节,开销大,储存信息大,而udp只有8个字节,开销小,储存信息小。
5.tcp是如何做到可靠传输的呢?
第一呢,tcp通过三次握手,四次挥手,来保证所建立的传输信道是可靠的
第二,tcp通过ARQ协议(超时自动重传)来确保数据传输的正确性,通过滑动窗口协议来确保接收方能够及时处理发来的数据报文,进行流量控制。
第三呢,tcp使用慢开始,拥塞避免,快重传和快恢复拥塞控制,避免网络拥塞。
通过以上三点来确保可靠传输
6.osi七层模型和对应功能?
物理层:
利用传输介质为数据链路层提供物理连接,实现比特流的透明传输(底层数据传输
)
数据链路层:
定义数据的基本格式,比如如何传输,如何表示,如,网卡Mac的地址
物理层:
定义IP编址,定义路由功能,如,不同设备的数据转发。
传输层:进行传输数据的控制,如tcp,udp
会话层:
控制应用程序之间的会话能力,比如不同软件数据发给不同的软件
表示层:
数据格式标识,基本压缩加密功能
应用层:直接向用户提供服务,完成用户希望完成的,如http,https
7.http的常见状态码?
301永久重定向
302暂时重定向
404资源没有找到
400请求错误
500服务器错误
8.4位首部长度作用?
读取tcp前20字节,提取出4位首部长度,也就是获得tcp报头大小size,要是这个size大于20字节说明还要对相应的选项,剩下的就是有效载荷
9.16位源端口号的作用?
因为内核中用哈希维护了端口号和进程的关系,所以可以通过端口号找到对应的进程
10.32位序号和32位确认序号作用?
因为发送方发送的报文,到达接收端的顺序可能是不一样的,比如1002 1003 1001
那么就需要报文序号,把到达的报文排好序,确保数据的可靠,而确认序号的作用是,向对端发出信号,说之前的报文我收到了,请从这个序号后面开始继续发送,谢谢。
11.16位窗口大小的作用?
16位窗口大小表示发端告诉对端,自己的接收缓冲区还有多少空间
12.6位标志位作用?
不同的报文有不同的类型,对应着不同处理动作比如要是是正常通信的报文,直接放缓冲区,等待用户读取,要是是连接断开请求,就不是用户去处理这个数据,而操作系统让tcp执行相应的握手和挥手动作
标志位有这些,syn中标记为1表示请求连接,fin位为1表示请求断开,ack为1表示对上次收到的报文的确定
13.16位检验和作用?
16为检验和作用检验数据是否出错了
14.16位紧急指针的作用?
当对端堆积了很多请求待处理或者有个请求要紧急处理,要使用16位紧急指针,而对端会优先处理这个报文
STL 部分
15.谈谈STL的容器?
STL的容器分为两种,序列化容器,关联化容器
序列化容器有
vector底层是一段连续的线性的空间
list底层是双向链表
deque单调链表
(可以组合成stack,queue,优先级队列 )
set和multiset是红黑色(平衡搜索二叉树)
map和multimap同上
unordered_set和unordered_map底层是哈希表
16.具体谈谈set
OK好的 set可以去重,他不允许重复的值的出现,用迭代器遍历set可以得到有序的序列e,因为底层是红黑树,所以元素不能被修改,而且搜索速度为logn,比unordered_set慢。
17.multiset和multimap呢?
multiset允许键值冗余,multimap允许键值冗余
18.具体谈谈map吧?
map是关联化容器,底层是红黑树,所以不能修改元素,搜索速度为logn,可以去重,有序,不能键值冗余,可以通过键值key,找到值value
19.平衡二叉树?
1.左右子树也是平衡二叉树
2.左右子树高度之差不差过1
3.左树的节点值全部小于根节点值,右树的节点值全部大于根节点的值
红黑树?
红黑树是一颗二叉搜索树,他在节点类里增加了一个颜色变量,时刻确保最长路径的长度不超过最短路径的两倍,因而近似平衡。
规则有 根节点必须是黑色,每个节点不是黑色就是红色,要是一个节点是红色,那么他的子节点就一定是黑色等等
20.为什么有了平衡二叉树还要红黑树?
虽然平衡二叉树的查找,搜索,删除的时间复杂度都是logn,但要插入,和删除打破了高度之差就要进行复杂的旋转,是一笔不小的开支。而红黑树的就不需要通过旋转节点来时时刻刻,保持高度之差不超过一,可以改变节点的颜色,从而避免多余的旋转开销
21.谈谈unordered_set吧
数据的储存无序,可以去重,不允许重复
查找时间复杂度为log1,但迭代效率比set低
22.谈谈unordered_map
无序 去重 可以使用[]获取value值
查找log1,迭代效率低
unordered_multiset和unordered_multimap不多说
哈希表实现,允许键值冗余
23.谈谈哈希表,?
哈希表是一种高效的查找数据结构
常见的有两类
一是闭散列,分为线性探测,就是往后推一,还有中是二次探测,加i的平方
二是散列式,意思就是说,当产生哈希冲突时,把冲突的元素挂着后面,形成链表,其中一类方法,负载因子保持在0.7左右,二类方法负载因子可以超过1。当这个链表过多元素,查找的速率就退化成on了,那此刻便可以把链表变成红黑树,变为logn,此谓,哈希桶里中红黑树,桶里中树
24.哈希表位置为什么要有三种状态?
有存在,删除,空白三种状态,是为了确保能够正确进行查找,比如在线性探测中,查找时要到空数组位置,要是没有三种状态,就直接返回哈希表中没有这个元素的结果,但其实,这个空数组位置可能只是被删除留下的空白位,后面有我们要查找的元素
查找40这种情况
25.哈希表扩容怎么扩?
不要按2倍2倍的关系去扩大哈希表容量,按素数数字扩大,假如此时容量是10,可以变成13,大一点可以扩大成19,甚至可以拿一个数组保存要扩大容量素数
linux部分
26.什么叫临界资源,临界区,原子性?
多线程执行流共享的资源叫临界资源
线程内部,访问临界资源的代码叫临界区
不会被任何调度机制打断的只有两种状态的叫原子性
27.为什么变量a–不是原子性操作?
因为有三步,第一步,把变量加载到寄存器中,第二步,寄存器完成–操作,第三步,操作系统把寄存器的值放回内存中
28.pthread_mutex_t mutex定义互斥量
pthread_mutex_init(&mutex,null)初始化互斥量
pthread_mutex_destroy(&mutex)销毁互斥量
pthread_mutex_lock(&mutex)加锁
pthread_mutex_unlock(&mutex)解锁
29.怎么保证申请锁的过程是原子性的呢?
刚开始内存中的mutex为1,寄存器里的al为1,当线程申请锁的时候,将自己寄存器中的al值清零,然后将mutex和al交换,这个交换指令为一条汇编指令,然后寄存器判断al是否大于0,然后大于0,则,加锁成功,若此时,有其他线程申请加锁,由于内存中mutex为0,进行交换后,寄存器中的al还是为0,所以会申请失败,这套流程保证了,申请锁的过程是原子性的
30.什么叫线程安全?
当有多个执行流并发同一段代码,不会出现不同的结果,称为线程安全
什么叫做重入,什么叫做可重入函数?
当一个执行流执行一个函数,还没执行完,就有其他的执行流来执行,叫做重入。一个函数在重入的情况下,不会出现其他情况,叫做可重入函数,否则就是不可重入函数
31.可重入和线程安全的联系?
可重入是指函数,线程安全是指线程在执行代码时是否安全
可重入函数一定是线程安全的,但反过来不一定成立
32.谈谈死锁?
打个比分,有两个线程个申请了一把锁,此时两个线程都想要对方的锁,就申请,结果失败,然后两个线程都被挂起等待,但两把锁都无法释放,此时这两把锁就是死锁了。
当然单执行流也可能导致死锁,比如一个线程连续申请两次加锁,第一次成功,但第二次会失败被挂起等待锁的释放,而这把锁本来就被自己线程拿住了,挂起状态无法释放,所以此时也会变成死锁!
33.死锁的必要条件?
满足死锁的四个条件,比如不剥夺条件,一个线程获得的资源,在未使用完之前,不能强制剥夺。满足了死锁的四个必要条件才可能产生死锁。
避免死锁的方法,破坏四个必要条件,避免锁未释放的情况,还有一些算法,比如银行家算法,死锁检测算法
34.为什么条件变量要配合互斥锁使用?
如果没有互斥锁,当唤醒等待条件变量满足的线程时,可能会有多个线程被唤醒,进行执行同一个临界区就可能有线程安全
35条件变量相关函数?
pthread_cond_t cond
定义一个条件变量
pthread_cond_init(&cond)
初始化一个条件变量
pthread_cond_wait(&cond,&mutex)
阻塞等待一个条件变量
pthread_cond_signal(&cond)唤醒一个阻塞在条件变量上的线程
pthread_cond_broadcast(&cond)
唤醒所有阻塞在条件变量上的线程
pthread_cond_destroy(&cond)销毁一个条件变量
36.说说pthread_cond_wait函数的作用?
第一,阻塞等待条件变量的满足
第二,释放已有的互斥锁
第三,当条件变量满足后,线程被唤醒后,立马申请互斥锁
其中第一二步是原子性操
他日若遂凌云志,敢笑黄巢不丈夫!