面试真题 | TPLINK嵌入式提前批[20240803]

1.TCP和UDP的区别

TCP与UDP的区别

1. 可靠性

  • TCP:是一种面向连接的、可靠的、基于字节流的传输层通信协议。TCP通过确认和重传机制来保证数据的可靠性传输,即使在网络拥堵或发生错误时,也能确保数据包的正确送达。
  • UDP:是一种无连接的、不可靠的传输层协议。它不提供任何形式的确认或重传机制,因此无法保证数据包的完整性和顺序性。UDP适用于对实时性要求高且可以容忍数据丢失的应用场景,如视频流、实时游戏等。

2. 连接管理

  • TCP:在数据传输之前,需要通过三次握手建立连接,并在数据传输结束后通过四次挥手来关闭连接。这种连接管理机制增加了额外的开销,但确保了数据传输的可靠性。
  • UDP:没有建立连接的过程,每个UDP数据包都是独立发送的,无需事先建立连接,也无需在发送后关闭连接。这减少了网络延迟,但牺牲了可靠性。

3. 头部开销

  • TCP:头部较大,通常包含20字节的固定部分和一些可选字段,用于实现复杂的控制功能,如序列号、确认号、窗口大小等。
  • UDP:头部较小,只有8字节,包含源端口、目的端口、长度和校验和,使得UDP传输效率更高,但功能相对简单。

4. 流量控制和拥塞控制

  • TCP:支持流量控制和拥塞控制机制,通过滑动窗口和拥塞窗口来动态调整发送速率,避免网络拥塞。
  • UDP:不提供流量控制和拥塞控制功能,发送方以恒定速率发送数据,不考虑网络的实际状况。

追问

问题1:TCP的三次握手过程是怎样的?

答案:TCP的三次握手过程如下:

  1. SYN包:客户端发送一个带有SYN标志的数据包给服务端,并附带一个随机生成的序列号(seq=x),表示请求建立连接。
  2. SYN+ACK包:服务端收到SYN包后,会回复一个带有SYN和ACK标志的数据包给客户端,确认号为客户端的序列号加1(ack=x+1),并附带一个服务端自己的序列号(seq=y)。
  3. ACK包:客户端收到服务端的SYN+ACK包后,会发送一个带有ACK标志的数据包给服务端,确认号为服务端的序列号加1(ack=y+1)。此时,TCP连接建立成功。

问题2:为什么UDP比TCP更适合实时应用?

答案:UDP比TCP更适合实时应用的原因主要有以下几点:

  • 无连接特性:UDP无需建立连接,减少了网络延迟。
  • 头部开销小:UDP头部只有8字节,相比TCP的20字节(不含选项)或更多,减少了处理时间。
  • 简单高效:UDP不提供复杂的控制机制,如确认、重传、流量控制等,这使得UDP在处理大量数据时更加高效。
  • 容忍丢包:在实时应用中,如视频流、音频通话等,一定程度的丢包是可以接受的,UDP的不可靠性反而成为其优势,因为它不会因为尝试重传丢失的数据包而引入额外的延迟。

这些问题和答案不仅展示了TCP和UDP的核心区别,还深入探讨了它们各自的特性和应用场景,有助于面试官全面了解你的网络协议知识。

2.static关键字的作用

static关键字在C语言中的作用

  1. 静态局部变量:在函数内部定义的静态局部变量只会被初始化一次,之后即使函数被多次调用,该变量的值也会保持不变,直到程序结束。这与自动(auto)局部变量不同,后者在每次函数调用时都会重新初始化。

  2. 静态全局变量:在全局变量前加上static修饰符,会使该变量的作用域限制在定义它的文件内,即该变量成为内部链接(internal linkage)的,不能被其他文件通过extern声明来访问。

  3. 静态函数:将函数声明为static,该函数的作用域将被限制在定义它的文件内,成为内部链接的,其他文件无法链接到该函数。

追问

问题1:C语言中静态局部变量和非静态局部变量的主要区别是什么?

答案:静态局部变量只会被初始化一次,并在函数调用之间保持其值不变,直到程序结束。而非静态局部变量(自动变量)在每次函数调用时都会重新初始化。

问题2:为什么有时候需要在全局变量前加static

答案:在全局变量前加static是为了限制该变量的作用域,使其只在定义它的文件内部可见和可访问,避免命名冲突和不必要的外部链接。

问题3:静态函数和非静态函数的主要区别是什么?

答案:静态函数的作用域被限制在定义它的文件内,其他文件无法访问该函数。这有助于封装和隐藏实现细节,减少全局命名空间的污染。非静态函数(默认情况下)可以被其他文件通过extern声明来访问。

问题4:请给出一个C语言中使用静态局部变量的例子。

答案

#include <stdio.h>

void function() {
    static int count = 0; // 静态局部变量
    printf("Function called %d times\n", ++count);
}

int main() {
    function(); // 输出: Function called 1 times
    function(); // 输出: Function called 2 times
    return 0;
}

在这个例子中,count是一个静态局部变量,它在function函数第一次被调用时被初始化为0,并在之后的函数调用中保持其值,直到程序结束。

3.进程间的通信方式

在面试中,当被问到进程间通信(Inter-Process Communication, IPC)的方式时,一个全面的回答应该涵盖多种常见的IPC机制,并简要解释每种机制的基本原理、使用场景以及优缺点。以下是一个较为完善的回答示例,并附加了几个相关问题及其答案。

完美回答示例

进程间通信是操作系统中允许不同进程或同一进程的不同线程间进行数据交换或共享的机制。常见的IPC方式包括:

  1. 管道(Pipes)

    • 基本原理:管道是一种最基本的IPC机制,用于连接一个进程的输出到另一个进程的输入。有匿名管道和命名管道(FIFO)两种。
    • 使用场景:适用于父子进程或兄弟进程间的单向数据流。
    • 优缺点:简单,但只能用于具有亲缘关系的进程间通信,且数据是单向流动的。
  2. 消息队列(Message Queues)

    • 基本原理:消息队列是消息的链接列表,存放在内核中并由消息队列标识符标识。消息队列允许一个或多个进程向它写入或从中读取消息。
    • 使用场景:适用于不同进程间的异步通信。
    • 优缺点:消息队列独立于发送和接收进程,解决了同步问题,但可能会因为消息过多而消耗大量内存。
  3. 信号量(Semaphores)

    • 基本原理:信号量是一个计数器,用于控制多个进程对共享资源的访问。
    • 使用场景:主要用于进程间的同步,而非数据交换。
    • 优缺点:能有效解决进程间的同步问题,但本身不传输数据。
  4. 共享内存(Shared Memory)

    • 基本原理:允许两个或多个进程共享一块给定的存储区。这块内存由操作系统分配,并可以被两个或多个进程映射到它们的地址空间中。
    • 使用场景:适合大量数据的快速传输。
    • 优缺点:速度最快,但需要额外的同步机制来避免数据冲突。
  5. 套接字(Sockets)

    • 基本原理:套接字是支持TCP/IP协议的网络通信的基本操作单元,它是网络通信的端点。
    • 使用场景:不仅限于本机进程间通信,还支持跨网络的不同主机间的进程通信。
    • 优缺点:灵活性强,支持复杂的网络通信协议,但相对于其他IPC机制,其开销较大。

追问

问题1:在Linux系统中,管道和命名管道的主要区别是什么?

  • 答案:管道是半双工的,数据只能单向流动,且主要用于具有亲缘关系的进程间通信;而命名管道(FIFO)允许无亲缘关系的进程间通信,且可以双向传输数据。

问题2:为什么在使用共享内存进行进程间通信时,通常需要结合信号量或互斥锁?

  • 答案:因为共享内存允许多个进程同时访问同一块内存区域,这可能导致数据冲突或不一致。信号量或互斥锁等同步机制可以用来控制对共享内存的访问,确保数据的一致性和完整性。

问题3:套接字编程中,TCP和UDP的主要区别是什么?

  • 答案:TCP是面向连接的协议,提供可靠的数据传输服务,通过三次握手建立连接,确保数据的顺序性和完整性;而UDP是无连接的协议,不保证数据的顺序性、完整性或可靠性,但传输速度快,适用于对实时性要求较高但允许数据丢失的应用场景。

4.mutex的实现原理

mutex 实现原理

mutex(互斥锁)是一种同步机制,用于保护共享资源免受多个线程或进程的同时访问,从而避免数据竞争和条件竞争。在嵌入式系统中,mutex 尤其重要,因为资源(如硬件寄存器、内存等)通常非常有限且需要精确控制访问。

基本概念

  • 互斥:确保在任何给定时间内,只有一个线程或进程可以访问某个资源。
  • :用于控制对共享资源的访问权限的机制。

实现方式

mutex 的实现通常依赖于底层的操作系统或实时操作系统(RTOS)的支持。在没有操作系统的裸机环境中,可能需要手动实现或使用硬件提供的同步机制(如信号量)。

  1. 初始化:创建一个 mutex 实例,并将其状态设置为未锁定。
  2. 加锁(Lock)
    • 当线程尝试访问受保护的资源时,它首先尝试获取 mutex
    • 如果 mutex 已被另一个线程锁定,则当前线程将被阻塞,直到 mutex 被释放。
    • 如果 mutex 可用,则将其锁定,并允许当前线程继续执行。
  3. 解锁(Unlock)
    • 当线程完成对受保护资源的访问后,它会释放 mutex
    • 这允许其他被阻塞的线程尝试获取 mutex 并访问资源。

嵌入式系统中的特殊考虑

  • 响应时间:在嵌入式系统中,对资源的访问延迟可能直接影响系统的实时性能。因此,mutex 的实现需要尽可能快。
  • 资源限制:嵌入式系统的资源(如内存和CPU时间)有限,因此 mutex 的实现需要高效且占用资源少。
  • 中断:在中断服务例程(ISR)中使用 mutex 时需要特别小心,因为中断可以打断正在执行的代码,从而可能导致死锁或优先级反转等问题。

追问

问题1:在嵌入式系统中,如何确保mutex的加锁和解锁操作是原子的?

答案:在嵌入式系统中,通常依赖硬件提供的原子操作指令(如ARM的LDREX/STREX指令对)或利用RTOS提供的原子操作API来确保mutex的加锁和解锁操作是原子的。这些操作确保了在执行过程中不会被中断或并发访问所干扰。

问题2:如果嵌入式系统没有RTOS支持,如何实现mutex

答案:在没有RTOS支持的裸机环境中,可以通过禁用中断、使用硬件提供的同步机制(如信号量)或实现自旋锁来模拟mutex。自旋锁是一种简单的同步机制,它在等待锁释放时不断循环检查锁的状态,而不是被阻塞。然而,自旋锁可能不适用于需要等待较长时间的情况,因为它会消耗CPU资源。

问题3:在嵌入式系统中使用mutex时,如何避免死锁?

答案:避免死锁的关键在于确保所有线程或进程在请求多个锁时遵循相同的顺序。此外,还可以使用超时机制来限制线程等待锁的时间,一旦超时则释放已持有的锁并返回错误。此外,在设计系统时,应尽量避免不必要的锁操作,以减少死锁的风险。

5. 项目里涉及了一个环形缓冲区,讲一下如何实现的。

环形缓冲区实现

#include <stdio.h>
#include <stdbool.h>
#include <string.h>

#define BUFFER_SIZE 10

typedef struct {
    unsigned char buffer[BUFFER_SIZE];
    int head;
    int tail;
    int count;
} CircularBuffer;

// 初始化环形缓冲区
void cb_init(CircularBuffer *cb) {
    cb->head = 0;
    cb->tail = 0;
    cb->count = 0;
}

// 检查缓冲区是否满
bool cb_is_full(CircularBuffer *cb) {
    return cb->count == BUFFER_SIZE;
}

// 检查缓冲区是否为空
bool cb_is_empty(CircularBuffer *cb) {
    return cb->count == 0;
}

// 向缓冲区写入数据
bool cb_write(CircularBuffer *cb, unsigned char data) {
    if (cb_is_full(cb)) {
        return false; // 缓冲区满,无法写入
    }
    cb->buffer[cb->tail] = data;
    cb->tail = (cb->tail + 1) % BUFFER_SIZE;
    cb->count++;
    return true;
}

// 从缓冲区读取数据
bool cb_read(CircularBuffer *cb, unsigned char *data) {
    if (cb_is_empty(cb)) {
        return false; // 缓冲区空,无法读取
    }
    *data = cb->buffer[cb->head];
    cb->head = (cb->head + 1) % BUFFER_SIZE;
    cb->count--;
    return true;
}

// 示例使用
int main() {
    CircularBuffer cb;
    cb_init(&cb);

    // 写入数据
    for (int i = 0; i < BUFFER_SIZE; i++) {
        cb_write(&cb, 'A' + i);
    }

    // 尝试写入更多数据,将失败
    if (!cb_write(&cb, 'Z')) {
        printf("Buffer is full, cannot write 'Z'.\n");
    }

    // 读取数据
    unsigned char data;
    while (!cb_is_empty(&cb)) {
        cb_read(&cb, &data);
       

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

ARM/Linux嵌入式真题 文章被收录于专栏

让实战与真题助你offer满天飞!!! 每周更新!!! 励志做最全ARM/Linux嵌入式面试必考必会的题库。 励志讲清每一个知识点,找到每个问题最好的答案。 让你学懂,掌握,融会贯通。 因为技术知识工作中也会用到,所以踏实学习哦!!!

全部评论

相关推荐

oppo二面1自我介绍2本科有参加项目或者比赛吗?3展开讲解一下硕士学位论文。课题目前什么进度?现有算法缺陷是什么,用人工智能做是创新点吗,怎么想到的?需要做实物吗?这个研究是理论封存还是有实际的工程价值,有相关的项目背景吗?做项目或者科研,刚开始拿到项目时,有会给自己定更高的指标的情况吗?加工误差在实际过程中怎么解决的?4经历偏天线,从个人发展来说,你怎么看天线射频领域?5本科,硕士学习中有遇到让你挫败感的事情吗?6项目是个人做的吗,还是一个团队做的?7最近一年除了毕设,有对生活学习有什么规划吗?8有了解oppo的一些产品吗?oppo&nbsp;hr面1自我介绍2为什么应聘oppo,对oppo的了解。对射频工程师和天线工程师的看法,优先选哪个?3求职中最关心的3个因素?4对oppo产品的了解?该产品设计不错的功能是什么?区别于别的品牌优势是什么?5手表手环面向群体是什么?你手机是什么,他的优势是什么?6对于工作地点怎么考虑的?西安东莞有什么先后级吗?家人怎么考虑的?7你现在投了哪些产业,有什么排序?手上有其他offer吗?8毕业设计进度怎么样了?有数据了吗?发论文了吗,达到毕业要求了吗?9本科毕业为什么选择东南大学?10西安,南京你觉着这两个地方怎么样?东莞或者广东你来过吗?会议在广州开为什么去深圳?11放暑假了吗?课题组工作强度怎么样?对加班怎么看待?能接受的工作强度?12运动爱好?每天上班到10.还会运动?13导师接受学生提前来实习吗?14考虑读博吗,为什么?15反问【招聘岗位】产品类、AI/算法类、标准研究类、软件类、硬件类、设计类、工程技术类、米哈游、销售服务类、品牌策划类、采购类、综合职能类【工作地点】东莞、深圳、成都、上海、北京、西安、南京、重庆、武汉、杭州、海外【福利待遇】极具竞争力的薪资+制化培养体系+多样化发展机制内推链接:https://careers.oppo.com/university/oppo/campus【内推码】X9020137(后续有流程/面试时间上的问题,欢迎随时联系~)留下岗位和姓名缩写~我会帮你跟进
OPPO
|
校招
|
超多精选岗位
点赞 评论 收藏
分享
1 15 评论
分享
牛客网
牛客企业服务