核心系统工程师笔试复盘:操作系统、网络与C++底层考点全解析
核心系统工程师这个岗位在校招方向里属于少数人的战争。2019年秋招季第一批笔试结束后不少准备投基础设施方向的同学在讨论区里感叹这套卷子和普通后台开发的画风完全不一样——常规后端考的是业务设计、SQL、框架理解这套卷子却把操作系统、网络协议栈、C/C内存模型和Linux排查能力放在最前面。原因也简单核心系统工程师要负责的是支撑大规模业务的底层组件这类系统出了问题不会给你重启一下的机会所以笔试考察的是候选人能不能把机器水平挖到底。这篇文章不逐题复述原题而是把这份卷子透出来的能力要求、高频考点和一套可落地的复习路径完整拆开。不管你是打算投核心系统/基础设施方向的应届生还是已经工作、想补一补底层功底的开发这份复盘应该都用得上。1. 拿到试卷的第一反应这份卷子到底想筛出什么样的人1.1 题目结构给人的直观信号先聊整体。核心系统工程师和普通后端开发的笔试题最大的区别不在难度而在考察重心的分配。普通后端可能算法题占大头再来一两道系统设计或SQL但这套卷子的风格是操作系统、计算机网络、C/C语言特性、Linux系统编程占了大半壁江山算法题有但数量不多更像压轴。我按常见考察模块整理了一张分布表参照这个画风去准备基本不会跑偏考察模块常见占比典型题型操作系统25%左右选择、简答、场景分析计算机网络20%左右选择、简答、状态流程题C/C与内存模型20%左右读代码写输出、选择Linux与系统编程15%左右概念选择、命令场景题数据结构与算法15%-20%编码题、复杂度分析数学/逻辑/专业素养少量选择或开放题这个比例说明一个事实这个岗位要的不是算法竞赛选手而是系统底层功底扎实、出了问题能快速定位的人。校招不要求你有几年生产环境的经验但要求你对基础理论有接近肌肉记忆的熟练度。比如问你一个进程和线程的区别这不是背定义而是要你能马上说出它们各自共享哪些资源、隔离哪些资源、在多线程模型里会带来什么同步问题。1.2 从岗位定位倒推出题人的心理核心系统工程师往细了说可能分分布式存储、消息队列、数据库内核、网络基础组件、大规模集群调度等方向但共性是都要和操作系统、网络、高并发、资源管理打交道。出题人坐在考场另一端他要判断的不是你会不会写业务CRUD而是你敢不敢碰别人不敢碰的底层代码。所以你会看到这套卷子里几乎没有框架题、没有Spring、没有中间件配置题。取而代之的是大量关于虚拟内存、TCP状态、指针、文件描述符的题目。这不是出题人偷懒而是因为这些内容才是核心系统稳定运行的基石。一个连文件描述符泄漏都不知道怎么排查的人是不可能维护好线上高并发组件的。1.3 拿到卷子后的时间分配策略这类笔试的题量通常不小我在准备阶段总结了一套时间分配逻辑实际用下来也比较稳选择题严格控制速度。会就选不会先标记跳过每道不超过1.5分钟争取15分钟内扫完。简答题按分点作答来写。这类题通常是按点给分比如问死锁条件就写四条每条带一句解释不要展开成长篇作文。算法题留足整块的40到50分钟。先确定思路再动手宁可写得慢一点也要保证核心逻辑正确边界条件不要漏。我见过不少同学在选择题上死磕结果最后一道算法题只写了个开头。这种笔试不是高考不需要每题都拿满分抓大放小才是正确的打开方式。2. 操作系统题进程线程、死锁和虚拟内存的三板斧2.1 进程与线程一道题考出资源归属概念操作系统的选择题和简答题里几乎必有一道关于进程和线程的辨析。表面上问的是概念实际上考的是一张资源归属表。我给你列一份比较全的对照进程是资源分配的基本单位线程是CPU调度的基本单位。进程拥有独立的地址空间、文件描述符表、信号处理器、当前工作目录、用户ID等资源。同一进程内的多个线程共享上述资源但每个线程有自己的栈、程序计数器、寄存器上下文、errno和线程局部存储TLS。进程上下文切换需要切换地址空间可能涉及TLB刷新开销大线程切换不需要切地址空间但内核级线程切换仍然要进入内核态。一个容易翻车的点是线程一定比进程轻量。从资源角度看线程确实更轻但如果是多核CPU密集计算场景大量线程切换带来的缓存失效和同步开销可能让性能反而下降。笔试如果问为什么线程切换不一定更快能从缓存局部性和锁竞争两个角度回答会非常加分。笔试现场如果遇到进程和线程谁有独立栈这种题答案是两者都有自己的栈。栈属于线程执行流的一部分只是进程在单线程模型下只有一个栈多线程模型下每个线程都有独立栈这些栈都位于进程的地址空间内。2.2 死锁四个必要条件和一个计算场景死锁这块是简答题的高频区考察方式一般有两种一是直接问死锁的产生条件二是给一个系统资源分配的场景让你判断是否可能死锁。四个必要条件要背到能脱口而出互斥一个资源每次只能被一个进程使用。持有并等待进程持有至少一个资源同时在等待获取其他进程持有的资源。不可剥夺进程已经获得的资源在使用完之前不能被强行夺走。循环等待存在一个进程资源的循环等待链。笔试里判断死锁的通用思路是画资源分配图然后检查图中是否存在环。有环不一定死锁还要看同类资源数量是否大于1。比如两个进程各持有一台打印机又各自持有对方需要的磁带机同时双方都不释放这就是典型的循环等待。打破死锁的四个方向也要顺手记住破坏互斥多数资源做不到、破坏持有并等待一次性申请所有资源、破坏不可剥夺允许强占、破坏循环等待资源编号按序申请。这种题在简答里几乎就是送分题但就怕你少写一条所以建议每次复习都默写一遍。2.3 虚拟内存与页面置换算法页面置换算法是操作系统选择题里的常客也是核心系统后端排查线上内存问题时经常要回头翻的基础知识。常见的包括OPT最优置换淘汰未来最长时间不被访问的页理论最优不可实现。FIFO淘汰最先进入内存的页实现简单但存在Belady异常——分配的物理块增多缺页次数反而增加。LRU淘汰最久未被访问的页利用局部性原理性能好但需要硬件支持和额外开销。Clock第二次机会给每个页一个访问位在循环扫描时二次机会是LRU的近似简化实现。笔试常见出法给一个页面访问序列和物理块数量分别求FIFO和LRU的缺页次数。这种题没有捷径必须老实画表。我自己的做题习惯是先画一个三列表格纵轴是访问序列横轴是物理块和缺页标记每访问一页按算法更新一次过程中带上系统当前时间和状态不容易乱。一个比较隐蔽的考点是为什么LRU在工程中常用近似实现而不是精确实现因为精确LRU需要记录每个页的最后访问时间每次访问都要更新成本和复杂度都高。操作系统和时间敏感系统宁可用Clock或类LRU算法做近似。这个点如果在简答题出现能说清楚理论最优但不实际的OPT和工程实用的近似LRU之间的取舍会显得很有层次。2.4 操作系统题背后的工程关联很多同学考完问这些操作系统题和实际工作有什么关系关系大得很。你写一个高并发网络服务就涉及进程与线程模型的选择你处理CPU飙高的问题就要理解调度和上下文切换你排查内存泄漏或OOM就要知道虚拟内存、页表和回收机制。举个例子。线上一个C服务突然内存暴涨你用top看RSS很高但业务上没申请多少内存。如果没有虚拟内存和页面置换的概念你大概率不知道去查是不是产生了大量缺页、是不是用到了swap、页表碎片是否严重。所以这套卷子里的操作系统题某种程度上是现场排障能力的预演。3. 计算机网络题三次握手、滑动窗口与一个隐蔽的时间管理陷阱3.1 TCP三次握手为什么要三次而不是两次TCP的三次握手是互联网行业笔试必考的基础出题角度多种多样但核心答案是一致的三次握手能确认双方的收发能力都正常同时防止失效的连接请求导致服务器资源浪费。一次握手显然不够服务器根本不知道客户端能不能接收。两次握手的问题在于如果客户端第一次发送的SYN在网络中滞留超时后客户端重发SYN并成功建立连接但随后旧SYN又到达服务器服务器会误以为这是一个新连接请求于是分配资源并返回确认而此时客户端并不会理睬这个迟到的连接——服务器端就会产生一个悬空的、浪费资源的连接。三次握手的本质是客户端发出SYN证明客户端发送能力正常服务器回应SYNACK证明服务器收发能力都正常客户端再回ACK证明客户端接收能力正常。另外还有一个很多人忽略的点握手的每一步还携带了初始序号三次握手确保双方都知道了对方的起始序号后续数据的按序传输才有基础。笔试常考的变体是如果第三次ACK丢了会发生什么。答案服务器收不到ACK会认为自己的SYNACK没送达于是按超时重传机制重发SYNACK。客户端会继续处理并忽略重传直到连接建立完成或超时。这题不难但能考出你对TCP状态机是否真理解。3.2 滑动窗口和拥塞控制是两码事这是网络题里最容易被混淆的一对概念。滑动窗口解决的是发送方和接收方之间的速率匹配属于流量控制拥塞控制解决的是发送方和网络之间的负载匹配防止网络被过大的发送量打爆。具体来说滑动窗口大小由接收方的接收能力决定接收方通过TCP报文头部的窗口字段告知发送方我还有多大缓冲区。而拥塞控制是发送方自己维护一个拥塞窗口通过慢启动、拥塞避免、快重传、快恢复四个算法动态调整。笔试常问慢启动阶段拥塞窗口是怎么增长的答案是每收到一个ACK拥塞窗口增加一个MSS实际上是每经过一个RTT窗口翻倍呈现指数增长。当窗口达到慢启动阈值ssthresh时进入拥塞避免阶段窗口线性增长。出现丢包时如果是超时则拥塞窗口降到1个MSS、阈值减半如果是快重传收到3个重复ACK则窗口减半并进入快速恢复。我建议你复习时画一张拥塞窗口随时间变化的曲线图把慢启动、拥塞避免、快重传和快恢复的分界点标出来。这张图画明白了相关选择题基本不会错。3.3 TIME_WAIT状态和端口复用经典的生产环境大坑这道题出现的频率高到离谱因为它太贴合生产环境了。主动关闭连接的一方在发送最后一个ACK之后会进入TIME_WAIT状态持续2MSL最大报文段生存时间的两倍后才会彻底关闭。为什么要等2MSL两个原因保证最后一个ACK能到达对端。如果这个ACK丢了对端会重发FIN主动关闭方必须还在等这个重发的FIN并能重新回ACK。让本连接中所有迟到的数据包在网络中消失防止它们污染后续使用相同四元组的新连接。笔试常见延伸题高并发短连接场景下服务器出现大量TIME_WAIT怎么处理这个问题很有区分度。如果直接回答设置SO_REUSEADDR是不完整的。SO_REUSEADDR的作用是允许新的监听套接字绑定到处于TIME_WAIT状态的地址上解决的是重启服务时端口被占用的问题针对大量TIME_WAIT连接本身更有效的手段包括改用长连接、打开SO_LINGER并设置超时、调整tcp_tw_reuse等。不过要注意Linux下tcp_tw_reuse只对出站连接生效且要配合时间戳选项不能一刀切打开。实际笔试问答里能答出先判断TIME_WAIT来源是主动关闭方还是被动关闭方的人很少说出这一句会显得你很懂线上排查。主动关闭方才会产生TIME_WAIT所以在典型的短连接服务里处理大量TIME_WAIT的思路是减少主动关闭的频率也就是引导客户端复用连接。3.4 HTTP状态码里最容易记混的几个这类题看似简单但失分点很多。必会的几个200 OK请求成功。301 Moved Permanently永久重定向302 Found临时重定向。401 Unauthorized未认证403 Forbidden已认证但无权限。404 Not Found。500 Internal Server Error服务器内部错误502 Bad Gateway网关/代理收到上游无效响应503 Service Unavailable服务暂时不可用504 Gateway Timeout网关/代理超时。笔试偏爱问502和504的区别。502强调上游返回了非法响应504强调上游一直没响应。如果你在做网关相关系统这两个状态码的排查路径完全不同502要查上游应用是否崩溃、返回格式是否错误504要查上游是否阻塞、超时配置是否合理。4. C/C语言题指针、虚表和内存管理的扣分重灾区4.1 const和指针的排列组合一个都别懵C/C题里const和指针的组合是必考项而且经常以读代码写含义的形式出现。我当年备考时把这几种写法整理成一张表考试时直接对照写法含义const int *p指向const int的指针p可变*p不可变int const *p同上const int *p的等价写法int *const p常量指针p不可变*p可变const int *const p指向const int的常量指针p和*p都不可变这里有个核心思路const修饰的是它左边最近的那个类型标识符。const int *p中const修饰int所以p所指向的int值是常量int *const p中const修饰*也就是指针本身所以p是常量。笔试还会考一个迷惑项把const int *p赋值给int *合法吗不合法因为这会允许通过int *修改const数据破坏了const语义。反过来int *赋值给const int *是合法的这是在增加约束。这类题把C的类型系统是否严格这一问题隐藏得很深。4.2 new/malloc、delete/free不能乱配对这里有个很容易被忽视的点new和malloc的底层都涉及堆内存分配但语义完全不同。malloc是C标准库函数分配指定字节数返回void*失败返回NULL不调用构造函数。new是C操作符分配内存并调用构造函数返回类型化指针失败抛bad_alloc异常。free释放内存不调用析构函数delete释放内存并调用析构函数。配对规则malloc配freenew配deletenew[]配delete[]。交叉使用是未定义行为——用free释放new出来的对象不会调用析构函数可能导致资源泄漏用delete释放malloc分配的内存可能导致堆管理结构错乱。笔试常问的一个点是new[]和delete[]为什么要配对。因为new[]在分配数组时可能在数组头部额外存储元素个数delete[]需要这个信息来逐个调用析构函数。如果对new[]出来的数组用delete而不是delete[]编译器不知道要析构多少个对象行为不可预测。现代C项目里裸指针应该尽量被智能指针替代。shared_ptr用引用计数管理多个所有者unique_ptr保证独占所有权weak_ptr解决shared_ptr之间的循环引用。笔试可能会问make_shared和直接new shared_ptr的区别make_shared只分配一次内存控制块和对象放在同一块内存里效率更高异常安全性更好。4.3 虚函数机制与构造析构顺序C的虚函数是笔试里颇具区分度的考点。理解虚函数必须理解vptr和vtable每个含有虚函数的类都有一个虚函数表vtable里面按声明顺序存放虚函数地址。每个对象内部有一个虚指针vptr指向所属类的vtablevptr在构造函数中初始化。调用虚函数时通过vptr间接跳转实现运行时多态。一个容易让人懵的笔试代码在构造函数或析构函数中调用虚函数会调用哪一个版本答案是当前正在构造/析构的那个类所对应的版本而不是最终的派生类版本。原因很简单基类构造时派生类成员还没初始化派生类vptr也还没设置此时调用派生类的虚函数会有风险所以C选择在基类构造阶段把虚函数调用绑定到当前类的实现上。构造析构顺序也是必考:Derived d;构造顺序是先基类构造、再成员对象构造、最后派生类自身构造析构顺序完全相反先派生类析构、再成员对象析构、最后基类析构。这个顺序决定了为什么基类析构函数必须声明为虚函数——否则通过基类指针delete派生类对象时只会调用基类析构派生类资源无法释放造成泄漏。4.4 sizeof和内存对齐一眼看出你是不是老手sizeof看似简单但结构体内存对齐题的错误率一直很高。规则是每个成员按自身对齐值对齐到相应偏移。结构体的总大小是最大对齐值的整数倍。实际编译器可能受#pragma pack影响。举一个经典例子struct A { char c; // 偏移01字节 int i; // 对齐4偏移4~7 char d; // 偏移81字节 }; // sizeof(A)在默认4字节对齐下 12char c占偏移0int i需要对齐到4的倍数所以跳到偏移4占4~7char d占偏移8最后总大小要对齐到最大对齐值4的整数倍所以是12。如果把int放前面、两个char放后面sizeof就变成8。笔试如果问为什么要有内存对齐答CPU访问对齐内存更高效某些架构甚至不允许非对齐访问就可以。这个知识点虽然基础但很能体现你有没有写过底层内存相关的代码。5. Linux与系统编程文件描述符、惊群和一条完整排查链路5.1 文件描述符与fd泄漏从一道概念题到实战排查Linux这部分的笔试题目通常围绕进程和文件系统的交互展开。文件描述符fd是内核用来标识进程打开文件的整数句柄0、1、2分别对应标准输入、标准输出、标准错误。笔试会出现这样一道题一个进程最多能打开多少个文件标准答案大概分两层从用户态看受ulimit -n限制从内核态看还受/proc/sys/fs/file-max限制。实际遇到too many open files错误时第一步是查当前进程fd使用量和上限。我在运维排查阶段处理fd泄漏的典型链路是这样的# 查看进程当前打开的文件描述符数量 ls /proc/12345/fd | wc -l # 查看进程fd上限soft/hard cat /proc/12345/limits | grep open files # 查看具体打开了哪些文件找出异常 ls -l /proc/12345/fd如果ls -l显示大量指向已删除文件文件名带(deleted)标记的fd那大概率是业务代码没有关闭文件句柄。这个知识点笔试可能只考个选择题但面试聊到项目时非常容易被追问建议提前把排查命令刻在脑子里。5.2 accept惊群与epoll模型高并发组件绕不开的坎高并发网络服务是核心系统工程师的日常工作场景所以Linux部分考epoll和惊群几乎是可以预见的。惊群是指多个进程/线程同时阻塞在accept或epoll_wait上当有一个新连接到来时内核唤醒所有等待者但最终只有一个进程能成功accept其余进程白白被唤醒并重新休眠造成无谓的上下文切换开销。传统解决惊群的方案有使用SO_REUSEPORT让多个socket监听同一个端口内核按负载均衡分发连接。在epoll模型下使用EPOLLEXCLUSIVE事件标志避免多个EPOLL等待者同时唤醒。使用ngx_accept_mutex之类的锁机制在应用层保证同时只有一个进程在accept。笔试常问epoll和select/poll的区别核心差异在于对比项selectpollepoll文件描述符数量限制FD_SETSIZE无无遍历方式每次全量遍历每次全量遍历事件回调就绪通知无无有水平触发/边缘触发仅水平仅水平两者都支持内核态数据拷贝有有mmap优化面试追问到LT和ET的区别时要能解释清楚水平触发只要缓冲区还有可读数据就会持续通知边缘触发只在状态变化时通知一次。边缘触发必须配合非阻塞IO循环读取直到返回EAGAIN否则可能漏掉数据。笔试不会写代码但会把ET模式下为什么必须用非阻塞IO作为概念题来问。5.3 线上排查必会的命令组合这部分的笔试题目通常以场景方式考察给出一个故障描述问你应该用什么命令排查。我整理了最常用的一组组合top看CPU和内存整体负载按1看每核负载。free -h看物理内存和swap使用情况。ps aux看进程状态、CPU和内存占用。ss -tan或netstat -tan查看端口监听和连接状态。lsof -i :端口查看谁占用了端口。strace -p PID跟踪进程系统调用定位卡顿点。gdb -p PID调试运行中的进程抓取调用栈。笔试可能会给一个场景某个进程CPU占用接近100%问怎么排查。标准思路是先用top确认进程再用top -H -p PID看具体线程然后gdb attach抓线程栈或者用perf top看热点函数。能说出先线程后调用栈这个顺序就说明你真有排查经验而不是只会背命令。6. 算法与数据结构压轴编程题的高性价比打法6.1 LRU缓存越是经典越要掌握得精核心系统方向的笔试算法题通常不会出太偏的题目但会在经典题上做文章。LRU缓存是我见过出场率最高的一道考察点是哈希表双向链表实现O(1)的get和put。当年我总结的思路是哈希表负责O(1)定位节点。双向链表维护访问顺序最近访问的节点移到头部最久未访问的节点在尾部。容量满时淘汰尾部节点删除哈希表对应项。一个常见的笔试变体如何实现LRU面试官期待你能说清楚为什么用双向链表而不是单向链表。因为删除节点时需要同时知道它的前驱节点单向链表做不到O(1)删除。如果能随手画出插入、删除、淘汰三个核心操作的指针变化这道题就稳了。6.2 链表和字符串题目边界条件决定成败除LRU外高频算法题还包括反转链表、判断链表中是否有环、求链表中间节点、最长无重复子串等。这些题本身不难但笔试环境容易在边界条件上失分。我总结的通用解法是链表题先考虑空链表和单节点链表。凡涉及快慢指针先想清楚快指针步长会不会越界。字符串滑动窗口题注意窗口左边界移动和哈希表更新的时序。提前写好如果输入为空则返回空的防御逻辑哪怕题目没明说。笔试阅卷通常按用例打分边界条件覆盖不住即使核心逻辑对也会因为挂了测试用例被扣分。所以我在笔试时有个习惯写完代码后在草稿纸上用手工小样例走一遍特别是有没有把循环终止条件写错成死循环。6.3 二分查找的边界问题一页纸也要拆着做二分查找看起来最简单但在笔试里挂的人从来不缺。核心坑在边界细节mid的计算用(left right) / 2还是left (right - left) / 2前者在left和right都很大时可能溢出后者更安全。另一个高频坑是区间定义。建议从头到尾统一用左闭右开区间[left, right)这样代码的一致性更高def binary_search(nums, target): left, right 0, len(nums) # 左闭右开 while left right: mid left (right - left) // 2 if nums[mid] target: left mid 1 else: right mid return left if left len(nums) and nums[left] target else -1笔试变体题目包括查找第一个大于等于target的位置、查找最后一个等于target的位置。这些都可以用同一个模板只是判断条件和返回值不同。建议备考时把一套模板吃透不要一到考场就临场改逻辑。6.4 复杂度分析不只写答案还要会解释题目最后一般会要求写出时间复杂度和空间复杂度。这里的失分点不是算错而是解释不清。比如LRU的get和put都是O(1)空间复杂度O(n)这里的n是缓存容量。遇到拓扑排序或并查集也要能把为什么是O(VE)说清楚。笔试中如果还包含一个是否能用更优算法的开放题不要只看常数优化要从根本思路上说。比如排序问题O(n²)的冒泡到O(n log n)的快排不仅是提速更是改变了比较模型再往下的O(n)计数排序则是跳出了比较模型的限制利用数据本身的范围做桶拆分。这种层次递进的讨论会让面试官眼前一亮。7. 从这套卷子倒推复习路径该背的背、该练的练、该放过的放过7.1 三个必须背到肌肉记忆的知识清单基于这类笔试的考察重心我整理了三份必须背到条件反射程度的清单。操作系统清单进程和线程资源对照表。死锁四个条件及对应破除方法。FIFO/LRU/Clock置换算法的替换逻辑和缺页次数计算步骤。用户态和内核态切换、系统调用的基本流程。同步机制互斥锁、信号量、条件变量、自旋锁的应用场景。网络协议清单TCP三次握手和四次挥手的状态迁移特别是TIME_WAIT出现的位置和时长。流量控制和拥塞控制的区别。HTTP状态码分类及常见状态码含义。TCP和UDP头部结构、区别、常见应用场景。C/C清单const与指针的四种组合。new/malloc、delete/free的配对规则。虚函数、虚表、构造析构顺序。智能指针的用法和适用场景。static关键字在全局、局部、类成员三个层面的含义。sizeof、内存对齐、内存布局。这些清单看起来很基础但考场上能快速写出来的前提就是考前反复默写直到形成条件反射。7.2 推荐的复习顺序和资料我的建议是分三轮推进。第一轮以教材为主不要一上来就刷题。操作系统看《深入理解计算机系统》的异常控制流和虚拟内存部分以及《现代操作系统》的进程和存储章节网络看《计算机网络自顶向下》的运输层和应用层C看《Effective C》和《C Primer》的关键章节。这一轮的目标是建立知识框架遇到不懂的术语能知道属于哪个模块。第二轮开始刷题重点不是题量而是错题背后的知识点。每做错一道题花时间回到教材里把对应的理论重新读一遍并用自己的话说清楚为什么错。这个过程中建议准备一份错题笔记里面只记考点关键词比如struct对齐12、TIME_WAIT2MSL考前翻一遍比刷十套题都有用。第三轮做限时模拟。找一套完整的笔试题严格按照考试时间来做特别是控制在1.5小时内完成选择题和简答题、留出40分钟给编码题。这个阶段的目的是训练节奏感避免考场上因为时间分配不合理而丢分。7.3 现场应试的动作要领有几个实操经验都是我踩过坑之后总结出来的。第一选择题不要恋战。一道题如果30秒内没有思路直接跳过全部做完后再回来蒙一个。这类笔试通常没有倒扣分蒙比空着强。第二简答题分点作答。阅卷人用的是点给分逻辑把关键词写全比写一大段话更有效。比如问你为什么要三次握手答案里一定要出现确认双方收发能力防止失效连接请求初始序号同步这几个词。第三编程题先写注释再写代码。我习惯先写三行注释核心数据结构是什么、整体思路是什么、边界条件考虑哪些。这样即使代码写不完阅卷人也能看到思考过程部分情况下能拿到步骤分。7.4 从笔试到面试这套题背后的能力模型笔试只是第一关。核心系统工程师的面试通常从笔试题里挑一个考点追问很深。比如笔试问过epoll是水平触发还是边缘触发面试就很可能继续追问ET模式下代码怎么写才能避免漏数据为什么nginx用epoll还是会出现惊群SO_REUSEPORT在内核里怎么实现负载均衡。所以备考不能停留在背答案层面。每复习一个考点都要顺手问自己三个问题这个知识点在什么场景下会被真实使用如果出现问题我该怎么定位有没有更容易出错的替代方案能把这三个问题回答好的人才是这个岗位真正在找的人。最后分享一个我个人很受用的做法每次复习完一个模块合上书找一张白纸把刚刚那部分内容的知识结构画出来包括核心概念、关联关系、典型题目和易错点。画不出来就回去重读画得出来才算真正掌握。这套方法看起来笨但对打牢底层基础特别有效也帮我顺利走过了校招那段压力很大的日子。