嵌入式软件开发工程师面试指南_总结_嵌入式软件开发面经攻略

收集整理了一份《2024年最新物联网嵌入式全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升的朋友。
img
img

如果你需要这些资料,可以戳这里获取

需要这些体系化资料的朋友,可以加我V获取:vip1024c (备注嵌入式)

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人

都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

2)、用const修饰形参:func(const int a){ };该函数在函数内不能改变。

3)、用const修饰成员函数:该函数对成员变量只能进行只读操作,就是不能修改成员变量的数值。

下面的声明都是什么意思?

const int a;
int const a;
const int \*a;
int \* const a;
int const \* a const;

第一和第二作业是一样的,a是常整型数。

第三个意味着a是一个指向常整型数的指针。(整型数不可修改,但指针可以)

第四个意思是a是一个指向整型数的常数的指针。(指针指向的整型数是可以修改的,但指针是不可修改的)

第五个意味着a是一个指向整型数的常指针。(指针指向的整型数是不可修改的,同时指针也是不可修改的)

[scode type=“blue”]

结论和记忆方法: ***
(1)const 在 *前面,就表示const作用于p所指向的量。所以这时候p所指向的是个常量。
(2)const 在 *后面,表示p本身是常量,但是p指向的不一定是常量。
(3)*在const中间,表示p本身是常量,p指向的也是个常量。

[/scode]

1.5、const常量和#define的区别(编译阶段、安全性、内存占用等)

用#define max 100;定义的常量没有类型(不就行类型安全检查,可能会参数意想不到的错误)所给出的是一个立即数,编译器只是把所定义的常量值与所在的常量名字联系起来,define所定义的宏变量在预处理阶段的时候进行替换,在程序中使用到该常量的地方都要进行拷贝替换。

用const int max = 255;定义的常量有类型(编译时会进行类型检查)名字,存储在静态区域中,在编译时确定其值。在程序运行过程中const变量只有一个拷贝,而#define所定义的宏变量却有多个拷贝,所以宏定义在程序运行过程中所消耗的内存比const变量的大很多。

1.6、volatile作用和用法

一个定义为volatile的变量是说这变量可能被意想不到的地改变,这样不会假设这个变量的值了。

以下几种情况都会用到volatile:

1)、并行设备的硬件存储器。

2)、一个中断服务子程序会访问到的非自动变量。

3)、多线程应用中被几个任务共享的变量。

1.7、变量的作用域(全局变量和局部变量)

全局变量:

在所以函数体外部定义,程序所在的部分(甚至其他文件中的代码)都可以使用。

全局变量不受作用域的影响(也就是全局变量的生命周期一直到程序的结束)。

局部变量:

出现在一个作用域内,它们是局限于一个函数的。

局部变量经常被称为自动变量,它们进入作用域时自动生成,离开作用域时自动消失。

关键字auto可以显式说明这个问题,但是局部变量默认为auto。所以没有必要声明auto。

局部变量可以和全局变量重名,在局部变量作用域范围内,全局变量失效,采用的是局部变量的值。

1.8、sizeof与strlen(字符串,数组)

1)、如果是数组:

#include<stdio.h>
int main()
{
int a[5]={1,2,3,4,5};
printf(“sizeof 数组名=%d\n”,sizeof(a));
printf(“sizeof \*数组名=%d\n”,sizeof(\*a));
}

运行结果:

sizeof 数组名=20
sizeof \*数组名=4

2)、如果是指针,sizeof只会检测到指针的类型,指针都是占用4字节的空间(32位机)。

sizeof是什么?是一个操作符,也是关键字,就不是一个函数,这和strlen()不同,strlen()是一个函数。

1.9、与或非,异或。运算符优先级

1.10、递归函数与回调函数的区别是什么?

答:回调是一个函数把非当前函数当做参数传递到自身内部来调用;而递归是自己调用自己。

1.11、问什么要用回调函数呢?

答:我们对回调函数的使用无非是对函数指针的应用,函数指针的概念本身很简单,但是把函数指针应用于回调函数就体现了一种解决问题的策略,一种设计系统的思想。

1.12、const关键字的作用

const是一个修饰符,被修饰的对象或者变量是不可修改的,也就是说const可读不可改

1.13、系统调用和函数调用的区别

系统调用是最底层的应用,是面向硬件的。而库函数的调用是面向开发的,相当于应用程序的API(即预先定义好的函数)接口;

1.14、段错误发生的原因

段错误 是指访问的内存超过了系统给程序分配的内存空间。

原因:

  • 访问不存在的内存空间
  • 访问只读的内存空间
  • 访问系统保护的内存空间
  • 栈溢出

1.15、段错误发生的原因

1.16、什么时候会造成内存泄露

常见的内存泄露

(1)内存分配未成功,却使用了它
(2)内存分配成功,但尚未初始化就引用它
(3)内存分配成功且初始化,但操作越过了内存的边界
(4)忘记释放内存,造成内存泄漏
(5)释放了内存却继续使用它

1.17、什么是大小端模式

0x123456在内存中的存储方式 - 大端模式 低地址 -----> 高地址 0x12 | 0x34 | 0x56 - 小端模式 低地址 -----> 高地址 0x56 | 0x34 | 0x12
指针方式来判断机器的大小端

#include <stdio.h>

// 如果是小端模式则返回1,小端模式则返回0
int is\_little\_endian2(void)
{
    int a = 1;
    char b = \*((char \*)(&a));     // 指针方式其实就是共用体的本质

    return b;
}

int main(void)
{
    int i = is\_little\_endian2();
    if (i == 1)
    {
        printf("小端模式\n");
    }
    else
    {
        printf("大端模式\n");
    }

    return 0;
}

1.18、全局变量可以声明定义在头文件中?

注意头文件中不可以放变量的定义!!!一般情况下头文件中只放变量的声明,因为头文件要被其他文件包含(即#include),如果把定义放到头文件的话,就不能避免多次定义变量,C++不允许多次定义变量,一个程序中对指定变量的定义只有一次,声明可以无数次。

1.19、C语言中各种数据类型与"0"的比较详解

1.19.1、int类型数据和0比较

1.19.1、int类型数据和0比较

if(a == 0)或者 if(a != 0)

1.19.2、float类型与0比较

const float N=0.0001;

if( (a>=N) && (a<=N)

不建议写成:

if(a == 0)或者 if(a != 0)

1.19.3、bool类型与0比较

建议写成:if(a)或者 if(!a)

1.19.4、指针类型与0比较

if(p == NULL) 或者 if(p != NULL)

1.20、c语言中什么是位段

位段(bit-field)是以位为单位来定义结构体(或联合体)中的成员变量所占的空间。含有位段的结构体(联合体)称为位段结构。采用位段结构既能够节省空间,又方便于操作。

1.21、简述什么是地址传递和值传递,并简述两者的区别

值传递只是将变量的内容复制一份而已,函数进行操作的其实是另一个变量,只是另一个变量的值和传递的变量值是相同的。

而地址传递是直接把变量的地址传递给函数,这时函数是直接对原来的变量进行操作的。所以值会变化。

1.21、c语言中调用函数如何返回多个值?

通过使用指针,在函数调用时,传递带有地址的参数,并使用指针更改其值;这样,修改后的值就会变成原始参数。

1.22、函数中能否返回一个局部变量地址

一般的来说,函数是可以返回局部变量的。 局部变量的作用域只在函数内部,在函数返回后,局部变量的内存已经释放了。

1.23、栈的特点是什么

栈的特点是先进后出表。栈是一种只能在一端进行插入和删除操作的特殊线性表。它按照先进后出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据。

1.24、c语言中用了#define,作用范围是从哪到哪

define只在当前文件有效,如果是在头文件中定义的,则引用改头文件的文件都有效

1.25、c语言中定义常量有几种方式

定义常量PI的两种方式:

#define Pi 3.1415926f;

const float pi 3.1415926f;

1.26、程序的局部变量存在于哪里,全局变量存在于哪里,动态申请数据存在于哪里。

程序的局部变量存在于栈区;全局变量存在于静态区;动态申请数据存在于堆区。

1.27、do……while和while有什么区别?

do…while是先循环再判断,while是先判断再循环。

二、Linux

2.1、 Linux内核的组成部分

Linux内核主要由五个子系统组成:进程调度,内存管理,虚拟文件系统,网络接口,进程间通信。

2.2、Linux系统的组成部分

Linux系统一般有4个主要部分:内核、shell、文件系统和应用程序。

2.3、系统调用与普通函数调用的区别

1)、系统调用:

  • 使用INT和IRET指令,内核和应用程核态,从而可以使用特权指令操控设备
  • 依赖于内核,不保证移植性
  • 在用户空间和内核上下文环境间切换
  • 是操作系统的一个入口点

2)、普通函数调用:

  • 使用CALL和RET指令,调用时没有堆
  • 平台移植性好
  • 属于过程调用,调用开销较小
  • 一个普通功能函数的调用

2.4、内核态,用户态的区别

内核态,操作系统在内核态运行——运行操作系统程序

用户态,应用程序只能在用户态运行——运行用户程序

2.5、bootloader、内核、根文件的关系

启动顺序:bootloader->linux kernel->rootfile->app

2.6 、Bootloader启动的两个阶段:

Stage1:汇编语言

Stage2:c语言

2.7、linux下检查内存状态的命令

查看进程:top
查看内存:free
cat /proc/meminfo
vmstat

2.8、一个程序从开始运行到结束的完整过程(四个过程)

预处理(Pre-Processing)、编译(Compiling)、汇编(Assembling)、链接(Linking)

2.9、什么是堆,栈,内存泄漏和内存溢出?

栈由系统操作,程序员不可以操作。

所以内存泄漏是指堆内存的泄漏。

堆内存是指程序从堆中分配的,大小任意的,使用完后必须显式释放的内存。应用程序一般使用malloc,new等函数从堆中分配到一块内存,使用完后,程序必须负责相应的调用free或delete释放该内存块,否则,这块内存就不能被再次使用。

内存溢出:你要求分配的内存超出了系统能给你的,系统不能满足需求,于是产生溢出。

内存越界:向系统申请了一块内存,而在使用内存时,超出了申请的范围(常见的有使用定大小数组时发生内存越界)

内存溢出问题是 C 语言或者 C++ 语言所固有的缺陷,它们既不检查数组边界,又不检查类型可靠性(type-safety)。

2.10、死锁的原因、条件

产生死锁的原因主要是:

1)、因为系统资源不足。

2)、进程运行推进的顺序不合适。

3)、资源分配不当等。

2.11、硬链接与软链接

1)、硬链接

硬链接只能引用同一文件系统中的文件。它引用的是文件在文件系统中的物理索引(也称为inode)。当您移动或删除原始文件时,硬链接不会被破坏,因为它所引用的是文件的物理数据而不是文件在文件结构中的位置。

硬链接的文件不需要用户有访问原始文件的权限,也不会显示原始文件的位置,这样有助于文件的安全。如果您删除的文件有相应的硬链接,那么这个文件依然会保留,直到所有对它的引用都被删除。

2)、软链接

软连接,其实就是新建立一个文件,这个文件就是专门用来指向别的文件的(那就和windows 下的快捷方式的那个文件有很接近的意味)。

软连接产生的是一个新的文件,但这个文件的作用就是专门指向某个文件的,删了这个软连接文件,那就等于不需要这个连接,和原来的存在的实体原文件没有任何关系,但删除原来的文件,则相应的软连接不可用。

2.12、中断和异常的区别

内中断:同步中断(异常)是由cpu内部的电信号产生的中断,其特点为当前执行的指令结束后才转而产生中断,由于有cpu主动产生,其执行点必然是可控的。

外中断:异步中断是由cpu的外设产生的电信号引起的中断,其发生的时间点不可预期。

2.13、中断怎么发生,中断处理流程

请求中断→响应中断→关闭中断→保留断点→中断源识别→保护现场→中断服务子程序→恢复现场→中断返回。

2.14、linux下编译优化选项

加:-o

2.15、linux命令

1)、改变文件属性的命令:chmod (chmod 777 /etc/squid 运行命令后,sq
就被修改为777(可读可写可执行))

2)、查找文件中匹配字符串的命令:grep

3)、查找当前目录:pwd

4)、删除目录:rm -rf 目录名

5)、删除文件:rm 文件名

6)、创建目录(文件夹):mkdir

7)、创建文件:touch

8)、vi和vim 文件名也可以创建

9)、解压:tar -xzvf 压缩包

打包:tar -cvzf 目录(文件夹)

10)、查看进程对应的端口号

1、先查看进程pid
ps -ef | grep 进程名
2、通过pid查看占用端口
netstat -nap | grep 进程pid

2.16、硬实时系统和软实时系统

软实时系统:
Windows、Linux系统通常为软实时,当然有补丁可以将内核做成硬实时的系统的。

硬实时系统:
对时间要求很高,限定时间内不管做没做完必须返回。
VxWorks,uCOS,FreeRTOS,WinCE,RT-thread等实时系统;

三、数据结构

3.1、十大排序

我想对于每一个经历过秋招的小伙伴们来说,十大排序基本都被问过(快速排序、归并排序、堆排序、冒泡排序、插入排序、选择排序、希尔排序、桶排序、基数排序)。

对这十大排序的考察主要有两点:
1、考察时间复杂度、空间复杂度、稳定与否。
2、手写某种排序。
第一点:对于时间复杂度的考察,可能会考察插入排序的平均复杂度是多少?最坏和最好复杂度又是多少?有时候也会从别的角度来对你进行考察,直接会问你了解到的的排序中哪些排序是稳定的?哪些不是稳定的?
第二点:快速排序手写次数绝对占据第一名,因为现在企业招聘基本都是有代码要求的,有时候面试官可能也拿不准让你写什么算法题,“算了,写个快排吧”,快排的频率就是就是这样被拉高的;第二高频率的应该就是归并排序了。在笔者秋招过程中,手写过5次归并,3次快排。因为归并是刚好比快排难度大一点,但也不是那种特别难的排序方法。对于女生来说,让手写的排序一般是冒泡排序、快速排序、归并排序,对于男生同学而言,要求手写的排序一般有快速排序、归并排序以及堆排序。
十大排序中考察最多的就是冒泡排序、快速排序、归并排序、堆排序以及可能会出现的桶排序和基数排序了,其余排序出现的概率稍小一点。

3.2、算法

嵌入式考察算法大多都是双向链表、二叉树、字符串翻转和复制这些普通题目。刷题可以在LeetCode、牛客网、杭电OJ等。
十种常见排序算法可以分为两大类:
非线性时间比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此称为非线性时间比较类排序。
线性时间非比较类排序:不通过比较来决定元素间的相对次序,它可以突破基于比较排序的时间下界,以线性时间运行,因此称为线性时间非比较类排序。

3.3、队列和栈的区别有什么?

栈:

栈(stack)又名堆栈,线性表。仅允许在表的一端进行插入和删除运算。这一端为栈顶,另一端为栈底,先进后出。

队列:

队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。

3.4、顺序表和链表他们的特点?

线性表存储数据,需要预先申请一块存储空间,然后将数据按照次序逐一存储,数据之间紧密贴合,不留一丝空隙,

链表的存储方式与顺序表截然相反,什么时候存储数据,什么时候才申请存储空间,数据之间的逻辑关系依靠每个数据元素携带的指针维持

3.5、什么是完全二叉树

如果二叉树中除去最后一层节点为满二叉树,且最后一层的结点依次从左到右分布,则此二叉树被称为完全二叉树。

3.6、什么是二叉树

树有很多种, 每个节点最多只能有两个子节点的叫二叉树

二叉树的子节点分为左节点和右节点

3.7、七大查找算法

顺序查找

二分查找

插值查找

斐波那契查找

树表查找

分块查找

哈希查找

3.8、十大排序排序算法

(1)冒泡排序;

(2)选择排序;

(3)插入排序;

(4)希尔排序;

(5)归并排序;

(6)快速排序;

(7)基数排序;

(8)堆排序;

(9)计数排序;

(10)桶排序;

3.8、怎样判断一个算法的优劣?

时间复杂度

空间复杂度

3.9、"算法"的基本特征有哪些?

一个算法应该具有以下五个重要的特征:

1,有穷性(Finiteness)

2,确切性(Definiteness)

3,输入项(Input)

4,输入项(Input)

5,可行性(Effectiveness)

3.10、什么是哈希表

根据关键码值而直接进行访问的数据结构

3.11、如何判断单链表是否存在环

方法一、穷举遍历

方法二、哈希表缓存

方法三、快慢指针

方法四、Set集合大小变化

3.12、删除链表中倒数第n个节点

要删除倒数第n个节点,我们就要找到其前面一个节点,也就是倒数第n+1个节点,找到这个节点就可以进行删除;
定义两个指针,p和cur,cur指针向前走,走了n+1步之后,p指针开始走,当cur指针走到链表结尾的时候,p指针刚好走到倒数第n+1个节点处。

3.13、循环队列有什么用

为充分利用向量空间,克服"假溢出"现象的方法是:将向量空间想象为一个首尾相接的圆环,并称这种向量为循环向量。

四、进程与线程

4.1、什么是进程、线程、有什么区别

进程是资源(CPU、内存等)分配的基本单位,线程是CPU调度和分配的基本单位(程序执行的最小单位)。

同一时间,如果CPU是单核,只有一个进程在执行,所谓的并发执行,也是顺序执行,只不过由于切换太快,误以为这些进程同步执行。多核CPU可以同一时间点多个进程在执行。

4.2、多进程与多线程的优缺点

1)、一个进程死了不影响其他进程,一个线程奔溃很可能影响1到它本身所处在的线程。

2)、创建多进程的系统花销大于创建多线程。

3)、多进程通讯因为需要跨域进程边界,不适合大量的数据传送,适合小数据或者密集的数据传送。多线程无需跨域进程边界,适合各线程间的大量传送。并且多线程跨域共享同一进程的共享内存和变量。

4.3、什么时候用进程、什么时候用线程

进程间通讯:

(1)、有名管道、无名管道;(2)、信号;(3)、共享内存;(4)、消息队列;(5)、信号量;(6)、socket

线程通讯(锁):

(1)、信号量;(2)、读写锁;(3)、条件变量;(4)、互斥锁;(5)、自旋锁

4.4、父进程、子进程

父进程调用fork()以后,克隆出一个子进程,子进程和父进程拥有相同内容的代码段、数据段和用户堆栈。

父进程和子进程谁先执行不一定,看CPU。所以我们一般会设置父进程等待子进程执行完毕。

4.5、Fork的作用是什么?

在Linux下产生新的进程的系统调用就是fork函数

4.6、fork和vfork的区别

  • fork ():子进程拷贝父进程的数据段,代码段
    vfork( ):子进程与父进程共享数据段
  • fork ()父子进程的执行次序不确定
    vfork 保证子进程先运行,在调用exec 或exit 之前与父进程数据是共享的,在它调用exec
    或exit 之后父进程才可能被调度运行。

4.7、进程的开销比线程大在了哪里?

  • 创建进程需要为进程划分出一块完整的内存空间,有大量的初始化操作,比如要把内存分段(堆栈、正文区等)。
  • 创建线程则简单得多,只需要确定 PC 指针寄存器 的值,并且给线程分配一个 用于执行程序,同一个进程的多个线程间可以复用堆栈
  • 因此,创建进程比创建线程慢,而且进程的内存开销更大。

4.8、什么是阻塞,什么是非阻塞

阻塞调用是指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。

非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程。

4.9、同步和互斥

互斥 :是指散步在不同任务之间的若干程序片断,当某个任务运行其中一个程序片段时,其它任务就不能运行它们之中的任一程序片段,只能等到该任务运行完这个程序片段后才可以运行。

同步 :是指散布在不同任务之间的若干程序片断,它们的运行必须严格按照规定的某种先后次序来运行,这种先后次序依赖于要完成的特定的任务。

4.10、申请互斥锁的过程

/\*头文件\*/

#include <pthread.h>

1)初始化互斥锁

int pthread\_mutex\_init(pthread_mutex_t \*mutex, const pthread_mutexattr_t \*attr);

2)上锁

int pthread\_mutex\_lock(pthread_mutex_t \*mutex);

3)解锁

int pthread\_mutex\_unlock(pthread_mutex_t \* mutex);

4)销毁互斥锁

int pthread\_mutex\_destroy(pthread_mutex_t \*mutex);

4.11、创建守护进程的步骤

  • 创建子进程,父进程退出
  • 子进程下创建新的会话
  • 设置当前目录为根目录
  • 设置文件权限掩码
  • 退出文件描述符

4.12、指出静态库和共享库的区别

静态库编译时程序较大,可以独立运行。

动态库编译时程序交小,不可独立运行。

4.13、什么是 I/O 多路复用?

I/O 通常指网络 I/O,多路指多个 Socket 链接,复用指操作系统进行运算调度的最小单位线程 。整体意思也就是多个网络 I/O 复用一个或少量的线程来处理 Socket。

I/O 多路服用有多种实现模式:selectpollepollkqueue

1.14、进线程的区别

线程依赖于进程,同一进程的多个线程共享这一进程的资源。 所以进程间的切换会比线程更加的耗时。

1.15、一个程序中最多创建多少个线程

一个线程的栈要预留1M的内存空间,而一个进程中可用的内存空间只有2G,所以理论上一个进程中最多可以开2048个线程,但是内存当然不可能完全拿来作线程的栈,所以实际数目要比这个值要小。

1.16、文件io中的文件描述符

对于Linux而言,所有对设备或文件的操作都是通过文件描述符进行的。

1.17、线程中的同步应该怎么实现

当使用多个线程来访问同一个数据时,非常容易出现线程安全问题(比如多个线程都在操作同一数据导致数据不一致),所以我们用同步机制来解决这些问题。

1.18、进程间通信消息队列的机制

消息队列与命名管道有许多类似之处,但少了在打开和关闭管道时的复杂性。但使用消息队列并未解决我们在使用命名管道时遇到的问题,比如管道满时的阻塞问题。

与命名管道相比,消息队列的优势在于,它独立于发送和接收进程而存在,这消除了在同步命名管道的打开和关闭时可能产生的一些困难。

1.19、什么是进程池

进程池的作用是在多个客户端并发请求时提高服务器的处理效率。

1.20、进程之间通信的途径有哪些?

进程间通讯方式有:管道,信号,信号量,消息队列,共享内存,套接字共六种。

1.21、产生死锁的原因是什么?

系统资源有限。

进程推进顺序不合理。

1.22、进程和线程有什么区别?

进程是资源分配的最小单位。

线程是程序执行的最小单位,

五、网络编程

5.1、TCP、UDP的区别

TCP --> 传输控制协议,提供面向对象连接、可靠的字节流服务。当客户端和服务器交换数据前,必须先在双方之间建立一个TCP连接、之后才能传输数据。

UDP --> 用户数据报协议,是一个简单的面向数据报的运算层协议。UDP不提供可靠性,它是把应用程序传给IP层的数据报发送出去,但是并不能保证它们能到达目的地。

TCP<–>UDP
TCP是面向连接UDP面向无连接
UDP程序结构简单
TCP是面向字节流UDP是基于数据报
TCP保证数据正确性UDP可能丢包
TCP保证数据顺序到达UDP不保证数据到达

4.5、TCP、UDP的优缺点

TCP优点:可靠稳定

TCP的可靠体现在TCP在传输数据之前,会有三次握手来建立连接,而且在数据传递时,有确认、窗口、重传、阻塞控制机制,在数据传完之后,还会断开来连接用来节约系统资源。

TCP缺点:慢、效率低、占用系统资源高、容易被攻击

在传递数据之前要建立连接,这会消耗时间,而且在数据传递时,确认机制、重传机制、阻塞机制等会消耗大量时间,而且每台设备上维护所有的传递连接。

UDP优点:快,比TCP稍安全

UDP没有TCP拥有各种机制,是一种无状态的传输协议,所以传输数据非常快,没有TCP整型机制,被攻击的机会就少一些,但也是无法避免被攻击。

UDP缺点:不可靠、不稳定

因为没有TCP的这些机制,UDP在传输数据时,如果网络质量不好,就会容易丢包,造成数据的缺失。

4.5、TCP、UDP适用场景

TCP:传输一些对信号完整性,信号质量有要求的信息。

UDP:对网络通信质量要求不高时,要求网络通信速度要快的场景。

4.5、TCP为什么是可靠连接

因为TCP传输的数据满足3大条件,不丢失,不重复,按顺序到达。

5.6、OSI典型网络模型 ★★★

5.7、三次握手、四次挥手

1)、三次握手过程

  • 第一次握手:建立连接时,客户端发送syn包(syn=x)到服务器,并进入SYN_SENT状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。
  • 第二次握手:服务器收到syn包,必须确认客户的SYN(ack=x+1),同时自己也发送一个SYN包(syn=y),即SYN+ACK包,此时服务器进入SYN_RECV状态;
  • 第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=y+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。

TCP/IP建立连接是三次握手过程:

第一次:建立连接时,客户端向服务器发送连接请求,进入SYN_END状态,并等待服务器确认。

第二次:服务器收到客户端连接请求,并向客户端发送允许连接应答,进入SYN_RECV状态。

第三次:客户端收到服务器允许连接应答,并向服务器发送确认连接,此时客户端和服务器进入通信状态,三次握手完成。

2)、四次挥手过程

  • 1.客户端进程发出连接释放报文,并且停止发送数据。释放数据报文首部,FIN=1,其序列号为seq=u(等于前面已经传送过来的数据的最后一个字节的序号加1),此时,客户端进入FIN-WAIT-1(终止等待1)状态。 TCP规定,FIN报文段即使不携带数据,也要消耗一个序号。
  • 2.服务器收到连接释放报文,发出确认报文,ACK=1,ack=u+1,并且带上自己的序列号seq=v,此时,服务端就进入了CLOSE-WAIT(关闭等待)状态。TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间。
  • 3.客户端收到服务器的确认请求后,此时,客户端就进入FIN-WAIT-2(终止等待2)状态,等待服务器发送连接释放报文(在这之前还需要接受服务器发送的最后的数据)。
  • 4.服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,FIN=1,ack=u+1,由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为seq=w,此时,服务器就进入了LAST-ACK(最后确认)状态,等待客户端的确认。

[collapse status=“false” title=“常见面试题:”]

【问题1】为什么连接的时候是三次握手,关闭的时候却是四次握手? ★★★

答:三次握手时,服务器同时把ACK和SYN放在一起发送到了客户端那里。

四次挥手时,当收到对方的 FIN 报文时,仅仅表示对方不再发送数据了但是还能接收数据,己方是否现在关闭发送数据通道,需要上层应用来决定,因此,己方 ACK 和 FIN 一般都会分开发送。

【问题2】为什么客户端最后还要等待2MSL?

答:客户端需要保证最后一次发送的ACK报文到服务器,如果服务器未收到,可以请求客户端重发,这样客户端还有时间再发,重启2MSL计时。

【问题3】为什么不能用两次握手进行连接?

答:3次握手完成两个重要的功能,既要双方做好发送数据的准备工作(双方都知道彼此已准备好),也要允许双方就初始序列号进行协商,这个序列号在握手过程中被发送和确认。

【问题4】如果已经建立了连接,但是客户端突然出现故障了怎么办?

TCP还设有一个保活计时器,显然,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75秒钟发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。

[/collapse]

5.8、常见网络协议

TCP/IP协议

NetBEUI

IPX/SPX协议

5.9、处理粘包问题

解决粘包问题: 就是转换成发送数据和接收数据的格式,

发送数据: 发送数据,先发送数据的长度,然后在发送真实数据的字节数;

接收数据: 接收真实数据的长度,然后在安置字节长度接收数据;

5.10、ip地址分了多少类

A类:0 ~ 127.255.255.255
B类:128 ~ 191.255.255.255
C类:192 ~ 223.255.255.255
D类:224 ~ 239.255.255.255
E类:240 ~ 255.255.255.255

六、C++

最喜欢问的莫过于strlen与sizeof的区别、explicit关键字、mutable关键字、指针和引用、public、protected、private三者在继承情况下的一些访问权限、菱形继承、友元函数等。这些随便一本基础的C++书籍都会讲到。

6.1、构造和析构的作用

收集整理了一份《2024年最新物联网嵌入式全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升的朋友。
img
img

如果你需要这些资料,可以戳这里获取

需要这些体系化资料的朋友,可以加我V获取:vip1024c (备注嵌入式)

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人

都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

双方都知道彼此已准备好),也要允许双方就初始序列号进行协商,这个序列号在握手过程中被发送和确认。

【问题4】如果已经建立了连接,但是客户端突然出现故障了怎么办?

TCP还设有一个保活计时器,显然,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75秒钟发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。

[/collapse]

5.8、常见网络协议

TCP/IP协议

NetBEUI

IPX/SPX协议

5.9、处理粘包问题

解决粘包问题: 就是转换成发送数据和接收数据的格式,

发送数据: 发送数据,先发送数据的长度,然后在发送真实数据的字节数;

接收数据: 接收真实数据的长度,然后在安置字节长度接收数据;

5.10、ip地址分了多少类

A类:0 ~ 127.255.255.255
B类:128 ~ 191.255.255.255
C类:192 ~ 223.255.255.255
D类:224 ~ 239.255.255.255
E类:240 ~ 255.255.255.255

六、C++

最喜欢问的莫过于strlen与sizeof的区别、explicit关键字、mutable关键字、指针和引用、public、protected、private三者在继承情况下的一些访问权限、菱形继承、友元函数等。这些随便一本基础的C++书籍都会讲到。

6.1、构造和析构的作用

收集整理了一份《2024年最新物联网嵌入式全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升的朋友。
[外链图片转存中…(img-zAEDoYJI-1715803855184)]
[外链图片转存中…(img-WcdO1j2L-1715803855184)]

如果你需要这些资料,可以戳这里获取

需要这些体系化资料的朋友,可以加我V获取:vip1024c (备注嵌入式)

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人

都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 32
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值