ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

9.10日面试遇到问题总结

9.10日面试遇到问题总结 1.简历里面的处理400mb/s的数据是瞬时的还是普遍的400mb/s还是很恐怖的几秒钟就1个G了你是怎么处理这个问题的你们的频谱设备的屏幕能显示多少呢400 MB/s 主要是高数据率场景下测试得到的接收吞吐量主要用于体现系统面对的峰值数据压力并不是所有工作模式下都持续保持这个速率实际数据率会根据设备采样率、带宽和工作模式变化。 “我们没有把所有原始 IQ 数据直接交给 UI 或者无限制地存到内存里。接收线程首先负责 UDP 数据接收然后按照包序号进行排序和组帧完整的数据帧进入应用层有限缓冲区。之后根据实际显示需求进行抽取把处理后的数据通过信号槽传给 UI 线程绘制。这样接收、数据处理和 UI 显示是分开的 因为原始数据量远远超过屏幕实际能够表达的信息量。比如一个波形窗口横向只有有限的像素点把大量采样点全部绘制没有实际意义反而会增加 CPU 和 UI 压力。所以我们在数据处理阶段根据显示窗口进行抽取只把当前显示需要的数据传给 UI。 具体点数取决于当时的显示窗口分辨率和时间范围我不想在这里给一个没有实际依据的数字。我们实际采用的是按照显示窗口进行抽取核心原则是让需要绘制的数据量和屏幕实际显示能力匹配而不是把原始 400 MB/s 数据全部送到 UI。400 MB/s 主要是我们在高数据率场景下测试得到的接收吞吐量更多是描述系统需要面对的峰值数据压力并不是说设备在所有情况下都会持续以 400 MB/s 满速运行。实际数据率会根据设备的采样率、带宽以及当前工作模式变化我们的核心思路不是把 400 MB/s 的原始 IQ 数据全部保存下来而是数据到达后进行分包、重组和必要的数据处理然后只把最终需要展示的数据传给 UI。面对高吞吐数据我们没有让 UI 线程直接处理原始数据。接收线程负责 UDP 数据接收、按包序号进行排序和组帧把完整的一帧 IQ 数据放入应用层缓冲区之后根据显示需求进行抽取降低需要送给 UI 的数据量最后通过 Qt 信号槽把处理后的数据传给 UI 线程进行波形绘制。这样网络接收、数据处理和 UI 显示是分开的避免大量原始数据直接进入 UI 导致界面卡顿。具体显示多少点要根据当时设备的显示分辨率和我们波形显示窗口的时间范围确定我这边不想直接报一个没有实际依据的数字。我们的处理思路是根据当前显示窗口的像素宽度进行抽取因为屏幕横向实际上只有有限的像素点所以没有必要把 400 MB/s 的所有原始采样点全部绘制出来因为采集端的数据主要是原始 IQ 数据它的价值不仅仅是实时显示还可能用于后续频谱分析、信号处理或者数据记录。所以采集端需要保证高吞吐数据能够完整、连续地进入应用层。显示只是其中一个消费者并不意味着所有原始数据都需要实时绘制。所以我们并不是无限制地把原始数据堆在内存里。应用层缓冲区主要是为了应对网络接收和后续处理之间短时间的速率差异属于有限缓冲而不是长期存储。数据处理完成后就会继续被消费。对于实时显示我们又会先进行抽取只保留当前显示窗口需要的数据因此不会因为 400 MB/s 的输入速率就把几秒钟的数据全部长期堆积在内存中400MB/s 是 FPGA 通过udp发给上位机的IQ 数据的瞬时峰值速率不是持续稳定的平均流量正常的IQ数据量应该是40兆400mb/s是因为硬件一次扫频就是频谱设备在一段连续频率区间从起始频率逐步扫描到终止频率在每个频点采集无线电信号短时间内高速吐出 IQ 原始采样数据瞬时带宽带宽是单位时间能够传输的数据量代表传输通道的数据吞吐上限。我们项目 400MB/s 就是 UDP 传输瞬时带宽达到这个水平如果直接全部绘图、存盘上位机会内存打满、卡顿。 处理方案区分 IQ 时域和频谱模式按需解析不会保存全部原始大数据。 界面绘图点数受屏幕像素限制最终送到 Qt 绘图只有几千个点仅几十 KB保证 UI 流畅。原始大数据只在缓冲区短暂存放旧数据直接覆盖不会长期保存。①独立 UDP 子线程专门接收报文预分配大缓冲区我们一次只会接收在业务设置的这个缓冲区接收一帧数据下一次新扫频的数据过来直接覆盖缓冲区里上一帧的旧数据不会缓存多帧。所以不需要 400MB 的内存。调大 socket 内核缓冲区减少丢包②做降采样抽帧不把全部原始采样交给绘图paint 函数区间取最大值丢弃冗余帧③区分 IQ 时域和频谱模式按需解析不会保存全部原始大数据。 界面绘图点数受屏幕像素限制最终送到 Qt 绘图只有几千个点仅几十 KB保证 UI 流畅。原始大数据只在缓冲区短暂存放旧数据直接覆盖不会长期保存。我们上位机软件在用户配置扫频参数的时候会提前校验如果预估单帧数据会超过 40MB就自动拆分频段分多次扫频保证单帧不会超过 40MB 缓冲区上限防止溢出。正常情况下我们做参数校验不会出现溢出。极端场景下来不及处理新数据包会丢弃打上丢包标记通知设备重扫。2.你们使用的是udp你们是怎么来降低丢包的概率的网卡收到 UDP 数据包硬件通过中断通知操作系统内核把数据包先放到 socket 的内核接收缓冲区排队。我们的上位机接收线程调用 recvfrom ()从内核缓冲区把数据包拷贝到我们用户态 40MB 业务环形缓冲区。 瞬时流量爆发的时候内核缓冲区充当 “临时蓄水池”。如果没有调大大量 UDP 小包瞬间涌入内核缓冲区很快填满新来的包直接丢弃调大之后内核可以短暂缓存更多报文给应用线程争取时间去读取从而降低丢包概率。这是我们减少 UDP 丢包的手段之一调大 socket 内核接收缓冲区作为临时蓄水池应对瞬时流量尖峰给应用线程留出读取数据的时间避免报文直接在内核层面被丢弃。 除此之外我们还有其他配套丢包处理方案①调大 socket 内核接收缓冲区缓存瞬间涌入的 UDP 小包减少内核直接丢包②业务层开辟 40MB 环形缓冲区接收线程把 recvfrom 读到的包存入按包序号重组拼接完整一帧③每个 UDP 数据包携带序列号接收端检测是否出现丢包一旦检测丢包向上层上报下发指令让 FPGA 重新执行一次扫频重传这一帧分段数据④上位机提前做参数校验超大频段自动拆分成多段扫频控制单帧大小避免一次性超大流量冲击网卡。2.你说你是通过给UDP到的包进行排序来确认包的顺序的请问具体是怎么实现的udp有哪个字段可以确定包比如时间戳什么的。UDP 原生协议头没有序列号我们在业务载荷前面自定义包头自己添加包序列号 seq。 FPGA 打包时给每个 UDP 包写入 seq 序号、帧编号、一帧总包数量。上位机收到包解析出自定义包头里的 seq根据序列号在环形缓冲区对应位置存放数据包完成重组。 接收完成后检查序列号是否连续检测丢包一旦丢包通知设备重扫。不用时间戳排序时间戳不能用来恢复数据包顺序。缓冲区底层是一块预先 malloc 的 40MB 连续一维数组整体封装成环形缓冲区。 因为 UDP 包会乱序到达不能简单 FIFO。我们依靠包里面的 seq 序列号计算对应的字节偏移直接写入数组对应位置同时维护一个标记数组记录每个 seq 包是否收到用来检测丢包。环形缓冲区的作用是复用这块内存新的一帧到来直接覆盖旧帧。4.你说为了给udp到的包设置了buffer具体是怎么实现的5.屏幕上显示的是多少数据量的数据6.知不知道udp和tcp的区别既然你们的业务需要处理丢包情况为什么不直接使用tcp协议拥塞控制的意思是一旦网络有轻微丢包就会降低发送窗口压低发包速率我们这个项目需要短时间爆发式发送大量数据包TCP 容易被限流传输一帧耗时变长。我们场景是短时间一次性推送一整帧几十 MB 的 IQ 数据追求瞬时高速发包。TCP 拥塞控制会限制发包速度。当瞬间大量数据发送TCP 检测到轻微丢包就主动降速40MB 的数据发送时间会被拉长达不到高速传输需求TCP 协议栈本身开销更大频繁的 ACK 报文会占用网卡带宽拉低最大吞吐我们的业务场景可以自己做简单的丢包处理包带自定义 seq 序号检测丢包之后直接通知设备重扫整帧。 一次扫频是完整的一帧一旦检测丢包直接重发整帧不需要 TCP 那种精细的单包重传。 权衡下来UDP 在 FPGA 端实现简单发包速率高丢包由我们业务层检测 重扫机制处理更适合频谱仪这种高速批量传输场景。7.如果说在实际开发中给你一个你从来没有接触过的qt业务让你来开发你接手到这个项目打算怎么做你的具体的开发流程是什么①需求调研与熟悉代码先看懂业务需求文档明确功能、输入输出、测试指标然后搭建编译环境跑通现有工程理解整体架构、模块划分、类之间的关系看懂已有数据流转比如数据接收、解析、绘图模块。梳理信号槽、多线程的边界重点区分 UI 主线程和工作线程防止 UI 阻塞。②方案设计梳理新功能的数据流确定新代码放在哪个模块明确和原有模块的交互接口考虑边界场景比如参数校验、异常处理、内存保护。 Qt 项目重点注意耗时操作不能放在 UI 主线程放到子线程通过信号槽把结果传回 UI还要考虑绘图性能、大数据降采样、缓冲区溢出等问题。③编码开发先写底层基础逻辑和接口再写 UI 界面尽量复用项目已有工具类、数据结构严格区分 UI 业务和数据处理逻辑减少耦合。开发过程写日志方便排查。④单元自测 联调写完模块先单元自测再和后端 FPGA 设备联调测试正常场景、边界场景超大扫描范围、网络波动、断连重点测试大数据流量尖峰、缓冲区溢出、丢包重扫场景最后做 UI 界面测试检查绘图、交互是否流畅。⑤收尾整理注释提交代码提交测试修复 bug。第一步先读懂需求文档搭建环境跑通工程熟悉项目架构、模块划分、线程模型与数据流转第二步做方案设计确定接口和模块划分重点保证耗时操作放在子线程不阻塞 Qt 主线程处理好边界异常第三步编码实现复用项目现有工具模块分离 UI 与数据逻辑第四步自测再和硬件联调测试正常场景、网络波动、大流量边界场景 最后修复 bug提交代码。8.C的内存管理是什么C 语言没有垃圾回收内存由程序员手动管理。内存分为栈、全局静态区、堆、代码段。 栈编译器自动分配释放局部变量容量小堆手动管理通过 malloc、calloc、realloc 申请free 释放用完必须释放防止内存泄漏。 malloc 得到的内存不会自动清零calloc 会初始化为 0。使用完不 free 造成内存泄漏free 之后继续使用会出现野指针。我们项目 40MB 环形缓冲区就是 malloc 在堆上分配。9.你的整个高并发服务器项目的实现逻辑是什么10.你不是科班计算机的呢你是在哪里学习的这些我是通过线上网课自学起步的B 站跟着课程学习 C 语言、数据结构。学完之后权衡方向决定专注 C边听课边敲代码代码都提交到 Gitee。后面发现只听课理解不够深入又读侯捷老师的 C 书籍同时参考 CSDN 技术博客自己也写博客复盘知识点。 语言基础打好后继续学习操作系统、计算机网络、Linux 系统编程。学网络编程后发现简单通信无法支撑多用户并发于是研读 muduo 库源码动手实现高并发服务器项目。11.你的高并发服务器项目是为什么想到会做这个呢代码从始至终是你自己手搓的还是说会借鉴一些别的学习网络编程的时候我写了简单 socket 程序但只能单连接无法处理并发。于是想学习高性能服务器的实现了解到 muduo 库。 项目思路借鉴 muduo 的 Reactor 模型设计核心代码是自己从零手写不是直接复制源码。参考开源项目的优秀架构是开发中很常用的方式我自己实现事件循环、epoll 监听、收发缓冲区、粘包处理等逻辑过程中独立调试 bug代码放到 Gitee同时写博客总结踩坑点。12.你怎么看现在ai盛行对我们程序员来说是怎么样的你有没有用ai实现过一些脚本我觉得 AI 是程序员的辅助工具不会取代程序员。AI 可以快速写模板代码、简单脚本减少重复工作但 AI 代码经常缺少边界处理存在隐藏 bug必须人工审核自测。 我有用 AI 写过一些简单的 shell 测试脚本。不过我一定会读懂代码逻辑验证正确性。项目里的核心底层逻辑都是我自己独立编码实现的。我用 AI 辅助写过两类 shell 脚本。一类是日志处理脚本自动筛选、统计日志里网络异常报错方便定位 bug另一类是简易并发测试脚本批量启动客户端连接服务器做简单并发测试。这些只是辅助测试工具项目核心代码是我自己写的。14.扫描范围怎么确定频谱设备作用是什么扫描范围由用户在上位机软件填写起始频率、终止频率、分辨率带宽等参数软件通过网络下发参数给 FPGA 硬件硬件按照这个区间执行扫频设置的频段范围越大采集采样点越多单帧数据量越大。 频谱设备作用捕获空间中的无线电电磁波信号。硬件采集原始 IQ 信号可以直接上传 IQ 采样数据也可以在 FPGA 内部做 FFT 快速傅里叶变换算出各个频点信号功率输出频谱数据。 我们 Qt 上位机接收数据绘制频谱曲线实现信号峰值检索、数据存储用于电磁环境监测、无线信号排查。17.如果给了你offer你打算在去公司工作前做什么如果拿到 offer入职前我会巩固 C、Linux、网络编程这些基础复习 Qt、数据库等项目用到的技术复盘我之前的项目梳理清楚项目原理了解公司业务同时保持算法刷题。争取入职之后可以快速上手业务尽快投入开发。18.你平常用的两个ai的区别是什么我用 AI 辅助写过两类 shell 脚本。一类是日志处理脚本自动筛选、统计日志里网络异常报错方便定位 bug另一类是简易并发测试脚本批量启动客户端连接服务器做简单并发测试。这些只是辅助测试工具项目核心代码是我自己写的。成为一个独立的人究竟要吃多少苦。----------2026.9.11 16:26
返回列表