1:new delete 与 malloc free的区别
1-> new是C++运算符,malloc是C的库函数
2-> 通过new创建的是具有类型的,malloc返回的则是void * ,需要进行类型强制转换
3-> new可以自动调用构造函数,而malloc不会
4-> new失败时会调用new_handler处理函数,而malloc失败直接返回null
5-> delete是C++运算符,free是C标准库函数
6-> delete自动调用对象的析构函数,而malloc不会
2:C++中explicit的作用
1-> 指定构造函数或者转换函数为显式,它不能用于隐式转换和复制初始化;
2-> 避免构造函数的参数自动转换成类对象的标识符,vector构造函数有explicit,string构 造函数没有explicit;
3-> explicit关键字只能用在类内部的构造函数声明上;
4-> explicit关键字用作单个参数的构造函数;
5-> explicit关键字用来修饰类的构造函数,被修饰的构造函数的类,不能发生相应的隐式类型转换;
3:进程和线程的区别:进程是火车,线程是车厢
1-> 线程=车厢线程在进程下行进(单纯的车厢无法运行)
2-> 一个进程可以包含多个线程(一辆火车可以有多个车厢)
3-> 不同进程间数据很难共享(一辆火车上的乘客很难换到另外一辆火车,比如站点换乘)
4-> 同一进程下不同线程间数据很易共享(A车厢换到B车厢很容易)
5-> 进程要比线程消耗更多的计算机资源(采用多列火车相比多个车厢更耗资源)
6-> 进程间不会相互影响,一个线程挂掉将导致整个进程挂掉(一列火车不会影响到另外一列 火车,但是如果一列火车上中间的一节车厢着火了,将影响到所有车厢)
7-> 进程可以拓展到多机,进程最多适合多核(不同火车可以开在多个轨道上,同一火车的车 厢不能在行进的不同的轨道上)
8-> 进程使用的内存地址可以上锁,即一个线程使用某些共享内存时,其他线程必须等它结束 ,才能使用这一块内存。(比如火车上的洗手间)-"互斥锁"
9-> 进程使用的内存地址可以限定使用量(比如火车上的餐厅,最多只允许多少人进入,如果 满了需要在门口等,等有人出来了才能进去)
4:产生死锁的主要原因:
1-> 系统资源不足
2-> 进程运行推进的顺序不合适,
3-> 资源分配不当
5:产生死锁的必要条件:
1-> 互斥条件:一个资源每次只能被一个进程使用
2-> 请求与保持条件:一个进程因请求资源阻塞时,对已经获得的资源保持不放
3-> 不剥夺条件:进程已获得的资源,在未使用之前不能强行剥夺
4-> 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系
6:TCP与UDP的区别:
1-> TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建 立连接
2-> TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付
3-> TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;UDP是面向报文的UDP 没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如 IP电话,实时视频会议等)
4-> 每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信
5-> TCP首部开销20字节;UDP的首部开销小,只有8个字节
6-> TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道
7: const的用法
1-> 在定义的时候必须进行初始化
2-> 指针可以是const指针,也可以是指向const对象的指针
3-> 类的成员函数可以返回的是常成员变量,不能修改类的成员变量(mutable除外), 类的成员函数可以返回的是常对象,即被const声明的对象
4> 类的成员变量是常成员变量,必须在构造函数的列表初始化
5-> 修饰变量,说明该变量不可以被改变,定义为const的形参在函数内部是不能修改的
6-> 修饰指针,分为指向常量的指针(pointer to const)和自身是常量的指针(常量指针,const pointer);
7-> 修饰引用,指向常量的引用(reference to const),用于形参类型,即避免了拷贝,又避免了函数对值的修改;
8-> 修饰成员函数,说明该成员函数内不能修改成员变量
8:static的用法:
1-> 在函数体内,一个被声明为静态的变量在这一函数被调用过程中其值保持不变
2-> 在模块内但在函数体外,一个被声明为静态的变量可以被模块内所有的函数访问,但不能 被模块外其他函数访问,他是一个本地的全局变量
3-> 在模块内,一个被声明为静态的函数只可能被这一块内的其他函数调用。
4-> 类内的static成员变量属于整个类所拥有,不能再类内进行定义,只能在类的作用域内进行定义
5-> 类的static成员函数属于整个类拥有,不能包含this指针,只能调用static成员函数
6->修饰普通变量:修改变量的存储区域和生命周期,使得变量存储在静态区,在main函数运行前就分配了内存空间,如果有初始值就用初始值初始化,如果没有,就用默认的初始值初始化
7->修饰普通函数,表示函数的作用范围,仅仅在定义该函数的文件范围内可以使用,起到一个隐藏的作用
8->修饰成员变量,修饰成员变量使得所有的对象只保存一个该变量,而且不需要生成对象就可以访问该成员
9-> 修饰成员函数,修饰成员函数使得不需要生成对象就可以访问该函数,但是在static函数内不能访问非static成员。
9:指针和引用的区别
1-> 引用是直接访问,指针是间接访问,引用必须进行初始化
2-> 引用是变量的别名,本身不单独分配自己的内存空间,而指针有自己的内存空间
3-> 引用绑定内存空间(必须赋值处置),一个变量名不能更改绑定,可以改变对象的值
10: struct和class的区别
1-> struct成员关键字也可以实现类,struct成员访问级别为public,class的成员访问级别为 private
2->class默认为private继承,struct保留字定义的人具有public继承
11:C++中哪些不能是虚函数
1-> 构造函数,构造函数声明为虚函数时,那么由于对象未创建,还没有内存空间,没有虚函数表地址来调用虚函数即构造函数
2-> 内联函数在编译时被展开,虚函数在运行时才能动态绑定函数,特指多态
3-> 友员函数,因为不可以被继承
4-> 静态成员函数,只有一个实体,不能被继承,父子共同使用
12:内联函数与宏定义的区别:
1-> 内联函数必须是与函数体在一起才有效
2-> 在C++中,在类的内部定义了函数体的的函数,被默认为是内联函数,不管是不是有inline关键字。
3-> 内联函数在编译时展开,宏在预编译时展开
4-> 内联函数直接嵌入到目标代码,宏是做简单的文本替换
5-> 内联函数有类型检测,语法判断等功能,而宏没有
6-> inline函数是函数,而宏不是函数
13: inline函数可以为虚函数吗
1-> virtual函数可以为inline函数,不会造成语法错误
2-> 虚函数是运行才决定调用基类还是子类的对应函数,而inline则是在编译时决定展开与否,因此若是多态的虚函数,是不知道其会调用哪个函数,在运行时才会知道
14:宁可以pass-by-reference-to-const替换pass-by-value
1-> 但是该规则并不适合内置类型,以及STL的迭代器和函数对象,对他们而言,pass-by-value比较合适
15 :输入输出操作符重载的标准模式如下所示:
1-> std::ostream &operator<< (std::ostream& os, const ClassA& ca);。而且重载类操作符应该为非类成员函数
16 :C++异常处理涉及到三个关键字:try、catch、throw
1->try中的代码标示将被激活的特定异常,它后面通常会跟着一个或者多个catch块
2->catch在你想要处理问题的地方,通过异常处理捕获异常,catch关键字用于捕获异常
3-> 当问题出现时,程序会抛出一个异常,这是通过使用throw关键字来实现的
17 :smart pointer 也就是模板指针
1-> shared_ptr允许多个指针指向同一个对象,通常可以采用make_shared进行初始化 shared_ptr
2-> shared_ptr都有一个关键的计数器,当该shared_ptr初始化另一个shared_ptr,或者将他作为参数传递给一个函数,以及作为函数的返回值会增加。当给该
shared_ptr赋予一个新值或者被销毁,离开其局部作用域,计数器就会被递减
3-> 智能指针构造函数是explicit的,因此不能将一个内置指针隐式转换为智能指针,必须使用直接初始化形式 shared_ptr
4-> 不要混合使用智能指针和普通指针
18 : nothrow 如果将nothow传递给new,就是告诉它我们不能抛出异常 --> int * ptr =new (std::nothrow)int(1024)
19 : NULL nullptr 0的区别
1-> 在C语言中NULL被定义为:一个为void *指针,指向的地址为0 #define NULL ((void *)0) ,在C++中,NULL会被定义为0
2-> 在写C语言时,给指针变量赋值可以使用NULL。在使用C++语言时,可以使用0,使用空指针时,使用nullptr
20: 内存泄漏
1->忘记delete内存,容易造成内存泄漏
2->释放已经释放掉的对象
3->同一块内存释放2次,因此delete之后需要重置指针
21 :拷贝构造函数(深拷贝和浅拷贝)
1-> 拷贝构造函数的参数必须要使用引用类型,赋值运算符通常返回一个指向其左侧运算对象的引用
2-> 构造函数初始化对象的非static数据成员,析构函数释放对象使用的资源,并且析构非static数据成员
3-> 对于一个给定类,只会有唯一一个析构函数,与普通指针不同,智能指针成员在析构阶段会被自动销毁
4-> 浅拷贝,只是增加了一个指针指向已经存在的内存地址;如果原地址发生改变,那么浅拷贝的对象也会发生改变,问题在于析构的
时候回多次释放重复地址。
5-> 深拷贝,是增加了一个指针并且申请了一个新的内存,使这个增加的指针指向这个内存;
22: 什么时候会调用析构函数
1-> 变量在离开其作用域时会被销毁
2-> 当一个对象被销毁时,其成员被销毁
3-> 容器被销毁时,其元素被销毁
4-> 对于动态分配的对象,对它指向的指针应用delete运算符时被销毁
5-> 对于临时对象,当创建它的完整表达式结束时被销毁
23: default 和 delete 构造函数
1-> 可以对构造函数,拷贝构造函数,赋值重载函数,析构函数使用default。使用默认的合成函数
2-> 防止拷贝,防止赋值可以使用delete,但是析构函数不能使用这个delete函数
24: 四种显式风格转换
1-> static_cast,在进行上行转换时,把子类的指针或者引用转换成父类来表示,这种转换是安全的。但是把父类的指针或者引用转换为子类来表示,就是不安全的
2-> dynamic_cast,在进行上行转换时,与static_cast效果一样.在进行下行转化时,具有类型检查的功能,比static_cast更安全。
3-> reinpreter_cast 其必须有指针,编译时不用检查,type-id必须是一个指针、引用、算术类型、函数指针或者成员指针。它可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针(先把一个指针转换成一个整数,在把该整数转换成原类型的指针,还可以得到原先的指针值)。
4-> const_cast 将转换掉表达式的const性质,除了添加和删除const特性,使用const_cast符来执行其他任何类型的转换都会引起编译错误
25: 重载,覆盖,隐藏的区别
1-> 重载,是指在同一个类内(同一个范围内),函数名相同,函数参数不同,virtual关键字可有可无;
2-> 覆盖,是指在不同的类内(基类和子类),函数名相同,函数参数相同,且基类必须具有virtual关键字;
3-> 隐藏,是指在不同类内,函数名相同,函数参数相同则没有vitrual关键字,函数参数不同则virtual关键字可有可无;
26: C++和C的区别
1-> C++仍然以C为基础,有区块(blocks),语句(statements),预处理器(preprocessor),内置数据类型,数组,指针;许多时候C++的解法不过就是较高级别的C解法
2-> Object_Oriented C++ ,C with class(构造函数,析构函数)封装(encapsualtion),继承(inheritance),多态(polymorphism),virtual函数动态绑定,这一部分是面 对对象设计之古典守则在C++上直接实施
3-> template C++,C++的泛型编程部分
4-> STL库,STL是个template程序库,它对容器(container),迭代器(iterators),算法(algorithms)以及函数对象(function objects)的规约有极佳的紧密配合与协调。
27: TCP/IP 4层模型
1-> 链路层,包括用于协作IP数据在已有网络介质上的传输协议,定义向地址解析协议(arp)协议,提供TCP/IP协议的数据结构和实际物理硬件之间的接口;
2-> 网路层,本层包含IP协议,RIP协议,主要是负责数据的包装、寻址和路由,同时还包含网络间控制报文协议(ICMP)用来提供网络诊断信息;
3-> 传输层,它主要提供两种端到端的通信服务,其中TCP协议提供可靠的数据流运输服务,UDP协议提供不可靠的用户数据报服务;
4-> 应用层,因特网的应用层协议包括Finger,WHOIS,FTP(文本传输协议)、Gopher、HTTP(超文本传输协议),Telent(远程终端协议),SMTP(简单邮件传送协议),IRC(因特网中继会话),NNTP(网络新闻传输协议)
28:constexpr
1-> 怎么说呢,const修饰的是类型,constexpr修饰的是用来算出值的那段代码
2-> constexpr函数必须满足如下的限制,函数返回值不能是void类型,函数体不能声明变量或者定义新的类型,函数体只能包含声明、NULL语句或者一条return语句
代码举例:
(1)constexpr int get_five() {return 5;}
int some_value[get_five() + 7];
29 确定对象在使用前已经被初始化,确保每一个构造函数都将对象的每一个成员初始化
30: const 和static成员的相关初始化规定
1-> const static数据成员可以在类内初始化,也可以在类外初始化,不能在构造函数中初始化,也不能在构造函数中的初始化列表初始化。
2-> static数据成员只能在类外,即类的实现文件中初始化,也不能在构造函数中初始化,不能在构造函数中的初始化列表中初始化。
3-> const数据成员只能在构造函数的初始化列表
4-> 普通数据成员不能在类内初始化,可以在构造函数中初始化,也可以在构造函数的初始化列表中初始化。
31 说说static的作用有哪些
1-> 隐藏,当我们同时编译多个文件时,所有未加static的全局变量和函数都具有全局可见性,如果加了static就会对其他源文件隐藏
2-> static的第二个作用是保持变量内容的持久,存储在静态数据区的变量会在程序刚开始运行时就会完成初始化,也是唯一的一次初始化,和全局变量比起来,static变量就可以控制变量的可见范围
3-> static的第三个作用是默认初始化为0,也就是说static的主要功能是隐藏,其次因为static变量存放在静态存储区,所以具备持久性和默认值0
4-> 类的静态成员函数属于整个类而非类的对象,所以它没有this指针,这就导致了它仅能访问类的静态数据核静态成员函数
5-> 不能将static成员函数定义为虚函数
6-> static数据成员只能在类外,即类的实现文件中初始化,也不能在构造函数中初始化,不能在构造函数中的初始化列表中初始化。且前面不加static
7-> 为了防止父类的影响,可以在自定义一个与父类相同的静态变量,以屏蔽父类的影响。
32 再谈C++四种显示风格转换----static_cast
1-> static_cast
2-> 用于类层次中基类和子类之间的指针转换,进行上行转换(把子类指针或引用转换为基类指针或引)是安全的,在进行下行转换(把基类指针或者引用转换为子类的指针或者引用)由于没有动态类型检查,所以是不安全的
3-> 用于基本的数据类型之间的转换。比如说Int转换成为char,这种转换的安全性也需要开发人员来保证
4-> 把void类型转换为目标类型的指针(不安全)
5-> 任何类型的表达式转换为void类型,static_cast不能转换掉expression中的const.volitale属性
33 再谈C++四种显示风格转换----dynamic_cast
1->dynamic_cast < type-id > ( expression ),该运算符把expression类型转换为type_id类型的对象,type-id必须是类的指针、类的引用或者void *,type_id和expression类型相同
2-> dynamic_cast主要用于类层次间的上下行转换,还可以用于类之间的交叉转换,在进行上行转换时其作用和static_cast的效果是一样的,在进行上行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全
33 Smarter pointer 四大指针----auto->ptr
https://blog.csdn.net/K346K346/article/details/81478223?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog- BlogCommendFromMachineLearnPai2-1.nonecase
智能指针的作用是管理一个指针,智能指针就是一个类,当超出了类的作用域时,类会自动调用析构函数,析构函数会自动释放资源,所以智能指针的作用原理就是在函数结束时自动释放内存空间
将基本类型指针封装为类对象指针(这个对象肯定是个模板,以适应不同类型的基本需求)并在析构函数里编写delete语句删除指针指向的内存空间
所有智能指针类都有一个explicit构造函数,以指针作为参数,因此不能自动将指针转化为智能指针对象,必须显示调用
一般不用智能指针去指向非堆内存的地址
1-> auto_ptr(C++)C++ 98的方案,C++11已经抛弃,而且存在潜在的内存崩溃问题
2->智能指针auto->ptr 在被赋值操作时,被赋值的取得其所有权,去赋值的丢失其所有权
auto_ptr
{
auto_ptr
auto_ptr
auto_ptr
auto_ptr
auto_ptr
};
auto_ptr
pwin = films[2]; // films[2] loses ownership. 将所有权从films[2]转让给pwin,此时films[2]不再引用该字符串从而变成空指针
for(int i = 0; i < 5; ++i)
cout << *films[i] << endl;
3 auto->ptr不能够作为函数的返回值和函数的参数,也不能在容器中保存 auto->ptr
34: Smarter pointer 四大指针----shared->ptr
1->智能指针的构造函数都有explicit关键词修饰,所以不能隐式类型转换
2-> 尽量使用make_sahred和make_unique而不使用new
3-> shared_ptr是一个标准的共享所有权的智能指针,允许多个指针指向同一个对象。
4-> shared_ptr对象除了包括一个所拥有的对象的指针外,还必须包括一个引用计数代理对象的指针
5 ->引用计数,为了防止内存泄漏而产生的,每当增加一次对同一个对象的引用,那么引用对象的引用计数就会增加一次,每删除一次引用,引用计数就会减一,当一个对象的引用计数递减为0,就自动删除指向的堆内存。
6->shared_ptr使用引用计数,每一个shared_ptr的拷贝都指向相同的内存。每使用他一次,内部的引用计数加1,每析构一次,内部的引用计数减1,减为0时,删除所指向的堆内存。shared_ptr内部的引用计数是安全的,但是对象的读取需要加锁。
35: Smarter Pointer四大指针 unique_ptr
1->std::unique_ptr 是一种独占的智能指针,它禁止其他智能指针与其共享同一个对象,从而保证了代码的安全:
2-> 无法进行复制构造,无法进行复制赋值操作,既无法使用两个unique_ptr指向同一个对象,但是可以进行移动构造和移动赋值操作
36: Smarter Pointer四大指针weak_ptr
1-> weak_ptr是用来解决shared_ptr相互引用时的死锁问题,如果说两个shared_ptr互相引用,那么这两个指针的引用计数永远不会降为0,资源永远不会释放,它是对对象的一种弱引用,不会增加对象的引用计数,和shared_ptr之间可以互相转化。
2-> std::weak_ptr 被管理的对象存在非拥有性(弱引用),在访问所引用的对象指针前,必须先转换为shared_ptr.
3 ->更像是shared_ptr的一个助手
37 :智能指针存不存在内存泄漏,如果存在该如何解决?
1 ->当两个对象互相使用一个shaed_ptr成员变量指向对方,会造成循环引用,使引用计数失效,从而导致内存泄漏
2 -> 解决的话使用弱引用智能指针weak_ptr。
38: 回答一下析构函数需不需要为虚函数?为什么C++默认的析构函数不是虚函数
1-> 析构函数不一定必须是虚函数,是否为虚函数取决于该类的使用,一般为基类产生继承和多态时,才会是虚函数,单独使用时可以不是虚函数。
2-> 之所以在继承和多态时设计为虚函数是因为当new 派生类,并且用基类指针指向这一个派生类时,在销毁基类指针时只会调用基类的析构函数,不会调用派生类的析构函数,因为基类无法操作派生类中的非继承的成员,这样就造成派生类智能new 无法delete
3->默认不是析构函数是因为如果析构函数为虚函数的话,就需要编译器在类中增加虚函数表来实现虚函数机制,这样所需要的内存空间就更大了,因此没有必要默认为析构函数。
39 :讲讲函数的多态和类的多态吧
1-> 多态性是一个接口多种实现,函数的多态性(重载)是指一个函数被定义为多个不同参数的函数,它们一般不存在头文件中,当你调用这个函数,针对不同的参数,就会调用不同的同名函数
2-> 类的多态性用一句话概括是:在基类的函数前加上virtual关键字,然后声明基类的指针,利用该指针指向任意一个子类对象,调用相应的虚函数,可以根据指向的子类不同而调用不同的函数
40: TCP状态控制码
TCP状态控制码,占6个比特,含义如下
1-> URG :紧急比特,当URG = 1时,表明紧急指针字段有效,代表该封包为紧急封包,也就是说报文内有紧急数据,应当尽快传送
2-> ACK::确认比特,只有当ACK=1时,确认字段号才有效,代表这个封包为确认封包,当ACK=0时,确认号无效
3 ->PSH: PSH若为1时,代表要求对方立即传送缓冲区内其他对应的封包,而无需等缓冲满了才送
4-> RST复位比特,当RST=1时,表明tcp连接中出现严重差错,必须释放连接,然后再重新建立运输连接
5-> SYN 同步比特,SYN置为1时,就是表示这是一个连接请求或者连接接受报文,通常有SYN标志的包表示要主动连接到对方的意思
6-> FIN:终止比特,用来释放一个连接,当FIN=1时,表明此报文段的发送端数据已经发送完毕,并要求释放运输连接。
41 再来一次TCP和UDP的区别
1-> TCP是面向连接的,UDP是无连接的
2-> TCP提供可靠的服务,也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,而且按序到达,UDP尽最大努力交付,既不保证可靠交付。
3-> TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道。
4-> TCP面向字节流,可能出现黏包问题,实际上是TCP把数据看成一串无结构的字节流,UDP是面向报文的(不会出现黏包问题)
5-> UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应有很有用,如IP电话,实时视频会议)
6-> 每一条TCP连接只是点对点的,UDP支持一对一,一对多,多对一,多对多的交互通信
7-> TCP首部开销20字节,UDP首部开销小只有8字节。
42 SCTP协议
1-> SCTP是一种传输层协议,和UDP,TCP类似。
2-> SCTP是后来引入的一种新型协议,提供了和TCP一样可靠,有序的数据传输功能,同时却能和UDP一样面对消息的方式来进行操作,保护消息边界。
3-> SCTP可以在一个联合中支持多流机制,每个流(stream)是独立的
4->SCTP在设计时就充分考虑了TCP的不足。为防止攻击者发送伪装的SCTP数据包到现有的连接中, SCTP的两端都使用一个称为“认证标记”的32bit数据来确保数据包真正属于现有的连接
43 :TCP三次握手建立连接
1-> 客户端发送SYN到服务端,说明客户端请求建立连接
2-> 服务端收到客户端的SYN,并回复SYN + ACK到客户端,表示同意建立连接
3-> 客户端收到服务端的SYN + ACK后,回复ACK给服务端(表示客户端收到了服务端发的同意报文)
4-> 服务端收到客户端的ACK后,连接就已经建立,可以进行数据传输
44 :TCP为什么要进行三次握手
1->因为信道不可靠,而TCP如果想在不可靠的信道上建立可靠的传输,那么三次通信是理论上的最小值
2-> 因为双方都需要确认对方收到了自己的序列号,确认过程最少需要进行三次通信
3-> 为了防止已经失效的连接请求报文突然又传送到了服务端,因而产生了错误
45:TCP四次挥手
1-> 客户端发送FIN给服务端,说明客户端不必发送数据给服务器了(请求释放出客户端)
2-> 服务器收到客户端发的FIN,并回复ACK给客户端(统一释放从客户端到服务端的连接)
3-> 客户端收到服务端回复的ACK,此时从客户端到服务端的连接已经释放(但服务端 到客户端的连接没有释放,客户还可以接收数据)
4 -> 服务端继续发送之前没有发送完的数据
5-> 服务端发送FIN 给客户端,表示服务端发送完了数据(请求释放从服务端到客户端的连接,就算没收到客户端的回复,过一段时间也会自动释放)
6-> 客户端收到服务端的FIN,回复ACK给客户端(同意释放从服务端到客户端的连接)
7-> 服务端收到了客户端的ACK后,释放从服务端到客户端的连接。
46 :TCP为什么要进行四次挥手
1-> 因为TCP是全双工模式,客户端请求关闭连接后,客户端向服务端的连接关闭后(一,二次挥手),服务端继续传输之前没传完的数据到客户端,服务端向客户端的连接关闭三,四次挥手),所以TCP释放连接时服务器的ACK和FIN是分开发的(中间隔着数据传输),而TCP建立连接时服务器的ACK和SYN是一起发送的,所以TCP建立连接需要3次,而释放连接则需要4次.
2->客户端请求释放时,服务器可能还有数据需要传输给客户端,因此服务器需要响应客户端FIN请求(服务端发送ACK),然后进行数据传输,传输完成后,服务端在提出FIN请求(服务端发送SN)而连接时则没有数据传输,因此SYN和ACK可以一起发送。
47 : 为什么客户端释放最后需要TIME_WAIT等待2MS呢
1-> 为了保证客户端发送的最后一个ACK报文能够到达服务端,若未成功到达,则服务端超时重传FIN + ACK报文,并重新计时
2-> 防止已失效的连接请求报文出现在本链接中。持续2MS可使本连接持续的时间内所产生的所有报文网段都从网络中消失,下次连接中不会出现旧的报文段。
48 :TCP拥塞控制
TCP拥塞控制由4个核心算法组成:
1->慢启动算法:TCP源端一开始不知道网络资源当前状况,因此新建立的TCP连接不能一开始就发送大量数据,而只能逐步增加每次发送的数据量
2->拥塞避免:算法让拥塞窗口缓慢增长,即每经过一个往返时间RTT就把发送方的拥塞窗口CWND加1,而不是加倍,这样拥塞窗口按线性规律缓慢增长
3->快重传和快恢复:接收方在收到一个乱序的报文后就立即发出重复确认,快重传算法规定,发送方只要一连收到三个重复确认就应当立即重传对方尚未收到的报文段,而不必继续等待设置的重传计时器时间到期
49: C/C++中sizeof(),strlen()的区别
1-> sizeof是一个操作符,而strlen是一个库函数
2-> sizeof的参数可以是数据的类型,也可以是变量,而strlen只能以结尾为‘\0’的字符串作为参数,也就是只能用char *作为参数
3-> 编译器在编译时计算出sizeof的结果,而strlen必须在运行时才能计算出来
4-> sizeof计算数据类型占内存的大小,strlen计算字符串实际长度
50: 栈和队列
1-> 栈是限定仅在表尾进行插入和删除操作的线性表,我们把允许插入和删除的一端称为栈顶,另一端称为栈底,不包含任何数据元素的栈称为空栈
2->栈的特殊之处在于限定了这个线性表的插入和删除位置,它始终只在栈顶进行,这也就使得栈底是固定的,最先进栈的只能在栈底
3-> 队列与栈不同,他是一种FIFO,先进先出的结构
queue 和 stack 有一些成员函数相似,但在一些情况下,工作方式有些不同:
front():返回 queue 中第一个元素的引用。如果 queue 是常量,就返回一个常引用;如果 queue 为空,返回值是未定义的。
back():返回 queue 中最后一个元素的引用。如果 queue 是常量,就返回一个常引用;如果 queue 为空,返回值是未定义的。
push(const T& obj):在 queue 的尾部添加一个元素的副本。这是通过调用底层容器的成员函数 push_back() 来完成的。
push(T&& obj):以移动的方式在 queue 的尾部添加元素。这是通过调用底层容器的具有右值引用参数的成员函数 push_back() 来完成的。
pop():删除 queue 中的第一个元素。
size():返回 queue 中元素的个数。
empty():如果 queue 中没有元素的话,返回 true。
emplace():用传给 emplace() 的参数调用 T 的构造函数,在 queue 的尾部生成对象。
swap(queue
51 :volatile
1-> volatile关键字是一种类型修饰符,它声明的类型变量可以不可以被某些编译器未知的因素更改,所以volatile告诉编译器不应该对这样的对象进行优化。
2-> vloatile关键字声明的变量,每次访问时都必须从内存中取出值,没有被volatile修饰的变量,可能由于编译器的优化,从CPU寄存器中取值
3-> const可以是volatile
4-> 指针可以是volatile变量
52 :assert()
1-> 断言是宏,而不是函数,如果它的条件返回错误,则终止程序运行
2-> 可以通过NDEBUG来关闭assert
53: union联合
1-> union是一种节省空间的特殊的类,一个uninon可以有多个数据成员,但是任意时刻只有一个数据成员可以有值,当某个成员被赋值后,其他成员定义为未定义状态;
2-> 默认访问控制符为public,可以有构造函数和析构函数
3-> 不能含有引用类型的成员
4-> 不能继承自其他类,不能作为基类,不能含有虚函数
54: this指针
1-> this指针是一个隐含与每一个非static成员函数的特殊指针,它指向调用该成员函数的对象
2-> 当一个成员函数被调用时,自动向它传递一个隐含的参数,该参数是一个指向这个成员函数所在对象的指针
3-> 当对一个对象调用成员函数时,编译程序现将对象的地址赋值给this指针,然后调用成员函数,每次成员函数存取数据成员时,都隐式使用this指针
55 :虚函数和纯虚函数的区别
1-> 类里面如果声明了虚函数,这个函数是实现的,哪怕是空实现,它的作用就是为了能让这个函数可以在它的子类里被覆盖,这样编译器就可以使用后期绑定来实现多态。纯虚函数只是一个接口,是个函数的声明而已,他要到子类里去实现。
2-> 虚函数在子类里可以不重写,但纯虚函数必须在子类才可以实例化子类
3-> 带纯虚函数的类叫做抽象类,这种类不能直接生成对象,而只有被继承,并重写虚函数后,才能使用,抽象类被继承后,子类可以继续是抽象类,也可以是普通类。
56 :虚函数表
1-> 拥有虚函数的类才有虚函数表
2-> 虚函数表属于类,然后类的所有对象通过虚函数表指针共享类的虚函数表
3-> 虚函数表的作用:当使用父类指针来操作子类对象时,虚函数表像一个地图一样,指明了实际该调用的函数
4-> C++编译器保证虚函数表的指针存在于对象实例中的最前面的位置,这意味着我们可以通过对象实例的地址得到虚函数表,然后可以遍历其中的虚函数指针,并且调用相应的虚函数。
5-> 虚函数表详解:https://zhuanlan.zhihu.com/p/75172640
57:std::move
1-> std::move函数可以非常简单的方式将左值引用转换为右值引用,通过std::move可以避免不必要的拷贝操作
2-> std::move是为性能而生,是将对象的状态或者所有权从一个对象转移到另外一个对象,只是转移,没有内存的搬迁或者拷贝
58:进程间的通信有哪些,各有什么优缺点:
1-> 管道:管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程之间进行使用。具有亲缘的关系通常是指父子进程关系
2-> 有名管道FIFO:有名管道也是半双工的通信方式,但是允许在没有亲缘关系中的进程间使用,有名管道是先进先出的通信方式
3-> 信号量:信号量是一个计数器,可以用来控制多个进程对共享资源的访问,作为一个锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源,因此主要作为进程间以及同一进程内不线程之间的同步手段
4-> 消息队列:消息队列是有消息的链表,存放在内核中并由消息队列标识符来确定。消息队列克服了信号传递信息少,管道只能承载无格式字节流以及缓冲区大小受限等特点。
5-> 信号signal:信号是一种比较复杂的通信方式,用于通知接受进程某个事件已经发生
6-> 共享内存:共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但很多进程都将可以访问,共享内存是最快的IPC方式,它是针对其他进程间通信方式运行效率低而专门设计的,它往往与其他通信机制,如信号量配合使用,来实现进程间的同步
7-> 套接字socket:套接字也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同机器间的进程通信
59:socket包含哪几样东西
1-> IP地址:也就是某台主机的逻辑地址,按照TCP/ip协议分配给本地主机的网络地址,两个进程要通讯,任意进程首先要知道通讯对方的位置,即对方的IP地址
2-> 端口号:用来辨别本地通讯进程,一个本地的进程在通讯时俊辉占用一个端口号,不同的进程端口号不同,因此在通讯前必须要分配一个没有访问的端口号;
3-> 连接:指两个进程间的通讯链路
4-> 半相关:网络中用一个三元组可以在全局唯一标志一个进程(协议,本地地址,端口号)
5-> 全相关:一个完整的网间进程通信需要由两个进程组成,并且只能使用同一种高层协议,也就是说完整的网间通信需要一个五元组来标识(协议,本地地址,本地端口号,远地地址,远地端口号)
60:socket相关的函数
1-> 创建套接字,int socket(int domain,int type,int protocol),该函数用于打开一个网络通讯接口,出错则返回-1,成功返回一个socket文件描述符,应用进程就可以像读写文件一样调用
read/write在网络上收发数据
2-> 绑定 int bind(int sockfd,const struct sockaddr*addr,socklen_t addrlen);将参数sockfd和addr绑定在一起,是sockfd这个用于网络通讯的文件描述符监听addr所描述的地址和端口号
3-> 监听 int listen(int sockfd,int backlog);该函数仅被服务端使用,listen声明sockfd处于监听状态,并且最多允许有backlog个客户端处于连接等待状态,如果收到更多的连接请求就忽略。listen成功返回0,失败返回-1
4->接收连接 int accept(int sockfd,struct sockaddr* addr,socklen_t* addrlen):当有客户端发起连接时,服务器就调用accept返回并接受这个连接;
5-> 请求连接:这个函数只需要客户端程序来调用,调用该函数后表明连接服务器,这里的参数是对方的地址
61: socket的使用中服务端和客户端的流程
服务器端工作流程:
1-> 使用WSAStartup()函数检查系统协议栈安装情况
2-> 使用socket()函数创建服务器端通信套接口
3-> 使用bind()函数将创建的套接口与服务器地址绑定
4-> 使用listen()函数使服务器套接口做好接收连接请求准备
5-> 使用accept()接收来自客户端由connect()函数发出的连接请求
6-> 根据连接请求建立链接后,使用send()还念书发送数据,或者使用recv()函数接收数据
7-> 使用closesocket()函数关闭套接口(可以先用shutdown()函数吸纳关闭读写通道)
8-> 最后调用WSACleanup()函数结束Winsock Sockets API
客户端工作流程:
1-> 使用WSAStartup()函数检查系统协议栈安装情况
2-> 用socket()函数创建客户端套接口
3-> 使用connect()函数发出与服务器建立连接的请求(调用前可以不用bind()端口号,由系统自动完成)
4-> 连接建立后使用send()函数发送数据,或使用recv()函数接收数据
5-> 使用closesocket()函数关闭套接口
6->最后调用WSACleanup()函数,结束Winsock Sockets API
62:HTTP与HTTPS的区别
1-> HTTP的URL以http://开头,而HTTPS的URL以https://开头
2-> HTTP是不安全的,HTTPS是安全的
3-> HTTP标准端口号是80,而HTTPS的标准端口是443
4-> 在OSI网络模型中,HTTP工作于应用层,而HTTPSd的安全传输机制工作在传输层
5-> HTTP无法加密,而HTTPS对传输的数据进行加密
6-> HTTP无需证书,而HTTPS需要CA机构wosign的颁发SSL证书
63:简述HTTP请求的7个步骤
1-> 建立TCP连接:在HTTP工作开始之前,Web浏览器首先要通过网络与Web服务器建立连接,该连接是通过TCP来完成的,该协议与IP协议共同构建 Internet,即著名的TCP/IP协议族,因此Internet又被称作是TCP/IP网络。HTTP是比TCP更高层次的应用层协议,根据规则, 只有低层协议建立之后才能,才能进行更层协议的连接,因此,首先要建立TCP连接,一般TCP连接的端口号是80。
2-> web浏览器发送请求命令,一旦建立了TCP连接,web浏览器就会向web服务器发送请求命令
3-> web浏览器发送请求头信息,浏览器发送请求命令之后,还要以头的形式向web服务器发送一些别的信息,之后浏览器发送了一空白行来通知服务器,它已经结束了该头信息的发送
4-> web服务器应答:客户机向服务器发出请求后,服务器会向客户机回送应答,HTTP/1.1 200 OK,应答的第一部分是一协议的版本号和应答状态码
5-> web服务器发送应答头:正如客户端会随同请求发送关于自身的信息一样,服务器也会随同应答向用户发送关于它自己的数据及被请求的文档。
6-> web服务器向浏览器发送数据:Web服务器向浏览器发送头信息后,它会发送一个空白行来表示头信息的发送到此为结束,接着,它就以Content-Type应答头信息所描述的格式发送用户所请求的实际数据。
7->web服务器关闭TCP连接:一般情况下,一旦Web服务器向浏览器发送了请求数据,它就要关闭TCP连接,然后如果浏览器或者服务器在其头信息加入了这行代码
64:gdb常用命令
1-> gdb + 可执行文件名:启动gdb调试
2-> thread apply all bt: 查看所有线程调用栈,thread x进入所需要的线程
3-> start:开始执行程序,停在main函数第一句语句前面等待命令
4-> step/s:执行下一行语句,如果有函数调用则进入到函数中
5-> r: 重头开始运行到断点
6-> c: 继续运行直到下一个断点
7-> p/x/d + 变量:以十六进制,十进制打印变量
8-> finish:连续运行到当前函数返回为止,然后停下来等待命令
9-> info/locals:查看当前栈帧局部变量的值
10-> list/l :列出源代码,接着上次的位置往下列,每次列100行
11-> list + 行号:列出从第几行开始的源代码
12-> next/n: 执行下一行语句
13-> print/p:打印表达式的值,通过表达式可以修改变量的值或者调用函数
14-> quit/q:退出gdb调试环境
15-> set var:修改变量的值
16-> attach pid:跟踪并挂起某个已经起来的进程
17-> call + 函数名/参数:手动调用对应函数,可以用来检查函数功能
18-> b + main.c:11:给main.c文件的11行打断点
19-> i d: 显示所有断点信息
20-> d + 对应断点:删除对应断点
21-> info local:查看局部变量
22-> until:结束当前循环
23-> signal:将一个信号发给正在运行的函数
24->backtrace:查看各级函数调用栈及参数
25->frame或f + 帧编号:选择栈帧
26->up/down:上移/下移栈帧,使得其他函数变成当前的函数
27->watch:监控一个变量当该变量改变时停止程序
28->jump: 程序跳到指定位置
29->register:查看寄存器
30->x + addr: 查看指定内存
65 :linux下动态库 .so和静态库.a的区别
1-> 两者的不同点在于代码被载入的时刻不同
2->静态库的代码在编译过程中已经被载入可执行程序,因此体积比较大,而且程序运行时不在需要该静态库
3-> 动态库(共享库)的代码在可执行程序运行时才载入内存,在编译过程中仅简单的引用,因此代码体积比较小,在程序运行时还需要运行
66: map中以class作为类的key需要怎么做
1-> map内部存储机制实际是以红黑树为基础,红黑树在插入节点时,必须依照大小比对之后在一个合适的位置上执行插入动作。所以作为关键字,起码必须有“<”这个比较操作符。我们知道,int,float,enum,size_t等等简单关键字,都有内置的比较函数,与map搭配无论是插入还是查找,都没什么问题。但是作为复杂数据类型,如果没有明确定义“<”比较操作符,就不能与map直接搭配使用,除非我们自己定义第三个参数。
67:聊一下HTTP的状态码有哪些
1->2XX 成功
200 OK,表示从客户端发来的请求在服务器端被正确处理 ✨
201 Created 请求已经被实现,而且有一个新的资源已经依据请求的需要而建立
202 Accepted 请求已接受,但是还没执行,不保证完成请求
204 No content,表示请求成功,但响应报文不含实体的主体部分
206 Partial Content,进行范围请求 ✨
2->3XX 重定向
301 moved permanently,永久性重定向,表示资源已被分配了新的 URL
302 found,临时性重定向,表示资源临时被分配了新的 URL ✨
303 see other,表示资源存在着另一个 URL,应使用 GET 方法定向获取资源
304 not modified,表示服务器允许访问资源,但因发生请求未满足条件的情况
307 temporary redirect,临时重定向,和302含义相同
4XX 客户端错误
400 bad request,请求报文存在语法错误 ✨
401 unauthorized,表示发送的请求需要有通过 HTTP 认证的认证信息 ✨
403 forbidden,表示对请求资源的访问被服务器拒绝 ✨
404 not found,表示在服务器上没有找到请求的资源 ✨
408 Request timeout, 客户端请求超时
409 Confict, 请求的资源可能引起冲突
5XX 服务器错误
500 internal sever error,表示服务器端在执行请求时发生了错误 ✨
501 Not Implemented 请求超出服务器能力范围,例如服务器不支持当前请求所需要的某个功能,或者请求是服务器不支持的某个方法
503 service unavailable,表明服务器暂时处于超负载或正在停机维护,无法处理请求
505 http version not supported 服务器不支持,或者拒绝支持在请求中使用的 HTTP 版本
68 说说为什么有了HTTP还要有HTTPS
1-> https是安全版的http,因为http协议的数据都是明文进行传输的,所以对于一些敏感信息的传输就很不安全,HTTPS就是为了解决HTTP的安全而生的。
69 为什么会发生TCP黏包、拆包?
1-> 要发送的数据大于TCP发送缓冲剩余空间的大小,将会发生拆包;
2->待发送的数据大于最大报文长度,将会发生拆包;
3->要发送的数据小于TCP发送缓冲区的大小,但TCP讲多次写入缓冲区的数据一次性发送出去,将会发送粘包;
4-> 接收数据端的应用层没有及时读取缓存区中的数据,将发生黏包;
70 黏包拆包的解决方法?
1-> 消息定长:发送端将每个数据包装为固定长度(不够的可以通过填0补充),这样接收端每次接收缓冲区中读取固定的长度的数据就自然而然的可以把每个数据包拆分出来;
2-> 设置消息边界:服务端从网络流中按照消息边界划分出消息内容,比如说像FTP协议一样,在包尾增加回车换行符进行分割;
3-> 将消息分为消息头和消息体:消息头中包含表示消息总长度(或者消息体长度)的字段;
71:什么是TCP流量控制:
1-> 流量控制是为了控制发送方发送速率,保证接收方来得及接收;
2-> 接收方发送的确认报文中的窗口字段可以用来控制发送方窗口大小,从而影响发送方的发送速率,将窗口值设为0,则发送方不能发送数据。
72: 什么是野指针?怎么产生的,怎么避免?
1-> 野指针就是指指向的位置是随机的,不可知的,没有明确限制的,与空指针是不同的。比如指针变量在定义时未初始化,其值是随机的,指针变量的值是别的变量地址,意味着指针指向了一个地址是不确定的变量。此时去解引用就是去访问了一个不确定的地址,所以结果是不可知的;
2 -> 指向不可访问的地址,比如内核空间,指向了一个可用的空间,但这个空间的程序正在被使用,指向一个可用但是没有特别意义的空间。
3-> 避免:在定义指针时初始化为NULL,在指针解引用之前先判断这个指针是不是NULL,在指针使用完之后将指针赋值为NULL,在指针使用之前将其赋值为一个可用的内存空间。
73:C++中map 和 set的使用及区别
1-> set是一种关联式容器,其以RBtree作为底层容器
2-> set所得元素只有key没有value,value就是key, set不允许出现键值重复
3-> 所有元素都会被自动排序, 不能通过迭代器来改变set的值,因为set的值就是键
4-> map和set一样时关联式容器。它们的底层都是红黑树,所有元素都是键 + 值存在的,所有的元素是通过键进行自动排序的,map的键是不能修改的,但是键对应的值是能修改的。
74:C++如何阻止一个类被实例化
1-> 将类定位抽象基类(就是类里面定义了纯虚函数的类)或者将构造函数声明为private
2-> 不允许类外部创建类对象,只能在类内部创建对象
75: 在浏览器输入一个网址后的流程
1->解析域名的IP地址(在浏览器缓存或hosts或DNS服务器查找)
2->发起连接请求,TCP三次握手
3->发送HTTP请求信息
4->接受服务器返回的数据并渲染到页面
5->断开TCP连接,四次挥手
https://blog.csdn.net/weixin_30376083/article/details/95320106
76: get和post的方法区别
1->GET在浏览器回退时是无害的,而POST会再次提交请求。
2->GET产生的URL地址可以被Bookmark,而POST不可以。
3->GET请求会被浏览器主动cache,而POST不会,除非手动设置。
4->GET请求只能进行url编码,而POST支持多种编码方式。
5->GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。
6->GET请求在URL中传送的参数是有长度限制的,而POST么有。
7->对参数的数据类型,GET只接受ASCII字符,而POST没有限制。
8->GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。
9->GET参数通过URL传递,POST放在Request body中。
https://blog.nowcoder.net/n/91a9334cbabf4c24893aef3f96e51303
https://zhuanlan.zhihu.com/p/110546080
77 数据库的四大特性
1->原子性, 是指事务包含的所有操作要么全部成功,要么全部失败回滚,因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响。
2->一致性, 一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。拿转账来说,假设用户A和用户B两者的钱加起来一共是5000,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是5000,这就是事务的一致性。
3->隔离性, 隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。即要达到这么一种效果:对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始,这样每个事务都感觉不到有其他事务在并发地执行。
4->持久性, 持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。
78 微信红包功能怎么测试
1->功能
在红包钱数,和红包个数的输入框中只能输入数字
红包里最多和最少可以输入的钱数 200 0.01
拼手气红包最多可以发多少个红包 100、超过最大拼手气红包的个数是否有提醒
当红包钱数超过最大范围是不是有对应的提示
当发送的红包个数超过最大范围是不是有提示
当余额不足时,红包发送失败
在红包描述里是否可以输入汉字,英文,符号,表情,纯数字,汉字英语符号,是否可以输入它们的混合搭配
输入红包钱数是不是只能输入数字
红包描述里许多能有多少个字符 10个
红包描述,金额,红包个数框里是否支持复制粘贴操作
红包描述里的表情可以删除
发送的红包别人是否可以领取、发的红包自己可不可以领取 2人
24小时内没有领取的红包是否可以退回到原来的账户、超过24小时没有领取的红包,是否还可以领取
用户是否可以多次抢一个红包
发红包的人是否还可以抢红包 多人
红包的金额里的小数位数是否有限制
可以按返回键,取消发红包
断网时,无法抢红包
可不可以自己选择支付方式
余额不足时,会不会自动匹配支付方式
在发红包界面能否看到以前的收发红包的记录
红包记录里的信息与实际收发红包记录是否匹配
支付时可以密码支付也可以指纹支付
如果直接输入小数点,那么小数点之前应该有个0
支付成功后,退回聊天界面
发红包金额和收到的红包金额应该匹配
是否可以连续多次发红包
输入钱数为0,"塞钱进红包"置灰
2->性能
弱网时抢红包,发红包时间
不同网速时抢红包,发红包的时间
发红包和收红包成功后的跳转时间
收发红包的耗电量
退款到账的时间
3-> 兼容
苹果,安卓是否都可以发送红包
电脑端可以抢微信红包
4 界面
发红包界面没有错别字
抢完红包界面没有错别字
发红包和收红包界面排版合理,
发红包和收到红包界面颜色搭配合理
5-> 安全
对方微信号异地登录,是否会有提醒 2人
红包被领取以后,发送红包人的金额会减少,收红包金额会增加
发送红包失败,余额和银行卡里的钱数不会少
红包发送成功,是否会收到微信支付的通知
6-> 易用性(有点重复)
红包描述,可以通过语音输入
可以指纹支付也可以密码支付
79 ARP地址解析协议工作原理:
1->首先,每个主机都会在自己的ARP缓冲区中建立一个ARP列表,以表示IP地址和MAC地址之间的对应关系。
2->当源主机要发送数据时,首先检查ARP列表中是否有对应IP地址的目的主机的MAC地址,如果有,则直接发送数据,如果没有,就向本网段的所有主机发送ARP数据包,该数据包包括的内容有:源主机 IP地址,源主机MAC地址,目的主机的IP 地址。
3->当本网络的所有主机收到该ARP数据包时,首先检查数据包中的IP地址是否是自己的IP地址,如果不是,则忽略该数据包,如果是,则首先从数据包中取出源主机的IP和MAC地址写入到ARP列表中,如果已经存在,则覆盖,然后将自己的MAC地址写入ARP响应包中,告诉源主机自己是它想要找的MAC地址。
4->源主机收到ARP响应包后。将目的主机的IP和MAC地址写入ARP列表,并利用此信息发送数据。如果源主机一直没有收到ARP响应数据包,表示ARP查询失败。
广播发送ARP请求,单播发送ARP响应
80 为什么要使用ARP协议
1-> OSI模型把网络工作分为七层,彼此不直接打交道,只通过接口(layer interface)。IP地址工作在第三层,MAC地址工作在第二层。当协议在发送数据包时,需要先封装第三层IP地址,第二层MAC地址的报头,但协议只知道目的节点的IP地址,不知道目的节点的MAC地址,又不能跨第二、三层,所以得用ARP协议服务,来帮助获取到目的节点的MAC地址。
ARP协议是第几层协议 ,在网络层
81 ARP在生成环境产生的问题及解决办法:
1->ARP病毒,ARP欺骗。
2>高可用服务器对之间切换时要考虑ARP缓存的问题。
3->路由器等设备无缝迁移时要考虑ARP缓存的问题,例如:更换办公室的路由器。
82 linux查看文件前几行和后几行的命令
1 -> 查看/etc/profile的前10行内容,应该是:# head -n 10 /etc/profile
查看/etc/profile的最后5行内容,应该是:# tail -n 5 /etc/profile,带数字表示从打几行,带+号表示从第几行开始
2 -> 从第3000行开始,显示1000行。即显示3000~3999行
cat filename | tail -n +3000 | head -n 1000
3-> 显示1000行到3000行
cat filename | head -n 3000 | tail -n +1000
4->,使用sed命令,sed -n '5, 10p' filename
83 having 和 where的区别
1-> having是在分组后对数据进行过滤
2-> where是在分组前对数据进行过滤
3-> having后面可以使用聚合函数
4-> where后面不可以使用聚合
5-> 在查询过程中执行顺序:from>where>group(含聚合)>having>order>select。
6->聚合语句(sum,min,max,avg,count)要比having子句优先执行,所有having后面可以使用聚合函数。而where子句在查询过程中执行优先级别优先于聚合语句(sum,min,max,avg,count),所有where条件中不能使用聚合函数。
84 数组和链表的区别(转https://www.jianshu.com/p/5233f2a2d523)
数组和链表是两种基本的数据结构,他们在内存存储上的表现不一样,所以也有各自的特点。
大致总结一下特点和区别,拿几个人一起去看电影时坐座位为例。
1-> 数组的特点
在内存中,数组是一块连续的区域。 拿上面的看电影来说,这几个人在电影院必须坐在一起。
数组需要预留空间,在使用前要先申请占内存的大小,可能会浪费内存空间。 比如看电影时,为了保证10个人能坐在一起,必须提前订好10个连续的位置。这样的好处就是能保证10个人可以在一起。但是这样的缺点是,如果来的人不够10个,那么剩下的位置就浪费了。如果临时有多来了个人,那么10个就不够用了,这时可能需要将第11个位置上的人挪走,或者是他们11个人重新去找一个11连坐的位置,效率都很低。如果没有找到符合要求的作为,那么就没法坐了。
插入数据和删除数据效率低,插入数据时,这个位置后面的数据在内存中都要向后移。删除数据时,这个数据后面的数据都要往前移动。 比如原来去了5个人,然后后来又去了一个人要坐在第三个位置上,那么第三个到第五个都要往后移动一个位子,将第三个位置留给新来的人。 当这个人走了的时候,因为他们要连在一起的,所以他后面几个人要往前移动一个位置,把这个空位补上。
随机读取效率很高。因为数组是连续的,知道每一个数据的内存地址,可以直接找到给地址的数据。
并且不利于扩展,数组定义的空间不够时要重新定义数组。
2->链表的特点
在内存中可以存在任何地方,不要求连续。 在电影院几个人可以随便坐。
每一个数据都保存了下一个数据的内存地址,通过这个地址找到下一个数据。 第一个人知道第二个人的座位号,第二个人知道第三个人的座位号……
增加数据和删除数据很容易。 再来个人可以随便坐,比如来了个人要做到第三个位置,那他只需要把自己的位置告诉第二个人,然后问第二个人拿到原来第三个人的位置就行了。其他人都不用动。
查找数据时效率低,因为不具有随机访问性,所以访问某个位置的数据都要从第一个数据开始访问,然后根据第一个数据保存的下一个数据的地址找到第二个数据,以此类推。 要找到第三个人,必须从第一个人开始问起。
不指定大小,扩展方便。链表大小不用定义,数据随意增删。
3-> 各自的优缺点
数组的优点: 随机访问性强,查找速度快,
数组的缺点: 插入和删除效率低, 可能浪费内存, 内存空间要求高,必须有足够的连续内存空间。
数组大小固定,不能动态拓展
链表的优点: 插入删除速度快, 内存利用率高,不会浪费内存 ,大小没有固定,拓展很灵活。
链表的缺点 :不能随机查找,必须从第一个开始遍历,查找效率低
-数组 链表
读取O(1)O(n)
插入O(n)O(1)
删除O(n)O(1)
83 网页突然变慢怎么搞
1->top、iostat查看cpu、内存及io占用情况
2-> 内核、程序参数设置不合理:查看有没有报内核错误,连接数用户打开文件数这些有没有达到上限等等
3-> 链路本身慢:是否跨运营商、用户上下行带宽不够、dns解析慢、服务器内网广播风暴什么的
4-> 程序设计不合理:是否程序本身算法设计太差,数据库语句太过复杂或者刚上线了什么功能引起的
5-> 其它关联的程序引起的:如果要访问数据库,检查一下是否数据库访问慢
6-> 是否被攻击了:查看服务器是否被DDos了等等
7-> 硬件故障 这个一般直接服务器就挂了,而不是访问慢
84 DNS解析域名地址流程
1-> 发起基于域名的请求后,首先检查本地缓存(浏览器缓存-->操作系统的hosts文件)
2-> 如果本地缓存中有,直接返回目标IP地址,否则将域名解析请求发送给本地DNS服务器
3-> 如果本地DNS服务器中有,直接返回目标IP地址,到这一步基本能解析80%的域名。如果没有,本地DNS服务器将解析请求发送给根DNS服务器
4-> 根DNS服务器会返回给本地DNS服务器一个所查询的TLD服务器地址列表
5 -> 本地DNS服务器再向上一步返回的TLD服务器发送请求,TLD服务器查询并返回域名对应的权威域名服务器的地址
6-> 本地DNS服务器再向上一步返回的权威域名服务器发送请求,权威域名服务器会查询存储的域名和IP的映射关系表,将IP连同一个TTL(过期时间)值返回给本地DNS服务器
7-> 本地DNS服务器会将IP和主机名的映射保存起来,保存时间由TTL来控制
8-> 本地DNS服务器把解析的结果返回给用户,用户根据TTL值缓存在本地系统缓存中,域名解析过程结束
85 啥是无效链接
1 死链接(Dead Links)指的是无效链接,也就是那些不可到达的链接。通俗地理解是以前可以通过点击这个链接到达网站页面,后续可能由于网站迁移、改版或操作不当等原因,使得链接指向的目标页面不存在而无法访问所遗留的链接,即称为死链接。
访问死链接时,一般会出现“抱歉,您所访问的页面不存在”的提示信息或者 404 状态页面。
86 HTTP劫持,DNS劫持 (转自https://www.jianshu.com/p/1e3c98275cb3)
1-> HTTP 劫持的原理就是在服务器和用户之间的信息传输之中添油加醋,这是由于信息没有被加密而造成的。用户请求了网站服务器,服务器返还网页给用户,在传输过程中就给了他人加料的机会。就算DNS服务器可靠,也无法防止HTTP劫持。
2->一般来说HTTP劫持主要通过下面几个步骤来做:标识HTTP连接。在天上飞的很多连接中,有许多种协议,第一步做的就是在TCP连接中,找出应用层采用了HTTP协议的连接,进行标识;篡改HTTP响应体,可以通过网关来获取数据包进行内容的篡改;抢先回包,将篡改后的数据包抢先正常站点返回的数据包先到达用户侧,这样后面正常的数据包在到达之后会被直接丢弃。
3-> DNS劫持:在DNS服务器中,将www.xxx.com的域名对应的IP地址进行了变化。解析出来的域名对应的IP,在劫持前后不一样;HTTP劫持:DNS解析的域名的IP地址不变。在和网站交互过程中的劫持了你的请求。在网站发给你信息前就给你返回了请求。
4-> HTTPS不仅可以防止HTTP劫持,也能够较好地防止DNS劫持,这是由于HTTPS的安全是由SSL来保证的,需要正确的证书,连接才会成立。如果DNS把域名解析到了不对应的IP,是无法通过证书认证的,连接会被终止
87 source、sh、bash ./sh的区别
1-> source在当前shell内去读取、执行a.sh,而a.sh不需要执行权限
2-> sh,bash都是打开一个subshell去读取、执行a.sh,而a.sh不需要有"执行权限"
3-> ./打开一个subshell,打开一个subshell去读取、执行a.sh,但a.sh需要有"执行权限",可以用chmod +x添加执行权限
88 软件开发的生命周期
1->分析阶段:软件开发首先需要进行需求调研和分析完善的需求是软件开发项目成败的重要因素, 提炼所收集的用户需求,建立完整的分析模型,把他编写成软件开发过程中需求,规格说明和初步的用户手册。
2->设计阶段:软件设计可以分为两个阶段概要设计和详细设计,实际上软件设计的主要任务就是把软件分解成模块是指实现某个功能的数据和程序的说明,概要设计就是结构设计,其主要目标就是给出软件模块结构,用软件结构图表示,详细设计的首要任务是设计模块的程序流程,算法和数据结构,设计人员依据软件需求规格说明文档,确定软件的体系结构,进而确定每个模块实现算法,数据结构和接口等,编写设计说明书,组织设计评审。
3->实现阶段:软件编码是指把软件设计转换成计算机可以接受的程序,即写成以某一段程序设计语言表示的“源程序清单”。充分了解软件开发语言,工具的特性和编程风格,有助于开发工具的选择 保证开发产品的开发质量。
4->测试阶段:在设计测试用例的基础上,测试软件的各个组成模块,然后,在把各个模块集成起来,测试整个产品的功能和性能是否能够满足已有的规格说明。
5->维护阶段:维护是指已经完成对软件的研制工作并交付使用后,对软件产品所进行的错误改正,适应环境变化和增强功能等软件工程修订,做好软件维护工作,不仅能排除障碍,使软件能正常工作,而且还可以扩展软件功能,提高性能,为用户带来明显的经济效益,
89 linux df,du的区别
1 du estimates and displays the disk space used by files.可知du基于文件计算和显示磁盘占用情况,du:(disk use)显示每个文件和目录的磁盘使用空间。
2 df:(disk free)显示磁盘分区上可以使用的磁盘空间。The df command reports the amount of available diskspace being used byfile systems. 基于文件系统,意味着不会根据文件是否存在判断当前目录的磁盘占用
90 DNS解析地址的流程(转自在浏览器地址栏输入一个URL后回车,背后会进行哪些技术步骤? - 谭庆波的回答 - 知乎https://www.zhihu.com/question/34873227/answer/441492470)
查询DNS,获取域名对应的IP。
1->检查本地hosts文件是否有这个网址的映射,如果有,就调用这个IP地址映射,解析完成。
2->如果没有,则查找本地DNS解析器缓存是否有这个网址的映射,如果有,返回映射,解析完成。
3->如果没有,则查找填写或分配的首选DNS服务器,称为本地DNS服务器。服务器接收到查询时:
如果要查询的域名包含在本地配置区域资源中,返回解析结果,查询结束,此解析具有权威性。
如果要查询的域名不由本地DNS服务器区域解析,但服务器缓存了此网址的映射关系,返回解析结果,查询结束,此解析不具有权威性。
4-> 如果本地DNS服务器也失效:
如果未采用转发模式(迭代),本地DNS就把请求发至13台根DNS,根DNS服务器收到请求后,会判断这个域名(如.com)是谁来授权管理,并返回一个负责该顶级域名服务器的IP,本地DNS服务器收到顶级域名服务器IP信息后,继续向该顶级域名服务器IP发送请求,该服务器如果无法解析,则会找到负责这个域名的下一级DNS服务器(如http://baidu.com)的IP给本地DNS服务器,循环往复直至查询到映射,将解析结果返回本地DNS服务器,再由本地DNS服务器返回解析结果,查询完成。
如果采用转发模式(递归),则此DNS服务器就会把请求转发至上一级DNS服务器,如果上一级DNS服务器不能解析,则继续向上请求。最终将解析结果依次返回本地DNS服务器,本地DNS服务器再返回给客户机,查询完成
90 app闪退的原因
1-> 弱网络情况下,服务端响应不及时,可能倒是闪退。(网络异常引起的)
2-> 应用版本太低,会导致不兼容,造成闪退。(有些API在老版本中有,在新版本中没有,造成对象为空引起闪退)
3-> APP的SDK和手机的系统不兼容。
4-> 缓存垃圾过多:由于安卓系统的特性,如果长时间不清理垃圾文件。会导致越来越卡,也会出现闪退情况。
5-> 设计不合理,1个接口,拉取的数据量太大,请求结果会很慢,且占用大量内存,APP会闪退(比如,我们现在做的记录仪,进入相册列表时候,要拉取所有图片,拉取太慢了,就闪退了)
6-> 不同APP间切换,交互测试,可能会出现闪退。
7-> 权限问题。
91 网页很卡的原因
1-> 带宽不足、硬件配置低、CPU或者是内存被占满。
2-> http请求次数太多。
3-> 接收数据时间过长,如下载资源过大。
4-> JS脚本过大,阻塞了页面的加载。
5-> 网页资源过多、接受数据时间长、加载某个资源慢。
6-> DNS解析速度慢
92 软件测试流程
1->测试需求分析阶段:阅读需求,理解需求,主要就是对业务的学习,分析需求点,参与需求评审会议
2-> 测试计划阶段:主要任务就是编写测试计划,参考软件需求规格说明书,项目总体计划,内容包括测试范围(来自需求文档),进度安排,人力物力的分配,整体测试策略的制定。风险评估与规避措施有一个制定。
3- 测试设计阶段:主要是编写测试用例,会参考需求文档(原型图),概要设计,详细设计等文档,用例编写完成之后会进行评审。
4-> 测试执行阶段:搭建环境,执行冒烟测试(预测试)-然后进入正式测试,bug管理直到测试结束
5-> 测试评估阶段:出测试报告,确认是否可以上线
测试流程:了解用户需求-->参考需求规格说明书-->测试计划(人力物力时间进度的安排)-->编写测试用例-->评审用例-->搭建环境-->测试包安排预测(冒烟测试)-正式测试-bug-测试结束出报告-->版本上线-->面向用户
93 http请求方法(转自https://zhuanlan.zhihu.com/p/25441947)
1->get方法请求指定的页面信息,返回实体主体。该请求是向服务器请求信息,请求参数会跟在url后面,因此,对传参长度有限制的,而且不同浏览器的上限是不同的(2k, 7~8k及其他)。由于get请求直接将参数暴露在url中,因此对于一些带有重要信息的请求可能并不完全合适。
2->post请求是向指定资源提交数据进行处理请求,例如提交表单或者上传文件等。数据被包含在请求体中,POST请求可能会导致新的资源的建立和/或已有资源的修改。post方法没有对传递资源的大小进行限制,往往是取决于服务器端的接受能力,而且,该方法传参安全性稍高些
3-> put方法是从客户端向服务器传送的数据取代指定的文档的内容。PUT方法的本质是idempotent的方法,通过服务是否是idempotent来判断用PUT 还是 POST更合理,通常情况下这两种方法并没有刻意区分,根据语义使用即可
4.->delete请求服务器删除指定的页面,DELETE请求一般会返回3种状态码:
200 (OK) - 删除成功,同时返回已经删除的资源
202 (Accepted) - 删除请求已经接受,但没有被立即执行(资源也许已经被转移到了待删除区域)
204 (No Content) - 删除请求已经被执行,但是没有返回资源(也许是请求删除不存在的资源造成的)
5->options 允许客户端查看服务器的性能。(常见的是跨域预检Preflighted Reqeusts方法会采用该方法)。一般来说,开发中用到该方法是用来获取服务器支持的请求类型或者查看服务器类型,来确保接下来发送的请求够安全。该请求方法的响应不能缓存。如果该URI是一个星号(“*”),OPTIONS请求将试图应用于服务器,而不是某个指定资源;如果该URI不是星号,则只能用来获取该资源通信中可用的选项。
6->head 类似于get请求,只不过返回的响应中没有具体的内容,用于获取报头
7->connect方法HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器
8->trace方法回显服务器收到的请求,主要用于测试或诊断。