嵌入式常见的面试题1

在嵌入式 Linux 应用层,使用 TCP socket 发送数据时,write()/send() 返回成功是否意味着数据已送达对端?如何确保对端应用层确实收到了数据?

考察点:TCP 协议栈缓冲区机制、可靠传输的误解、应用层确认协议。

参考答案

  • write() 成功仅表示 :数据已从用户空间拷贝到内核 TCP 发送缓冲区,且缓冲区剩余空间足够容纳此次写入。它绝不代表

    • 数据已发出网卡。

    • 数据已被对端 ACK。

    • 对端应用已调用 read() 取走数据。

  • 确保应用层收到的方法

    1. 应用层 ACK 协议:接收方在成功处理完业务数据后,主动发回一个确认消息(例如自定义的 "ACK" 包)。发送方必须等待此 ACK 才能认为传输完成。

    2. 结合 shutdown()SO_LINGER :在关闭连接前,调用 shutdown(sockfd, SHUT_WR) 发送 FIN,并配合 setsockopt(..., SO_LINGER, ...) 设置超时,确保对端关闭了连接(暗示其应用已 close(),但这仍不等同于业务处理完成)。

    3. 心跳与超时重传:对于需要高可靠性的场景(如工业控制),设计请求-响应模式,发送方带序列号,接收方按序确认,超时未收到 ACK 则重传。


在一个裸机嵌入式设备上,如何实现一个简单有效的 TCP 粘包/拆包处理逻辑?

考察点:TCP 流式传输特性理解、嵌入式协议栈内存管理。

参考答案

  • 原因:TCP 是流协议,没有消息边界,多次发送的小包可能合并到一个 TCP 段中(粘包),或一个长包被 IP 分片、TCP 分段。

  • 常用解决策略(裸机环境)

    1. 定长消息:规定每个数据包固定长度(如 128 字节),不足补零。解析时从流中逐个切分。缺点:浪费带宽。

    2. 分隔符协议 :在消息末尾添加特殊字节(如 \r\n0x00)。接收方在 lwIP 的 recv 回调中遍历缓冲区寻找分隔符。注意 :裸机环境下避免使用 strstr 等动态内存操作,应直接基于环形缓冲区状态机扫描。

    3. 头部定长 + 长度字段(最常见):定义包头结构如下:

      text

      复制代码
      struct pkt_hdr {
          uint16_t magic;  // 可选,帧头校验
          uint16_t len;    // 后续负载长度
      };

      接收处理逻辑:

      • 状态机初始为 WAIT_HEADER,累积到头部长度后解析 len,转入 WAIT_PAYLOAD

      • 累积到 len 字节后,校验通过则交给应用处理,指针回退并重新进入 WAIT_HEADER

    • lwIP 特有注意tcp_recv 回调可能一次收到多个 TCP 段,必须循环调用 pbuf_copy_partial() 或直接遍历 pbuf 链表,将数据拷入内部环形缓冲区,再触发状态机解析,避免在回调中长时间阻塞导致协议栈丢包。

嵌入式设备通过 4G 模块联网,使用 MQTT 协议与云端通信。若设备发送一个 PUBLISH 报文(QoS=1)后,在未收到 PUBACK 之前网络断开了,重连后应如何处理未确认的消息?

考察点:MQTT 协议状态机、会话保持机制。

参考答案

  • 关键依赖CONNECT 报文中的 Clean Session 标志。

    • Clean Session = 0(持久会话):

      • 服务端会为客户端保存未确认的 QoS 1/2 消息。

      • 客户端重连时,只要使用相同的 Client ID,服务端会在 CONNACK 中返回 Session Present = 1

      • 随后服务端会立即重发 之前未确认的 PUBLISH 报文给客户端,客户端应能按原 Packet ID 处理并响应 PUBACK。

    • Clean Session = 1(大多数物联网低功耗设备的默认选择):

      • 会话状态不保留,服务端在连接断开后丢弃所有未确认消息。

      • 客户端必须自行负责重传机制

        1. 在应用层实现本地存储队列(如 SPI Flash 或文件系统)。

        2. 每条 PUBLISH 消息在收到 PUBACK 前保留在队列中,标记为"未确认"。

        3. 网络恢复并重连 MQTT 后,遍历队列中所有"未确认"消息,按顺序重新 PUBLISH(使用新的 Packet ID)。


在 Linux 系统中,编写一个基于 UDP 的客户端程序,如何检测到对端服务已经崩溃(对端主机未关闭 socket,而是整机掉电)?

考察点:UDP 无连接特性与异常检测的工程方法。

参考答案

  • UDP 原生缺陷 :UDP 没有连接状态,sendto() 通常成功(只要 ARP 表有记录),不会因对端崩溃而报错。

  • 检测策略

    1. ICMP 错误报文监听(被动方式):

      • 若对端主机崩溃,当本机继续发送 UDP 数据时,若路径上的路由器或最终主机(ARP 失败)返回 ICMP Port UnreachableICMP Host Unreachable,这些错误会被内核记录在 socket 的错误队列中。

      • 应用层可通过 recvmsg() 配合 MSG_ERRQUEUE 标志获取挂起的错误,从而得知目的不可达。

      • 缺点:如果停止发送数据,将永远得不到通知。

    2. 应用层心跳协议(主动方式):

      • 客户端定期发送"心跳请求"UDP 包,对端必须回复"心跳应答"。

      • 若连续 N 次心跳未收到应答,判定对端失联。这是工程上最可靠的方法。

    3. SO_KEEPALIVE 无效性 :TCP 的 SO_KEEPALIVE 选项对 UDP 无效,不可混淆。

相关推荐
春风解人意4 小时前
从零开始学习嵌入式P32----网络基础之TCP
c语言·网络·学习·tcp/ip
虹科数字化与AR5 小时前
拓影Twyn能替代三坐标吗?AR视觉检查与精密计量的正确分工
经验分享
云絮.5 小时前
网络原理---- 网络层,数据链路层,应用层
网络
Johny_Zhao7 小时前
网络安全等级保护测评实施方案
linux·网络·人工智能·网络安全·信息安全·云计算·等保测评·系统运维·itsm
落羽的落羽8 小时前
【AI】快速理解AI应用的相关名词概念
linux·c++·人工智能·python·计算机网络·算法
刚入门的大一新生8 小时前
Linux-进程控制
linux·运维·服务器·c++
上火的金鱼妹8 小时前
K8S基础组件作用和关系整理
linux·运维·服务器·kubernetes
Vcaker8 小时前
Linux学习25-harbor私有仓库部署
linux·运维·学习
刃神太酷啦8 小时前
Redis 进阶核心:持久化 (RDB/AOF)、事务与主从复制全解析----《Hello Redis!》(5)
linux·c语言·数据库·c++·redis·缓存·bootstrap
虹科网络安全8 小时前
使用艾体宝 IOTA 10 CORE+ 监控企业网络中的 AI 流量
网络·人工智能