- 操作系统相关
- 进程和线程的区别:
- 进程是资源分配的最小单位,线程是操作系统能够进行运算调度的最小单位
- 不同进程的地址空间和其他资源相互独立,但是同一进程的各个线程共享
- 线程上下文切换比进程上下文切换要快得多
- linux各个指令的书写:
- 删除文件夹:rmdir
- 更改所有者:chown
- 更改权限:chmod
- 查看后端运行的进程:bg
- 查看磁盘使用和空闲磁盘空间:df
- 以默认千字节大小查看磁盘使用情况:du
- 显示文件/目录或文件系统的大小:stat
- 显示磁盘大小以及磁盘分区信息:fdisk -|
- 查看文件或目录占用磁盘空间大小:du -h
- Gcc编译过程
- 预处理:
- 预处理是读取c源程序,对其中的伪指令(以#开头的指令,也就是宏)和特殊符号进行“替代”处理;经过此处理,生成一个没有宏定义、没有条件编译指令、没有特殊符号的输出文件。
- 编译:
- 编译程序所要作得工作就是通过词法分析和语法分析,在确认所有的指令都符合语法规则之后,将其翻译成等价的中间代码表示或汇编代码。
- 汇编:
- 汇编过程实际上指把汇编语言代码翻译成目标机器指令的过程。对于被翻译系统处理的每一个C语言源程序,都将最终经过这一处理而得到相应的目标文件。目标文件中所存放的也就是与源程序等效的目标的机器语言代码。 目标文件由段组成。通常一个目标文件中至少有两个段:代码段和数据段
- 链接
- 汇编程序生成的目标文件并不能立即就被执行,其中可能还有许多没有解决的问题。例如,某个源文件中的函数可能引用了另一个源文件中定义的某个符号(如变量或者函数调用等);在程序中可能调用了某个库文件中的函数,等等。所有的这些问题,都需要经链接程序的处理方能得以解决。 链接程序的主要工作就是将有关的目标文件彼此相连接,也即将在一个文件中引用的符号同该符号在另外一个文件中的定义连接起来,使得所有的这些目标文件成为一个能够被操作系统装入执行的统一整体,也就是可执行程序。
- 预处理:
- Bootloader启动过程
- Bootloader的启动流程一般分两个阶段:
- Stage1(阶段一主要通过汇编语言实现,依赖cpu体系结构初始化, 进行硬件的初始化(watchdog,ram初始化)。为Stage2加载代码准备RAM空间。复制Stage2阶段代码到RAM空间。设置好栈。跳转到第二阶段代码的入口点。
- Stage2(阶段2主要通过c语言实现,具有好的可读性和移植性)初始化该阶段所用到的硬件设备。检测系统内存映射。将uImage ,Rootfs,dtb文件从flash读取到RAM内存中。设置内核启动参数。(如通过寄存器传递设备树文件的内存地址)
- Bootloader的启动流程一般分两个阶段:
- 内存分配算法
- 首次适应算法(First Fit):
- 从空闲分区表的第一个表目起查找该表,把最先能够满足要求的空闲区分配给作业,这种方法的目的在于减少查找时间。为适应这种算法,空闲分区表(空闲区链)中的空闲分区要按地址由低到高进行排序。该算法优先使用低址部分空闲区,在低址空间造成许多小的空闲区,在高地址空间保留大的空闲区。
- 最佳适应算法(Best Fit)
- 从全部空闲区中找出能满足作业要求的、且大小最小的空闲分区,这种方法能使碎片尽量小。为适应此算法,空闲分区表(空闲区链)中的空闲分区要按从小到大进行排序,自表头开始查找到第一个满足要求的自由分区分配。该算法保留大的空闲区,但造成许多小的空闲区。
- 最差适应算法(Worst Fit)
- 从全部空闲区中找出能满足作业要求的、且大小最大的空闲分区,从而使链表中的结点大小趋于均匀,适用于请求分配的内存大小范围较窄的系统。为适应此算法,空闲分区表(空闲区链)中的空闲分区按大小从大到小进行排序,自表头开始查找到第一个满足要求的自由分区分配。该算法保留小的空闲区,尽量减少小的碎片产生。
- 循环首次适应算法(Nf)
- 每次为进程分配空间的时候,从上一次刚分配过的空闲区的下一块开始寻找,比如,初始化的内存空闲区是用户输入的max大小,没有进行回收之前之前必定是只有最后一块是空闲的,但是经过回收之后,你设定的表(这里是设定了一张表,也可以用俩张,但是一张就可以解决的没必要俩张),从是空闲区的区号开始分配之后,标记此块,下次分配从标记的这一块开始向下寻找,符合就分配,然后标记分配的空闲区区号,与首次适应算法的区别就在这.
- 首次适应算法(First Fit):
- 大小端
- 大端字节序:高位字节在前,低位字节在后,这是人类读写数值的方法。
- 小端字节序:低位字节在前,高位字节在后,即以0x1122形式储存。
- 进程、线程间通信
- 进程间通信主要有管道、消息传递、共享内存、文件映射和套接字
- 进程管理和控制是通过执行各种原语来实现的。
- 用信箱实现进程间互通信息的通信机制,其需要两个通信原语:发送原语和接收原语。其属于消息传递的间接通信。
- 自旋锁和信号量在互斥使用时需要注意什么?在中断服务程序里面的互斥是使用自旋锁还是信号量?
- 自旋锁会一直自旋等待,不会休眠;而信号量是等待信号来唤醒进程,进程会睡眠。使用时注意希望长等待不吃系统资源时使用信号量,反过来短期的等待使用自旋锁,但会增加系统开销。 中断中不可以使用信号量,因为中断不能睡眠。
- Linux系统的挂起、待机、休眠?
- 挂起:CPU、内存工作,而硬盘、显示器等外部设备停止工作。
- 待机:只对内存供电,CPU、外设停止工作。
- 休眠:CPU、内存停止工作,内存中的数据保存在硬盘中,外部设备也停止工作。
- SPI是什么?有几条线?几种模式?
- SPI,是一种高速的,全双工,同步的通信总线,在芯片的管脚上只占用四根线。SPI总线有四种工作方式,通过行同步时钟极性和相位可以进行组合配置。
- 常用GDB指令
- quit:退出gdb,结束调试
- list:查看程序源代码
- reverse-search:字符串用来从当前行向前查找第一个匹配的字符串
- run:程序开始执行
- help list/all:查看帮助信息
- break:设置断点
- break get_sum:以函数名设置断点
- break 行号或者函数名
- if 条件:以条件表达式设置断点
- watch 条件表达式:条件表达式发生改变时程序就会停下来
- next:继续执行下一条语句 ,会把函数当作一条语句执行 s
- step:继续执行下一条语句,会跟踪进入函数,一次一条的执行函数内的代码
- 简单描述linux设备驱动中的总线,设备和驱动的关系。
- 总线将设备和驱动绑定。在系统每注册一个设备的时候,会寻找与之匹配的驱动;
- 相反的,在系统每 注册一个驱动的时候,会寻找与之匹配的设备,而匹配由总线完成。一个现实的Linux设备和驱动通常都需要挂接在一种总线上。设备与驱动的关联通过总线的match()方法进行匹配,驱动挂载总线时与所有设备进行匹配,设备挂载总线时与所有的驱动进行匹配,所以驱动和设备的挂载无先后之分。匹配成功后会通过调用驱动的probo()方法来初始化设备。
- 头文件的两种包含方式的区别
- < >引用的是编译器的类库路径里面的头文件,#include <> 的查找位置是标准库头文件所在目录;" "引用的是你程序目录的相对路径中的头文件, #include "" 的查找位置是当前源文件所在目录。
- 进程和线程的区别:
- C语言相关
- Strcpy安全问题
- 原因:他们不检查边界,容易造成栈溢出,可能无意间修改错误的内存内容,会引起很多恶意程序的注入,strncpy同理。
- 解决方法:包含头文件的<cstring>,推荐使用strcpy_s(char* a(目的),int len,char* b(源));
- 什么是多态?
- 多态首先是建立在继承的基础上的,有继承才能有多台。
- 字面意思就是多种状态。
- 多态是指不同的子类在继承父类后分别都重写覆盖了父类的方法,即父类同一个方法,在继承的子类中表现出不同的形式。多态成立的另一个条件是在创建子类时候必须使用父类new子类的方式。
- 多态是如何实现的?
- 继承中构成多态还需要两个条件:
- 必须通过基类的指针或者引用调用虚函数
- 被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写
- 继承中构成多态还需要两个条件:
- 虚函数
- 被virtual修饰的类成员函数称为虚函数。
- 派生类有个和虚函数完全一样的函数(返回值,函数名,参数列表相同)
- 静态局部变量和全局变量、静态全局变量
- 全局变量不属于函数,不利于代码维护,静态局部变量虽然在全局数据区,但是他只能被他所在的函数调用。
- 静态全局变量定义在函数体外,用于修饰全局变量,表示该变量仅被本文件可见。其余文件在该变量不用static修饰的时候可以用extern获取该值,其他文件也可以定义相同的变量名而不冲突,他起到了文件隔离的作用。
- 什么是结构体数组?
- 指数组中的每个元素都是一个结构体。
- Struct和union的区别
- Struct的成员放在不同地址上,union成员放在同一个地址空间
- Struct长度是所有成员所占空间的和,union的长度是其占用空间最大的成员的长度
- New和malloc的区别
- New从自由存储区上分配内存,malloc从堆上分配内存
- 自由存储区是C++基于new操作符的一个抽象概念,凡是通过new操作符进行内存申请,该内存即为自由存储区。
- 堆是操作系统中的术语,是操作系统所维护的一块特殊内存,用于程序的内存动态分配。
- new、delete 返回的是某种数据类型指针;malloc、free 返回的是 void 指针。
- 使用new操作符申请内存分配时无须指定内存块的大小,编译器会根据类型信息自行计算;使用malloc则需要显式地指出所需内存的尺寸。
- new 可以调用对象的构造函数,对应的 delete 调用相应的析构函数;malloc 仅仅分配内存,free 仅仅回收内存,并不执行构造和析构函数。
- new、delete 是操作符,可以重载;malloc、free 是函数,可以重写(覆盖)。
- New从自由存储区上分配内存,malloc从堆上分配内存
- struct和class之间的区别
- struct 是值类型,class 是对象类型
- struct 不能被继承,class 可以被继承
- struct 默认的访问权限是public,而class 默认的访问权限是private.
- struct总是有默认的构造函数,即使是重载默认构造函数仍然会保留。这是因为Struct的构造函数是由编译器自动生成的,但是如果重载构造函数,必需对struct中的变量全部初始化。并且Struct的用途是那些描述轻量级的对象,例如Line,Point等,并且效率比较高。class在没有重载构造函数时有默认的无参数构造函数,但是一被重载些默认构造函数将被覆盖。
- struct的new和class的new是不同的。struct的new就是执行一下构造函数创建一个新实例再对所有的字段进行Copy。而class则是在堆上分配一块内存然后再执行构造函数,struct的内存并不是在new的时候分配的,而是在定义的时候分配
- 面向过程的思想和面向对象的思想
- 面向对象和面向过程的思想有着本质上的区别,作为面向对象的思维来说,当你拿到一个问题时,你分析这个问题不再是第一步先做什么,第二步再做什么,这是面向过程的思维,你应该分析这个问题里面有哪些类和对象,这是第一点,然后再分析这些类和对象应该具有哪些属性和方法。这是第二点。最后分析类和类之间具体有什么关系,这是第三点。
- 函数入栈顺序是什么
-
- C程序栈底是高地址,栈顶是低地址。参数入栈顺序是从右至左,这样才支持可变长参数,栈顺序(从右⾄左)的好处就是可以动态变化参数个数。通过栈堆分析可知,⾃左向右的⼊栈⽅式,最前⾯的参数被压在栈底。除⾮知道参数个数,否则是⽆法通过栈指针的相对位移求得最左边的参数。这样就变成了左边参数的个数不确定,正好和动态参数个数的⽅向相反。
-
- 拷贝构造函数用法
- 默认拷贝构造函数
- 很多时候在我们都不知道拷贝构造函数的情况下,传递对象给函数参数或者函数返回对象都能很好的进⾏,这是因为编译器会给我们⾃动产⽣⼀个拷贝构造函数,这就是“默认拷贝构造函数”,这个构造函数很简单,仅仅使⽤“⽼对象”的数据成员的值对“新对象”的数据成员⼀⼀进⾏赋值
- 缺点:可能不会处理静态数据成员
- 浅拷贝
- 默认拷贝构造也是浅拷贝,所谓浅拷贝,指的是在对象复制时,只对对象中的数据成员进⾏简单的赋值,但是一旦对象有动态成员,浅拷贝就会出现问题,拷贝后的对象和原对象的动态成员指针会指向同一个地址,这样析构的时候会对同一个内存空间析构两次。
- 深拷贝
- 在“深拷贝”的情况下,对于对象中动态成员,就不能仅仅简单地赋值了,⽽应该重新动态分配空间
- 为什么拷贝构造函数必须是引用传递,不能是值传递?
- 防止递归引用
- 默认拷贝构造函数
- 简述一下堆和栈的区别
- 1. 管理方式 对于栈来讲,是由编译器自动管理,无需手动控制;对于堆来说,分配和释放都是由程序员控制的。
- 2. 空间大小 总体来说,栈的空间是要小于堆的。堆内存几乎是没有什么限制的;但是对于栈来讲,一般是有一定的空间大小的。
- 3. 碎片问题 对于堆来讲,由于分配和释放是由程序员控制的(利用new/delete 或 malloc/free),频繁的操作势必会造成内存空间的不连续,从而造成大量的内存碎片,使程序效率降低。对于栈来讲,则不会存在这个问题,因为栈是先进后出的数据结构,在某一数据弹出之前,它之前的所有数据都已经弹出。
- 4. 生长方向 对于堆来讲,生长方向是向上的,也就是沿着内存地址增加的方向,对于栈来讲,它的生长方式是向下的,也就是沿着内存地址减小的方向增长。
- 5. 分配方式 堆都是动态分配的,没有静态分配的堆。栈有两种分配方式:静态分配和动态分配,静态分配是编译器完成的,比如局部变量的分配;动态分配由alloca函数进行分配,但是栈的动态分配和堆是不同的,它的动态分配是由编译器实现的,无需我们手工实现。
- 6. 分配效率 栈是机器系统提供的数据结构,计算机会在底层对栈提供支持,分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率很高。堆则是 C/C++ 函数提供的,它的机制是很复杂的,例如为了分配一块内存,库函数会按照一定的算法在堆内存中搜索可用的足够大小的空间,如果没有足够大小的空间(可能是由于碎片太多),就有可能调用系统功能去增加程序数据段的内存空间,这样就有机会分到足够大小的内存,然后进行返回。显然,堆的效率要比栈底的多。
- Strcpy安全问题
- 数据库
- 数据库搜索去重关键字:distinct
- 去重第二个方法,用于一部分字段有重复,但是主键不重复:group by
- 什么是死锁?如何避免?
- 定义:两个或两个以上的进程在执行的时候,因为争夺互斥资源而造成的一种互相等待的现象,若无外力作用,他们都无法进行下去,此时系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。
- 死锁发生的条件:
- 1、互斥条件:进程分配到的资源是互斥的临界资源。
- 2、进程已经至少保持一个资源,又提出了新的资源请求,但是该资源已经被其他资源占有。
- 3、进程获得的资源在未使用完之前不能被剥夺
- 4、环路等待条件:指发生死锁的时候必然存在一个环形等待链。
- 避免死锁的四个方法:
- 避免多次锁定,避免同一个线程对多个lock进行锁定。
- 具有相同的加锁顺序。
- 使用定时锁。
- 死锁检测,针对不可能按序加锁也不可能使用定时锁的场景。
- JAVA
- Java重写:也称覆盖。重写是子类对父类非静态,非private,非final方法的实现过程进行重新编写,返回值(JDK7以后,被重写的方法返回值类型可以不同,但是必须是具有父子关系的)和形参都不能改变。即外壳不变,核心重写。
- Java重载:重载的参数列表是必须修改的,而返回值类型,访问限定符是可以修改的。重载是静态绑定,即在编译时就根据实参类型确定了调用哪个方法。
- Final不能修饰方法,final修饰的方法表示最终方法,不能被重写,但是接口本来就是其他接口继承,其他类实现的,所以不能用final修饰,类可以被final修饰但是不能被继承。
- 静态变量和常量的区别:
- 共同点:他们在编译的时候都是直接分配内存的
- 本质上,static是类型引用,const是实例引用
- 静态变量存放在全局数据区中,伴随着这个程序流程,能将此变量的值保留到下次调用,不过数据过大的静态变量有可能造成内存泄露。 而const常量算是一个普通的只读变量,随函数结束而结束。
- Static在java和C++区别
- Java中:
- 1、static为特定数据类型和对象分配单一的存储空间,和创建的对象个数无关。
- 2、Static方法不能方位非static类型的变量。Static字段每个类只有一个。
- C++中:
- 1、修饰全局变量时,用于限制全局变量使用范围,仅在本文件内使用该变量。
- 2、修饰局部变量时,修改该变量的存储控件类型,没修饰前变量存在栈区,函数结束会清空,修饰后变量存在静态区,函数结束不会清空。
- 3、修饰函数时,使成员变量或函数属于整个对象而不是这个类。
- Java中:
- 数据结构相关
- 栈是线性表,关联数组不是,关联数组是有特殊索引方式的数组。
- 二分查找中间值有两个的时候取偏小的那个
- 因为是循环链表 rear不一定就比front地址高 所以有可能rear-fornt得到结果是负数 所以为了正确性起见需要+m再%m
- 每种数据结构都应具备三种基本运算:插入、删除和搜索。(错),栈没有搜索操作。
- 二维数组是每个元素都为线性表的线性表 .
- 项目相关
- IEEE 802.11b/g/n协议
- IEEE 802.11b是无线局域网的一个标准。其载波的频率为2.4GHz,可提供1、2、5.5及11Mbit/s的多重传送速度。
- IEEE 802.11g在2003年7月被通过。其载波的频率为2.4GHz(跟802.11b相同),共14个频段,原始传送速度为54Mbit/s,净传输速度约为24.7Mbit/s(跟802.11a相同)。802.11g的设备向下与802.11b兼容。
- IEEE 802.11n,是由IEEE在2004年1月组成的一个新的工作组在802.11-2007的基础上发展出来的标准,于2009年9月正式批准。该标准增加了对MIMO的支持,允许40MHz的无线频宽,最大传输速度理论值为600Mbit/s。同时,通过使用Alamouti提出的空时分组码,该标准扩大了数据传输范围。
- I2C(Inter-Integrated Circuit ,内部集成电路)是两条串行的总线,它由一根数据线(SDA)和一根 时钟线(SDL)组成。
- 两条线都需要上拉电阻。I2C 总线上可以接多个 I2C 设备,每个器件都有一个唯一的地址识别。同一时间只能有一个主设备,其他为从设备。通常 MCU 作为主设备控制,外设作为从设备。
- iic分为两条总线:SDA(数据线) 和SCL(时钟线)。只有⼀条数据线也决定了它只能进⾏“半双⼯”通信。需要通讯的设备挂载在这两条总线上。线上设备都有⾃⼰的iic地址。
- ⼀般地址位有8位(7位是地址位,1位是⽅向位。 0:主机发,1:主机收)
- 在起始信号后(调⽤iic开始函数) 必须传送⼀个从机的地址(7位),第8位是数据的传送⽅向位(R/T),⽤“0”表⽰主机发送数据(T),“1”表⽰主机接收数据(R)。
- iic本⾝不带检验码
- 启动条件:SCl ⾼,SDA 由⾼到低,结束条件:SCl ⾼ ,SDA 由低到⾼
- 传送⼀字节的数据(⼀字节为8位),加上应答帧就是9帧。
- 在传送过程中,当需要改变传递⽅向时,起始信号和从机地址都被重复⼀次产⽣⼀次,但两次读/写⽅向位正好相反
- 空闲状态,两线都是处于⾼电平状态。
- IEEE 802.11b/g/n协议
- 计算机网络相关
- 七层模型
- 应用层、表示层、会话层、传输层、网络层、数据链路层、物理层
- 五层模型
- 应用层(应用层、表示层、会话层)、传输层、网络层、数据链路层、物理层
- TCP/IP层对应协议
- 应用层:HTTP,DNS(域名解析协议),FTP(文件传输协议)
- 传输层:UDP,TCP
- 网络层:IP(网际协议),ICMP(互联网控制报文协议),IGMP(互联网组管理协议),RIP
- TCP和UDP区别
- UDP:对网络通讯质量要求不高时,要求网络通讯速度要快的场景
- 无连接,发送数据之前不需要建立连接。
- 尽最大努力交付,不保证可靠交付,不使用拥塞控制。
- 面向报文,适合多媒体通信。
- 支持一对一,一对多,多对一,多对多的交互通信。
- 首部开销小,8个字节。
- TCP:当对网络通讯质量有要求时,比如HTTP、HTTPS、FTP等传输文件的协议, POP3、SMTP等邮件传输的协议
- 面向连接。
- 每一条TCP有且只有两个端点,为一对一关系。
- 提供可靠交付。
- 全双工通信,全双工为即可传输又可接收。
- 面向字节流。
- UDP:对网络通讯质量要求不高时,要求网络通讯速度要快的场景
- TCP为什么可靠
- 乱序重排
- 应答确认
- 报文重传
- 流量控制(接收方受不了)
- 拥塞控制(网路受不了)
- 一般嵌入式 Linux 的开发过程, 无论是 ARM, PowerPC 或 MIPS 的处理器, 都必需经过以下的开发过程:
- 创建 Linux 交叉编译环境;
- 建立 Bootloader;
- 移植 Linux 内核;
- 建立 Rootfs (根文件系统);
- 安装驱动程序;
- 安装软件;
- 在浏览器中输入URL后,执行的全部过程。
- 域名解析
- 发起TCP的3次握手
- 建立TCP连接后发起http请求
- 服务器响应http请求
- 浏览器解析html代码,并请求html代码中的资源(如js、css、图片等)
- 断开TCP连接
- 浏览器对页面进行渲染呈现给用户
- ACK : TCP协议规定,只有ACK=1时有效,也规定连接建立后所有发送的报文的ACK必须为1
- SYN(SYNchronization) : 在连接建立时用来同步序号。当SYN=1而ACK=0时,表明这是一个连接请求报文。对方若同意建立连接,则应在响应报文中使SYN=1和ACK=1. 因此, SYN置1就表示这是一个连接请求或连接接受报文。
- FIN (finis):即完,终结的意思, 用来释放一个连接。当 FIN = 1 时,表明此报文段的发送方的数据已经发送完毕,并要求释放连接。
- 为什么TCP客户端最后还要发送一次确认呢?
- 主要是为了防止已失效的连接请求报文段又突然传送给B,从而产生了错误。
- 进行三次握手的主要作用就是为了确认双方的接收能力和发送能力是否正常、指定自己的初始化序列号为后面的可靠性传送做准备。第三次握手不能去掉,第三次握手能防止发生死锁,因为若为两次握手且服务器发出第二次握手而客户端没有收到,服务器开始传输数据报后客户端便不会理会,导致服务器以为丢包而源源不断地发送数据报,造成死锁。
- 四次挥手
- 客户端进程发出连接释放报文,并且停止发送数据。释放数据报文首部,FIN=1,其序列号为seq=u(等于前面已经传送过来的数据的最后一个字节的序号加1),此时,客户端进入FIN-WAIT-1(终止等待1)状态。 TCP规定,FIN报文段即使不携带数据,也要消耗一个序号。
- 服务器收到连接释放报文,发出确认报文,ACK=1,ack=u+1,并且带上自己的序列号seq=v,此时,服务端就进入了CLOSE-WAIT(关闭等待)状态。TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间。
- 客户端收到服务器的确认请求后,此时,客户端就进入FIN-WAIT-2(终止等待2)状态,等待服务器发送连接释放报文(在这之前还需要接受服务器发送的最后的数据)。
- 服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,FIN=1,ack=u+1,由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为seq=w,此时,服务器就进入了LAST-ACK(最后确认)状态,等待客户端的确认。
- 客户端收到服务器的连接释放报文后,必须发出确认,ACK=1,ack=w+1,而自己的序列号是seq=u+1,此时,客户端就进入了TIME-WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过2∗∗MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态。
- 服务器只要收到了客户端发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接。可以看到,服务器结束TCP连接的时间要比客户端早一些。
- TCP、UDP的区别?
- TCP是面向连接的,UDP是面向无连接的。 TCP是面向字节流的,UDP是基于数据报的。 TCP提供可靠服务(正确性、顺序性),UDP提供不可靠服务。 TCP程序结构复杂,占用资源多;UDP程序结构简单,占用资源少。 TCP有拥塞控制;UDP没有拥塞控制。 TCP只支持一对一;UDP支持一对一、一对多、多对一、多对多。
- 请你说说 TCP 和 UDP 的使用场景
- UDP:语音、视频、寻址、游戏、广播。
- TCP:邮件、远程登陆、超文本、文件、身份信息、重要内容
- 请你说说 DNS 解析过程以及 DNS 劫持
- DNS查询的过程简单描述就是:主机向本地域名服务器发起某个域名的DNS查询请求,如果本地域名服务器查询到对应IP,就返回结果,否则本地域名服务器直接向根域名服务器发起DNS查询请求,要么返回结果,要么告诉本地域名服务器下一次的请求服务器IP地址,下一次的请求服务器可能是顶级域名服务器也可能还是根域名服务器,然后继续查询。循环这样的步骤直到查询到结果,本地域名服务器拿到结果返回给主机。
- 在完成整个域名解析的过程之后,并没有收到本该收到的IP地址,而是接收到了一个错误的IP地址。比如输入的网址是百度,但是却进入了奇怪的网址,并且地址栏依旧是百度。在这个过程中,攻击者一般是修改了本地路由器的DNS地址,从而访问了一个伪造的DNS服务器,这个伪造的服务器解析域名的时候返回了一个攻击者精心设计的网站,这个网站可能和目标网站一模一样,当用户输入个人账户时,数据会发送给攻击者,从而造成个人财产的丢失。 加分回答 预防DNS劫持可以通过以下几种方法: 1. 准备多个域名,当某个域名被劫持时,暂时使用另一个 2. 手动修改DNS,在地址栏输入http://192.168.1.1,进入路由器配置,填写主DNS服务器为114.114.114.114,填写备用DNS服务器为8.8.8.8 3. 修改路由器密码, 4. 给运营商打投诉电话,讲明被劫持的情况
- 七层模型