面经-网络

基础知识:

网络:

cookie和session的区别

这两个都是为了解决http协议无状态的问题而提出的,两者合作共同解决这一个问题

cookie是存放在客户端的,记录一个sessionid,是服务器发送给客户端用来唯一标识一个客户的

session存放在服务器端,利用sessionid来区分不同的客户

跳跃表

http://blog.jobbole.com/111731/

https://www.cnblogs.com/George1994/p/7635731.html

跳跃表的性质(空间复杂度是o(n))

由很多层组成,每一层都是一个有序链表

每一个节点有两个指针,一个指向同一层的下一个节点,一个指向下一层的同一个节点

最后一层链表包含所有的元素

跳跃表的查找(时间复杂度log(n))

自上而下查找,一直查找到一个节点的值小于给定值并且该节点的下一个节点的值大于给定值,然后进入下一层继续查找,如果没有下一层,则查找结束

跳跃表的插入(查找的时间复杂度o(logn)+插入的时间复杂度o(1)=o(logn))

自上而下查找待插入的节点的插入位置,然后插入节点,同时根据抛硬币的原则决定是否提升当前节点,如果要提升则在其上层节点中插入当前节点,然后对上层中插入的节点做相同的处理,如果不提升则插入结束

跳跃表的删除(查找的时间复杂度o(logn)+插入的时间复杂度o(1)=o(logn))

自上而下,在各个层中找到指定值的节点并删除,如果当前层只剩下头尾两个节点则删除这一层

include尖括号和双引号的区别

尖括号一般默认是库文件会去系统的include目录里去搜索然后再去搜索源代码目录

双引号默认是用户自定义的头文件会现在源代码所在目录里搜说然后再去系统目录里搜索

两种事件处理模型

reactor模式(同步I/O):主线程只负责监听文件描述符上的事件,有的话通知(消息队列)工作线程,工作线程负责连接,I/O和业务处理。(有点像炒菜,主线程只是报个菜名,然后后面的切菜炒菜都是工作线程负责)

proactor模式(异步I/O(信号)):主线程和内核负责所有的I/O操作,工作线程只负责业务处理部分(主线程负责记菜名,切菜,工作线程只是炒一下就好了)

数组名和指针的区别

两者都是指针,数组名是数组首元素的指针,但是数组名是一个常量指针,本身不能改变,但是它所指之物的值何以改变

开机流程linux系统

首先开机启动的第一个程序是bios,bios去读cmos,里面是一些系统的硬件的一些基本参数,bios知道了硬件就能找到第一个可开机的设备,然后去读里面的第一个分区MBR的boot loarder程序,boot loarder再去加载内核到内存中,内核加载之后启动的第一个程序是init(systemd)进程

如何判断一个图是否连通

dfs,bfs 从任意一点开始遍历图,如果图是连通的那么就能访问到所有的节点,否则不是连通图

如何把一个文件快速下发到100w个服务器上

树状:每个服务器接受上层服务器传来的文件之后像下层服务器转发

p2p:将文件分块分发到不同的服务器上,每个服务器可以向其他服务器请求文件的同时向别的服务器也传输文件,很快就可以扩散到100w台服务器

引用和指针的区别?引用占不占内存怎么验证

  • 指针保存的是所指对象的地址,引用是所指对象的别名,指针需要通过解引用间接访问,而引用是直接访问;
  • 指针可以改变地址,从而改变所指的对象,而引用必须从一而终;
  • 引用在定义的时候必须初始化,而指针则不需要;
  • 指针更灵活,用的好威力无比,用的不好处处是坑,而引用用起来则安全多了,但是比较死板。

引用在作为函数参数的时候占内存,因为实际上是传递了一个指针进去,除此之外不占内存。

验证可以通过int a=1;int& b=a;  int c=2,查看ac的地址是连续的

菱形继承存在虚函数的情况下,类的内存分布?,使用虚继承不考虑虚函数类的内存分布?

菱形继承存在虚函数的情况下,b,c继承a,      d继承b,c   

d的内存布局首先显示b的部分,然后是c的部分,最后是d的部分

b的部分中包含了a,如果a中有虚函数,那么有一个虚指针,这个虚指针是b中的a和b还有d共享的

c的部分中也包含了a,如果a中有虚函数,那么有一个虚指针,这个虚指针是c中的a和c共享的

使用虚继承不考虑虚函数类的内存分布:

d的内存布局首先是b的部分,然后是c的部分,然后是d的部分,然后是a的部分

b的部分首先是一个虚基类指针,这个指针指向a的部分

c的部分也是最开始是一个虚基类指针,这个指针同样指向a的部分

epoll两种工作模式的区别

LT(电平触发,默认)ET(边沿触发,更高效)

LT:应用程序调用epoll_wait,对某一个文件描述符上的时间如果不处理的话,下次epoll_wait还会报告给应用程序知道被处理

,但是ET工作模式只触发一次,必须立即处理,否则不会再报告。因此ET会避免一个事件被重复多次触发,会更高效

拷贝构造函数?智能指针的拷贝构造函数和赋值运算重载函数?

拷贝构造函数:

A(const A&  x){

        this.val=x.val;

}

赋值运算符重载函数:

A& operator=(const A& x){

     this.val=x.val;

}

智能指针的实现

https://www.cnblogs.com/lengender-12/p/6658679.html

UDP如果报文太长怎么办?

封装成IP报文的时候,超过了MTU,IP协议会将其分片

堆和栈的区别?为什么栈快?(分配1,访问3)

https://blog.csdn.net/baidu_37964071/article/details/81428139

1.栈是由系统负责分配回收,堆是由程序员负责申请释放,栈的分配更加快速,堆的更慢,因为需要遍历系统的空闲链表找到合适大小的空闲块,同时还有内存碎片的问题

2.栈的大小有限,堆可以分配更大的空间

3.数据的存取效率:栈提供系统级的支持有专门的寄存器(sp存放栈顶地址)还有机器指令,栈的数据访问可以直接找到数据,而堆的数据访问需要先读取堆的地址然后再去读堆中的数据因此更慢,间接寻址(地址放在寄存器中,先去寄存器中读取地址,然后再根据地址去读取数据)

C++和c的区别

c是面向过程的,c++是一个支持多种特性的语言,他兼容c,也有面向过程的部分,同时他还有面向对象的特性,还有模板和泛型编程。

c和c++的内存管理方式也不同,一个是malloc,free  一个是new,delete

为什么内存分配采用栈?为什么要采用后进先出的形式?

霍夫曼编解码?

首先先建立霍夫曼树(根据每个字符出现的频率,频率高的编码的长度比较短),对每个字符进行编码(左子树1右子树0,然后从根节点开始遍历,路径上面的所有01串组成一个字符的编码)

解码过程就是每次从根节点开始遍历直到到达叶结点,将该编码串翻译成叶结点对应的字符,再从下一个编码串开始直到翻译完

如何判断内存泄露,野指针是什么,内存泄漏怎么办?

野指针:指向已经释放的内存或者没有访问权限的内存指针(感觉空悬指针是野指针的一种?!)

内存泄漏:申请了一块堆上的内存,但是没有显示释放掉,造成内存泄漏;对象没有被正确的析构掉(父类析构函数非虚)

指针越界:访问没有访问权限的内存

空悬指针:指针没有初始化指向一个不确定的地方,或者指针所指的地址释放掉之后,指针没有赋空,依然指向已经释放掉的内存

检测内存泄漏:检测malloc和free是否匹配,window下可以利用crt库跟踪内存的分配(分配内存的代码所在的行和文件,第多少次分配,可以通过添加断点(根据次数)观察函数调用栈发现内存泄漏的代码)和释放。如果没有正确释放就会被检测出来。

内存快照:在有可能发生泄露的地方获取内存快照进行对比

linux下用valgrind

浏览器输入地址后发生的全过程

涉及到的协议http,dns,tcp,udp,ip,arp

首先需要对输入的域名进行解析,利用DNS协议,获得IP地址(DNS需要首先获取域名服务器的IP地址,然后经过一系列的封装(将DNS报文封装成底层的UDP再封装成IP包,在封装成帧)发送到DNS服务器,DNS服务器响应并给出IP地址。帧的发送需要用到mac地址,如果arp缓存表里面没有对应的mac地址,还需要把IP地址转换成mac地址,用到arp协议(附加arp请求的过程))

拿到域名对应的IP地址之后,就可以进行http请求了,http协议建立在tcp协议之上,因此需要首先进行三次握手建立连接

建立连接之后就可以进行http请求和响应了

最后客户端请求结束断开连接,四次挥手

为什么是三次握手,四次挥手

tcp是全双工通信,因此至少需要三次握手才能确保双向的连接。三次握手能在一定程度上减少syn攻击(主动连接端不停的发送syn报文,如果只是两次握手的话,服务器端的资源会很快被消耗完,导致服务器崩溃,如果是三次握手还需要回复ack报文,增加攻击的难度),另外就是防止失效的连接造成错误,a向b发送的同步报文由于超时,a又重新发送了新的同步报文,并和b建立了连接之后完成通信接着断开连接,此时超时的同步报文到达b,b以为a又发起了新的连接,如果没有三次握手,那么b就一直等待着a,消耗了资源,如果有三次握手的话,b等不到a的确认报文就不会建立连接

四次挥手:同样因为tcp是全双工的,所以要可靠的关闭两端的通信最少需要三次,但是有可能被动关闭方还有数据没有发送完或还没被全部确认有可能需要重新发送,所以有可能不会立即关闭,因此被动关闭端的fin报文和ack报文会分开发送所以需要四次

c++解决内存泄漏方法

使用智能指针管理内存,只能指针在其析构函数中会自动进行资源的释放,shareptr首先会判断引用计数是否为0.如果不是只是将引用计数减一,如果是的话就调用delete将内存释放掉

但是shareptr会存在循环引用的问题,也会造成内存泄漏,解决方法是weakptr,weakptr不会增加引用计数(将一个对像内部的shareptr换成weakptr),因此不会造成循环引用的问题

DNS的底层协议

dns同时占用tcp和udp的53的端口
区域传送时使用TCP(辅域名服务器会定时(一般时3小时)向主域名服务器进行查询以便了解数据是否有变动。如有变动,则会执行一次区域传送,进行数据同步。区域传送将使用TCP而不是UDP,因为数据同步传送的数据量比一个请求和应答的数据量要多得多)
域名解析时使用UDP协议

Linux查找特定文件

查找内容中包含某个字符串的文件:find  . |xargs  grep '字符串'

查找文件名中包含某个字符串的文件:find . -name '字符串'

历史命令

history(显示所有的)

history  3(显示最近的三条)

!command(执行最近一条包含conmmand的命令,相当于补全)

向上的箭头(表示上一条命令)

Vim命令

复制yy(nyy)

粘贴p(粘贴到光标所在行的下一行) P(上一行)

移动到第一行(gg),移动到最后一行(G,移动到第n行,nG),移动到一行的开头(0),移动到一行的结尾($) 向下移动n行(n+enter)

删除光标处的一个字符dl(或者x 向后删除n个字符nx ) 向前删除X=backspace   删除整行dd(ndd)

列选择 ctrl+v

上下翻页:ctrl+b(上)ctrl+f  (下)

搜索:/word(向下搜索)?word(向上搜索) :1,$s/word1/word2/g (替换)  :1,$s/word1/word2/gc(询问是否替换)

撤销u(反撤销ctrl+r)

重复前一个动作  (.)

-------------------

编辑模式 i (插入一个字符)  o(插入一行)

--------------------

命令模式:!wq

---------------------

连续选择多个字符:v (左右键)  连续选择多行V(上下键)  选择一块,相当于箭头按住选择一个矩形区域(ctrl+v)

块选中之后的操作(复制y   粘贴p   删除d)

查看系统命令

free

https://www.cnblogs.com/pengdonglin137/p/3315124.html

分total  used  free  cache  buffer   (total=used+free)

mem是对操作系统而言的,所以cache+buffer被算进了used里面

但是+、-buffer,cache是对应用程序而言的,认为cache和buffer总是可用,把cache+buffer被算进了free里面

top

https://www.cnblogs.com/dragonsuc/p/5512797.html

按数字键1可以查看多cpu的状态。否则一般显示的是所有cpu的一个平均值

linux中查找命令find、locate、whereis、which、type区别

find可以查找所有类型的文件,会搜索磁盘

locate比find快也是所有类型的文件,因为他会查询一个数据库

whereis 查询二进制文件,man文件,也是查询数据库

which会在path变量指定的路径中查询系统命令(系统命令对应的可执行文件)

type也是查询命令时shell自带的还是外部的命令

SQL慢查询:

https://www.cnblogs.com/qmfsun/p/4844472.html

第一步设置慢查询的日志(在mysql的配置文件中设置),可以设置日志的路径还有日志文件名,然后设置要记录的慢于多长时间的语句需要记录

第二步分析具体的语句,用explain ,可以看到一个查询的执行计划,怎么执行的,用了哪些索引,从而可以进行优化

常量引用(对const的引用)的作用

限定引用所引用的对象不能通过该引用被修改

常量引用可以引用非常量对象,可以引用字面值,可以引用表达式,可以引用类型可引用类型不一致的类型(本质是产生了一个临时对象)

最优二叉树(霍夫曼树)

带权路径最短的二叉树,权值乘以从根节点到叶结点的路径长度称为带权路径

Linux扩大分区

第一如果使用的是LVM几逻辑卷管理就可以动态的扩展分区(扩展原理:首先许多物理的分区或者磁盘(PV)组合成一个大的逻辑的磁盘(VG),然后这个大的逻辑的磁盘进行分块,每一个小块就PE,分区的实现是将VG进行分区形成LV,LV的扩大就是增加PE,减小就是删除PE)

第二删除老的分区(删除之前备份数据),重新划分一块更大的分区(前提是还有空闲空间)然后文件进行拷贝

第三重新建立一个新的分区(前提是还有空闲空间),然后把新的分区挂在到老的分区下面就可以继续使用

磁盘阵列

raid-0 有多块磁盘,每次写数据的时候数据被分散的写到各个磁盘上面,因此读写性能很好,但是一块磁盘的数据损坏之后所有的数据就都不能用了

raid-1  (镜像)每个磁盘上都存相同的数据,读性能极佳,但是磁盘容量会减半

raid-01  先组装成raid-0,再组装成raid-1

raid-5搞不清楚

map用的是红黑树,和AVL树的区别

都是平衡二叉树,但是红黑树的平衡性没那么严格,AVL是左右子树的高度相差不超过一,红黑树只需要保障对任意一个节点,从这个节点出发到叶结点的所有路径上面的黑节点的数目一样即可。因此AVL的平衡性的维护代价也比红黑树高,红黑树一般不需要自底向上的一个不断调整的过程(伯父节点是黑节点),如果非要涉及到这样一个调整的话(伯父节点是红节点),那么可以采用自顶向下的一个过程来减少旋转操作(只需要修改节点的颜色)

map删除元素要注意什么?
删除元素之后原来的迭代器就会失效,一般用这个语句比较好 m.erase(iter++)先返回iter的副本,不会影响iter本身,iter本身已经指向下一个元素了

25u-50结果是多少,u代表unsigned

25+max(unsigned int)+1-50

什么时候出现段错误

指针越界

系统中断

第一类cpu外部中断:I/O中断,时钟中断

第二类cpu内部中断:溢出,越界

第三类系统调用中断

发生中断的时候会从用户态切换到内核态。内核态的优先级高不允许被抢占,并且处于内核态的时候可以访问到所有的内存空间,用户态与之相反

模板类中可以使用虚函数吗?模板成员函数可以是虚函数吗?

https://blog.csdn.net/zzuchengming/article/details/51763563

模板类中可以使用虚函数。和普通的类没有区别。

但是模板成员函数不能是虚函数,因为类在定义的时候必须确定虚函数表的大小,但是模板成员函数只有在调用的时候才实例化,因此必须知道有多少模板成员虚函数被调用了才能知道有多少虚函数也才能确定虚函数表的大小,但是并不能提前知道有多少函数被调用了。

什么时候需要自己定义构造函数,拷贝构造函数,赋值运算符,析构函数?编译器什么时候需要合成构造函数拷贝构造函数等?

需要定义析构函数的类一般都需要定义拷贝函数和复制运算符函数,一般管理动态内存的类需要定义析构函数(像share_ptr)

四种情况:(一般而言编译器在有必要的时候才会为类合成构造函数等一些函数)有必要的时候是指:含有基类,含有成员对象,含有虚函数,含有虚基类

 

forward, move,右值引用,移动拷贝

https://www.cnblogs.com/my_life/articles/5995578.html

左值和右值:凡是&操作能够成功的,都是左值,其余都是右值

一般的引用时左值引用

右值引用:对右值的引用

移动拷贝函数:( A(A &&  t)  ;    A(const A& t))就是避免复制。

move :将左值转换成右值

forward :一般是一个函数中调用另一个函数,他们的参数又是同一个,希望可以达到第一个函数中的参数是左值那么第二个函数中的参数也是左值,第一个的是右值第二个的也是右值,一般用在模板函数中

RAII机制

利用类去管理资源(内存,数据库连接,套接字,互斥锁),防止资源泄漏。原理是将资源的释放操作放在管理资源的类的析构函数中,利用析构函数会再对象结束生命周期之后自动调用的原理,将自动的释放资源,从而避免资源泄漏。

各种排序空间复杂度和时间复杂度,稳定程度

https://blog.csdn.net/yushiyi6453/article/details/76407640

字节序,网络序是什么字节序,为什么会有不同的字节序

小端:高字节高地址,低字节低地址

大端:高字节低地址,低字节高地址

网络序是大端

为了交换数据的方便和统一,不管机器字节序是什么大家都统一遵循网络字节序是大端字节序,因此从网上接受到的数据和发送到网络中的数据都是大端字节

opencv里面的基本算法(搞一个能讲出原理,会做,其他知道名字知道是干嘛的就行)

开源的视觉库(图像处理库)。

基本的数据结构:cvmat    iplimage  

图像处理:平滑(中值平滑),形态学(膨胀,腐蚀,开运算(突出的部分消失),闭运算(凹陷的部分消失)),缩放,阈值化

图像变换:卷积(图像中的点的灰度值和核中的值相乘相加作为核中心元素卷积后的值,实际意义,比如说求均值的时候可以定义一个3*3大小的每个元素都是1/9的核,卷积实际就是在求一个3*3邻域的均值),梯度,canny,旋转平移,傅立叶变换(整不明白)

解决hash冲突的几种方式

第一,开链;第二,线性探测(1,2,3),二次探测(1,4,9);第三,再哈希,使用第二个哈希函数,第三个直到不在发生冲突为止

有哪些方法清除cache中旧的数据

两种缓存:cache(读缓存)  buffer (写缓存)

sync命令

echo 1>drop_caches清理页面缓存

echo 2>drop_caches清理目录缓存和inode

echo 3>drop_caches清理页面、目录缓存和inode

多进程和多线程的使用场景

https://blog.csdn.net/qq_16209077/article/details/52769609

需要使用并发的时候,需要用到多进程和多线程

从数据同步和共享来讲,多线程的数据同步比较复杂,数据共享很简单

创建和切换,多线程是比较快速,因为没有自己的资源

编程和调试,多进程简单一点

可靠性,多进程更可靠一点

分布式,多进程是多核,多机分布,多线程是多核分布

需要频繁的创建和销毁,需要大量的计算一般用线程。多机分布的话用多进程

B+树,跟B树有什么区别?

m阶B树每个节点最多只有m-1个元素,B+数最多有m个

B+说的所有数据元素都同时存放在叶子节点

查找数据的复杂度,B+树是稳定的,B树则跟查找的元素有关系。B+树的范围查找很方便

cout和printf有什么区别?

cout对于类型的控制更加安全(不用指定具体类型,因此也不怕指定错了之后会有错误的后果)智能;扩展性好(可以根据用户自定义的类型来重载运算符就可以实现用户自定义类型的输出,但是printf只能输出特定的几种类型)

为什么模板类一般都是放在一个h文件中?(不太会)

放在h文件中可以很方便的被包含到其他文件中,这样在实例化模板的时候就可以找到相应的模板定义。放在h文件中可以不用去处理,也符合模板没有被实例化就不用被处理,但是放在cpp文件中需要被处理,但是又不知道相应的类型无法处理。

自己设计如何采用单线程的方式处理高并发

异步I/O处理,proactor模式

判断一个点是不是在三角形内

https://blog.csdn.net/deepseazbw/article/details/75913253

面积法:三个小三角形的面积之和等于大三角形的面积

同向法:该点与任意顶点在其他两个顶点所形成的直线的同侧

讲讲大量请求时怎么办(分布式集群,I/O复用,缓存,索引)

说明联合共用内存的概念

不同数据类型共享同一段内存,同一时刻只有一种数据类型的数据有效。为了节省内存。

 

 

 

 

 

 


智力:

时针和分针的夹角计算

先计算分针走过的角度x*(360/60)   然后计算时针走过的角度y*(360/12)  然后计算分针带动时针走过的角度x*(30/60)然后计算时针和分针走过的角度的差的绝对值就是两者之间的夹角

一副扑克牌,怎么实现随机打乱?

https://blog.csdn.net/zly9923218/article/details/51418366

对第一张牌,产生0-n-1的随机数,并将第一张牌和随机数代表的牌进行交换

对于第二张牌,产生0-n-2的随机数,并价格他们交换

这样可以保障每张牌出现在每个位置上的概率都是1/n

第一张是1/n

第二张是在第一张的基础上是条件概率 (1-1/n)*(1/(n-1))=1/n


一到一百万的素数,怎么快速求

用查表的方法,刚开始用3-一百万的数除以2,能整除的去掉

然后接着用4-一百万的数除以第二个质数3,能整出的去掉

一次用质数去除,最后剩下的数就是所有的质数
topk,快排,堆,复杂度

有一堆数,再给你很多对数,每对数都在同一个组,求一共有多少组数

 

 

int to string,string to int(string to int的时候,数字越界要抛出异常,要考虑负数,前置0等情况)

删除单项链表中重复的节点 (1 2 2 3 3 9) -> (1 2 3 9)

求二叉树的深度

单链表判环

求一个数组的最长连续子序列(连续,不连续),最长递增子序列(连续,不连续)

判断一颗树是不是二叉搜索树

之字形打印二叉树

二分查找中位数

手写vector<int> 扩容代码

memcpy 函数  怎么实现的

求每一个元素右边第一个最大元素

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值