嵌入式常见的面试题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 无效,不可混淆。

相关推荐
木白CPP1 小时前
DMA-Buffer内核驱动API文档
linux
zmj3203242 小时前
CAN + 以太网 + Wi-Fi + BLE + TCP/IP + MQTT +HTTP协议层级
网络·网络协议·tcp/ip
HXQ_晴天2 小时前
Linux 系统的交互式进程监控工具htop
linux·服务器·网络
南湖北漠2 小时前
记录生活中的那些小事(佚名)
网络·人工智能·计算机网络·其他·安全·生活
song8582 小时前
韦东山开发手册阅读笔记(五)
linux
M158227690552 小时前
免编程・全兼容|SG‑PLC‑Private PLC 数据采集网关 —— 打通设备数据最后一公里
网络
LIZhang20162 小时前
linux写一个脚本实时保存内存占用情况
linux·运维·服务器
发光小北2 小时前
IEC103 转 ModbusTCP 网关应用在什么场景?
网络·网络协议
IDC02-阿杰2 小时前
Windows WSL2安装Ubuntu24.04全攻略
linux·windows