一面:
1、IP报文结构
各字段解释如下:
(1)version:版本号,4bits,指IP协议的版本。
(2)header length:首部长度,4bits,单位为4字节,故最大长度为4*(2^4-1)=60字节,首部固定部分长度为20字节,可变部分为0~40字节。
(3)differentiated services:服务类型,8bits,组成如下:
过程字段:3位,设置了数据包的重要性,取值越大数据越重要,取值范围为:0(正常)~ 7(网络控制)
延迟字段:1位,取值:0(正常)、1(期特低的延迟)
流量字段:1位,取值:0(正常)、1(期特高的流量)
可靠性字段:1位,取值:0(正常)、1(期特高的可靠性)
成本字段:1位,取值:0(正常)、1(期特最小成本)
保留字段:1位 ,未使用
(4)total length:总长度,16bits,首部加上数据的长度总和,单位为字节,故数据报最大长度为2^16-1=65525字节。另外总长度必须不超过最大传送单元MTU。
(5)identification:标识,16bits,计数器,作为数据报标识。当数据报需要分片时,该标识用来表示同属一个数据报的分片。需要分片时结合以下flags、fragment offset一起使用。
(6)flags:标志,3bits,记为D0-D1-D2,各自意义如下:
D0:1表示有后续分片,0表示该数据报为最后一片。
D1:1表示不分片,0表示分片。
D2:保留位,未使用。
(7)fragment offset:片偏移,13bits,单位为8字节,表示分片后的某分片在原分组中的相对位置。
(8)time to live:生存时间,8bits,表示数据报在网络中的寿命,单位为跳,经过一个路由表示一跳,该值减 一,到零则丢弃。
(9)protocal:协议,8bits,指出使用该包裹的上层协议,如TCP=6,ICMP=1,UDP=17等。
(10)header checksum:首部(不包括数据部分)检验和,16bits。这里不采用 CRC 检验码而采用简单的“反码算术求和”计算方法。
(11)source address:源地址,32bits,即源IP地址。
(12)destination address:目的地址,32bits,即目的IP地址。
(13)options:可选字段,长度可变,1~40字节。用于增加IP数据报的控制功能。
(14)另外还有个填充字段,上图中未显示,该字段用来保证首部的长度为4字节的整数倍。
(15)Data:用户数据。
2、TCP报文
TCP(Transmission Control Protocol)传输控制协议是一种面向连接的、可靠的、基于字节流的传输层协议。
(1)TCP报头中的源端口号和目的端口号(各占2字节):同IP数据报中的源IP与目的IP唯一确定一条TCP连接
(2)序号(4字节):用来标识TCP发端向TCP接收端发送的数据字节流第一个字节的序号
(3)确认号(4字节):是期望收到对方下一个报文段的第一个数据字节的序号,若确认号为N,则表明到N-1为止的所有数据均已正确收到
(4)数据偏移(占4位):指出TCP报文段的首部长度,存在该字段是因为TCP报头中任选字段长度可变。报头不包含任何任选字段则长度为20字节;4位所能表示的最大值为1111,转化为10进制为15,15*32/8 = 60,故报头最大长度为60字节
(5)保留(占6位):保留为今后使用,但目前应置为0
(6)紧急指针(2字节):当Urgent标志置1时,紧急指针才有效,它指出本报文段中的紧急数据的字节数(紧急数据结束后就是普通数据)
(7)窗口(2字节):指的是发送本报文段的一方的接收窗口(而不是自己的发送窗口),窗口值作为接收方让发送方设置其发送窗口的依据
(8)检验和(2字节):检验和字段检验的范围包括首部和数据这两部分
(9)选项:长度可变,最长可达40字节,当没有使用“选项”时,TCP的首部长度是20字节
(10)紧急URG:当URG=1时代表紧急指针字段有效,它告诉系统此报文段中有紧急数据,应尽快传送
(11)确认ACK:仅当ACK=1时确认号字段才有效
(12)推送PSH(PuSH):当发送方将报文中的PSH=1时,是希望接收方在收到这个报文后能够尽快地交付接收应用程序,而不是等到整个缓存都填满了后再向上交付
(13)复位RST(ReSeT):当RST=1时,表示TCP连接中出现严重差错(如由于主机崩溃或其他原因),必须释放连接,然后再重新建立运输连接
(14)同步SYN(SYNchronization):在连接建立时用来同步序列号。当SYN=1而ACK=0时,表明这是一个连接请求报文段。若对方同意建立连接,则应在响应的报文段中使SYN=1,ACK=1
(15)终止FIN(FINis):用来释放一个连接,当FIN=1时,表明此报文段的发送方的数据已发送完毕,并要求释放运输
3、线程 进程
进程:是系统进行资源分配和调度的一个独立单位。
线程:是进程的一个实体,是CPU调度和分配的基本单位,线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器、一组寄存器和栈),但它可以与同属一个进程的其他线程共享进程所拥有的全部资源。
在实现了线程的操作系统中,进程是资源分配的基本单位,线程是调度的基本单位,是系统并发执行单元。
引入线程主要有以下四个方面的优点:
a.易于调度
b.提高并发性(同一个进程中的多个线程可以并发执行)
c.开销小
d.有利于发挥多处理器的功能
需要注意的是,线程和进程有以下区别:
(1)一个线程必定属于也只属于一个进程;一个进程可以拥有多个线程并至少拥有一个线程
(2)属于一个进程的所有线程共享该线程的所有资源,包括打开文件、创建的socket等,不同的进程互相独立
(3)线程间切换代价小;进程间切换代价大
(4)进程是程序的一次执行,线程可以理解为程序中一段程序片段的执行(程序:是一组指令的集合)
(5)每个进程都有独立的内存空间,而线程共享其所属进程的内存空间
4、死锁条件及如何解决
产生死锁的原因主要是:
(1) 因为系统资源不足。
(2) 进程运行推进的顺序不合适。
(3) 资源分配不当等。
如果系统资源充足,进程的资源请求都能够得到满足,死锁出现的可能性就很低,否则就会因争夺有限的资源而陷入死锁。其次,进程运行推进顺序与速度不同,也可能产生死锁。
产生死锁的四个必要条件:
(1) 互斥条件:一个资源每次只能被一个进程使用。
(2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
(3) 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
(4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之一不满足,就不会发生死锁。
死锁的解除与预防:
理解了死锁的原因,尤其是产生死锁的四个必要条件,就可以最大可能地避免、预防和解除死锁。所以,在系统设计、进程调度等方面注意如何不让这四个必要条件成立,如何确
定资源的合理分配算法,避免进程永久占据系统资源。此外,也要防止进程在处于等待状态的情况下占用资源。因此,对资源的分配要给予合理的规划。
5、字符串编程,不使用vector
6、电视机坏了怎么办
我认为应该是从测试的角度谈,比如先黑盒测试,然后白盒测试
7、重载()运算符和构造函数冲突吗
不会冲突的,复制构造函数只会在对象定义时被调用,运算符重载则是在对象定义后才被调用。调用时机是完全独立,无冲突可能
8、const有什么作用
const可用于修饰常量、常数组、常对象、常指针、常引用,以及函数的常参数、函数的返回值、类的成员函数、在另一连接文件中使用const常量等。
主要有以下作用:
(1)定义const常量,具有不可变性
(2)方便进行类型检查
(3)方便进行参数的调整或修改
(4)保护被修饰的东西,防止意外的修改,增强了程序的健壮性
(5)为函数重载提供参考
(6)节省空间。const常量从汇编角度看,只是给出了对应的内存地址,程序运行过程中只有一份复制品
(7)提高程序效率。编译器通常不为const常量分配存储空间,而是将其保存到符号表中,没有了存储于读内存的
9、是什么虚函数,为什么虚函数处理慢
指向基类的指针在操作它的多态类对象时,会根据不同的类对象调用其相应的函数,这个函数就是虚函数,虚函数用virtual修饰函数名。虚函数的作用是在程序的运行阶段动态地选择合适的成员函数。在派生类中重新定义的函数应与虚函数具有相同的形参个数和形参类型,(参数类型的顺序也要一致),以实现统一的接口。如果在派生类中没有重新定义虚函数,则它继承基类的虚函数。
当在用父类的引用或者指针调用虚函数时,会先从该对象的头部取到虚函数的地址(C++标准规定虚函数表地址必须放最前),再从虚函数表中取到实际要调用的函数的地址,最终调用该函数。
从网络上大家的总结来看,理论上,虚函数慢的原因主要有三个:
(1)多了几条汇编指令(运行时得到对应类的虚函数的地址)
(2)影响cpu流水线,究其原因还是因为存在动态跳转,这会导致分支预测失败,流水线排空。
设想一下,如果说不是虚函数,那么在编译时期,其相对地址是确定的,编译器可以直接生成jmp/invoke指令;
如果是虚函数,多出来的一次查找vtable所带来的开销,倒是次要的,关键在于,这个函数地址是动态的,譬如
取到的地址在eax里,则在call eax之后的那些已经被预取进入流水线的所有指令都将失效。流水线越长,一次分支预测失败的代价也就越大。
(3)编译器不能内联优化(仅在用父类引用或者指针调用时,不能内联)
10、谈谈多态
C++中通过虚函数实现多态。虚函数的本质就是通过基类访问派生类定义的函数。每一个含有虚函数的类,其实例对象内部都有一个虚函数表指针,该虚函数表指针被初始化为本类的虚函数表的内存地址。所以在程序中,不管对象类型如何转换,但该对象内部的虚函数表指针是固定的,这样才能实现动态地对对象函数进行调用,这就是C++多态性的原理。
假设B由A继承而来,A *a=new B();基类指针a指向派生类对象,加入定义了虚函数,那么由a调用虚函数会调用B中重新定义的虚函数。