
1. 先把岗位看清楚奇安信网络开发到底考哪些基本功2019年春天那次春招到现在我还记得挺清楚。我投的是奇安信网络开发岗去之前以为安全公司的笔试肯定一多半是漏洞、渗透、攻击手段结果拿到卷子发现前面全是TCP状态迁移、socket编程、Linux并发模型。当时在考场里我就意识到一个结论安全公司的网络开发岗考的还是网络和系统的基本功安全题只是点缀并不作为重点。这是我对这份试题最深的印象也是今天想把它重新盘一遍的原因。先说清楚一个容易误解的点。奇安信虽然是做安全产品和服务的但“网络开发”这个岗位不等于“安全研究员”也不等于“渗透测试工程师”。它更接近一个基础设施开发岗做的事情是把网络流量解析出来、把协议字段拆开、把数据高效转发或存储、把终端和服务器上的通信链路做好。简单说安全产品里的流量检测引擎、日志采集器、协议分析模块、网关类设备上的通信组件都需要网络开发工程师去实现。所以笔试才不偏门把网络协议、系统编程、并发模型这些基础考点铺得很扎实。我后来和同一批考试的同学凑过回忆版把各家渠道的信息整理到一起发现这份网络开发试题的构成大概是这样的考察方向大致占比常见出题方式TCP/IP 协议栈30%左右选择题、简答题重点考三次握手、状态机、可靠传输Linux 系统编程与C语言25%左右代码填空题、程序输出题、socket编程题并发与性能15%左右select/poll/epoll 对比线程进程区别锁网络安全基础15%左右常见攻击原理、防御手段、日志和流量分析思路算法与手写代码15%左右一到两道编程题需要手动实现完整解法注意这个占比是我根据多份回忆拼出来的不是官方划分。但方向上很能说明问题不管公司名字里带不带“安全”二字网络开发岗的核心能力模型始终是“网络 系统 编程”。如果你准备这类笔试时只刷漏洞知识大概率会像我一样看到卷子先懵几分钟。1.1 网络开发岗和普通后端开发不是一回事我见过不少同学在春招时把网络开发岗当成普通“后端开发”去准备这也容易出问题。普通后端开发更关注业务逻辑、数据库、缓存、微服务框架网络开发则更关注数据链路本身。你可以把后端开发理解成盖楼网络开发是修水管和电网——后者更底层任何一处的性能瓶颈都可能直接拖垮整栋楼。这两类岗位在笔试上的差异很明显。普通后端笔试可能会给你一个“用户下单”的场景让你设计接口和表结构网络开发笔试则可能直接给一段十六进制报文让你算出源端口、目的端口和报头长度。它考的是你对数据包有没有“手感”。这种手感怎么练没有捷径。我当时是把《TCP/IP详解卷1》的重点章节啃了一遍然后自己用Python的scapy库构造各种协议包再用Wireshark抓下来对比。这个过程很枯燥但效果非常直接。笔试中只要看到报文我脑子里能立刻映射到Wireshark的解析界面答案基本就是手到擒来。1.2 从回忆版笔试题提炼的考点权重我在整理这份复盘时也去翻过当年群里大家分享的考后回忆。说实话精确到原题已经很难还原但高频考点是稳定的。选择题里TCP状态迁移、IP分片、端口号范围、DNS解析顺序这些几乎属于必考简答题则集中在这几类解释TIME_WAIT为什么需要2MSL、select和epoll的区别、进程与线程的适用场景、给定一个抓包场景让你判断异常行为。这些考点背后其实都指向同一种能力你能不能在生产环境下把一个网络问题从头到尾排查干净。安全产品上线后遇到“客户端连不上服务端”“数据传着传着就断了”“CPU突然飙高”之类的问题都需要开发人员去抓包、看状态、查系统调用。笔试题目只是把这些真实场景抽象成了试卷上的考点而已。基于这个逻辑后面的章节我就按“网络协议 - 系统编程 - 安全视角 - 手写代码 - 面试复盘”的顺序来拆基本对应我当时从笔试到面试的完整链路也方便你按顺序做知识梳理。2. 网络协议考点从抓包解析到TCP状态机再到HTTP网络协议是整个笔试最重要的一块也是拉开差距的关键。很多非科班出身的人能背出七层模型但一碰到具体字段就发怵。这一章我挑三类高频题展开讲每类都附上我现在回看时觉得最有效的解题思路。2.1 报文解析题拿到十六进制先看哪几行我记得笔试题里有一类很典型的题目给出一段十六进制数据要求解析出以太网头部、IP头部和TCP头部的关键字段。因为不允许用Wireshark所以只能靠手推。比如下面这种45 00 00 3c 1c 46 40 00 40 06 b1 e6 ac d9 17 7c 0a 63 22 04拿到这种题我的习惯是先按字节序号切分而不是从第一行硬读。IP头从第15个字节开始第13个字节是协议号06代表TCP第15、16字节是源IP第17、18字节是目的IP。如果题意要求解析TCP头那就继续往后找源端口和目的端口TCP头前4个字节就是这两个字段各占2字节。解题核心是熟练记住IP头和TCP头的默认长度。IP头一般是20字节选项字段为0TCP头也一般是20字节数据偏移字段默认是5表示有5个32位字。只要这两个长度判断准了后续的载荷偏移就不会算错。我当时记了个口诀“IP20TCP20选项全零最容易。”但实际考试里如果遇到带选项的报文别慌TCP头长度看第13个字节的高四位那个值乘以4就是真实长度。这类题考的是“能不能从底层理解一个连接从建立到传输的全过程”。做安全产品的时候经常要自己解析非标准协议的报文或者对私有协议做字段重排没有这种底子根本做不了。所以别嫌它基础基础到极致就是最实用的技能。2.2 TCP状态机与高频问法三次握手、TIME_WAIT、连接失败TCP状态迁移题出现频率极高而且每次都不是死记硬背能应付的。有三个问法特别常见第一个是“为什么三次握手而不是两次”。标准答案是两次握手无法让双方确认彼此的接收和发送能力。但更工程化的理解是防止历史重复连接请求突然建立无效连接。如果只有两次握手服务端在收到一个延迟了很久的SYN后就会建立连接并分配资源造成资源浪费和连接混乱。三次握手让服务端能通过第三次握手中的确认信息判断客户端是否真的想建立连接。第二个是“TIME_WAIT为什么是2MSL”。这个考点我几乎每次面试都被追问。我的理解分两层第一层是保证最后一个ACK能到达对端如果丢了可以重传第二层是让所有属于本次连接的数据包在网络中消散避免污染新连接。2MSL就是给数据包一个完整的往返时间确保旧包消失。后来我看到线上环境大量TIME_WAIT怎么处理时才发现这个机制带来的端口占用问题远比书上的概念复杂。不能只背结论得能说出“对性能的影响”和“常见处理手段”比如调整内核参数或开启连接复用。第三个是“连接失败如何排查”。这题看似简单但坑很多。如果客户端connect返回超时一般先ping服务器看网络通不通再查目标端口是否被防火墙丢弃如果返回连接拒绝Connection refused大概率是端口没监听。笔试里经常用这题考经验因为纸上写不出实际抓包过程只能看你有没有完整的排查框架。我推荐按“本地网卡 - 路由 - 防火墙 - 目标端口 - 应用进程”的顺序去答每一步对应什么工具、什么现象能串起来就是高分答案。2.3 应用层DNS、HTTP、HTTPS的工程化问题应用层协议里DNS解析流程几乎年年考。比如“浏览器输入一个域名之后发生了什么”很多人一开口就是从HTTP请求讲起但其实第一步是DNS解析。我记得当时笔试考了一个细节DNS使用UDP 53端口但区域传送用TCP 53端口为什么答案是因为UDP包有长度限制无法承载大量记录TCP适合大流量且需要可靠传输的场景。这种题不是让你背端口号而是让你理解同一种服务在不同场景下会通过传输手段的取舍。HTTP部分的题比较常规但容易在状态码上翻车。特别是301和302的区别、401和403的区别。我的记忆方法是301是永久重定向SEO里常用302是临时重定向业务里做登录跳转常用。401是“你没登录”403是“你没权限”。笔试选择题最喜欢混着考记错了会很亏。HTTPS的题目在2019年已经明显增多核心考的是TLS握手流程客户端发ClientHello服务端回ServerHello和证书客户端校验证书后生成预主密钥再用服务端公钥加密发送双方各自计算会话密钥最后交换Finished报文。不用把每个消息字段背全但要能画出一个握手过程并且说清楚证书校验是防止中间人攻击的关键。3. Linux系统编程与C语言笔试最容易暴露短板的地方如果网络协议题是“送分题”那系统编程题就是“拉分题”。这一部分最能看出一个人是不是真的写过网络程序还是只会在LeetCode上刷题。奇安信的网络开发岗明显更偏向Linux平台所以C语言、系统调用、并发模型几乎是必考。3.1 socket编程题处处是坑手写回显服务器时要留意的点有一类高频题是让你补全一个TCP回显服务器。核心代码写上socket、bind、listen、accept这些调用很容易但真正决定分数的是你对待边界情况的态度。下面是一个简化的C语言骨架我当年考试时就是这么写的#include stdio.h #include stdlib.h #include string.h #include unistd.h #include sys/socket.h #include netinet/in.h #include arpa/inet.h #define PORT 8080 #define BACKLOG 128 int main() { int listen_fd socket(AF_INET, SOCK_STREAM, 0); if (listen_fd 0) { perror(socket); exit(1); } int opt 1; setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, opt, sizeof(opt)); struct sockaddr_in addr; memset(addr, 0, sizeof(addr)); addr.sin_family AF_INET; addr.sin_addr.s_addr htonl(INADDR_ANY); addr.sin_port htons(PORT); if (bind(listen_fd, (struct sockaddr*)addr, sizeof(addr)) 0) { perror(bind); exit(1); } if (listen(listen_fd, BACKLOG) 0) { perror(listen); exit(1); } while (1) { struct sockaddr_in client_addr; socklen_t client_len sizeof(client_addr); int conn_fd accept(listen_fd, (struct sockaddr*)client_addr, client_len); if (conn_fd 0) { perror(accept); continue; } char buf[1024]; ssize_t n read(conn_fd, buf, sizeof(buf) - 1); if (n 0) { perror(read); } else { buf[n] \0; write(conn_fd, buf, n); } close(conn_fd); } close(listen_fd); return 0; }这段代码能跑但笔试如果只写到这个程度最多算及格。面试官会盯着几个点继续追问为什么在bind前设置SO_REUSEADDR“SO_REUSEADDR解决的是bind失败报Address already in use的问题本质是允许重用处于TIME_WAIT状态的端口。”如果没写这句话说明你可能从来没在实际部署里遇到过端口占用。还有accept返回值要检查、read要处理EINTR、客户端断开时read返回0要妥善处理这些都属于“经验分”。笔试时如果时间允许我会建议在代码里补上注释说明每个关键系统调用失败后应该怎么办。这不只是给面试官看的也是给自己理清逻辑。现实中网络程序跑着跑着崩溃80%的问题都在这些看起来不起眼的边界条件上。3.2 并发模型题fork、线程、epoll怎么选并发模型几乎是必考的简答题。常见问法是你如何设计一个支持大量并发连接的TCP服务器。首先要分清楚两种思路一种是多进程/多线程模型每个连接对应一个进程或线程另一种是事件驱动模型通过select、poll或epoll监听多个fd。笔试时不能只罗列概念最好能结合场景说明。如果连接数不多但每个连接都有阻塞式计算多线程模型更直观如果连接数上万且每个连接大多数时间都在等待IO事件驱动模型是唯一合理的选择。我当时的答法是分三层第一层说清楚“连接多但流量不一定大”的典型场景比如即时通信、物联网设备接入第二层对比多线程和事件驱动的内存开销、上下文切换成本和编程难度第三层给出实际选型例如“用epoll作为主事件循环配合线程池处理业务逻辑”。这样答既有高度又不会扯得太虚。3.3 select、poll、epoll笔试必考的三方对比这三者的对比已经成为网络开发岗的“经典题中的经典题”。最好用表格记维度selectpollepoll底层数据结构fd_set 位图pollfd 数组红黑树 就绪链表最大连接数受FD_SETSIZE限制理论无上限理论无上限每次调用开销需要把fd集合从用户态拷贝到内核态同 select通过epoll_ctl维护不需每次重新拷贝就绪通知方式轮询所有fd轮询所有fd回调机制只返回就绪fd触发模式仅水平触发仅水平触发支持水平触发和边沿触发易用性简单但效率低比select灵活用法稍复杂性能最好笔试里常考的坑是select能监听的最大fd数量为什么是1024因为fd_set是一个位图默认大小1024位。这个限制后来被认为不够用所以epoll才火起来。另外很多人以为epoll一定比select快其实如果连接数很少、活跃度很高select的简单反而可能更快。说是“性能最优”永远要先加个前提。我当时笔试写简答题时会把这个表格的核心点用一段话穿起来select和poll每次调用都要把全部fd从用户态拷贝到内核态内核再线性扫描每一个fdepoll通过内核事件表和回调机制只把就绪的fd返回给用户态所以连接数越大优势越明显。这段话比单纯背表格更容易得分因为它展示了“为什么”。3.4 epoll的水平触发LT和边沿触发ET一道经典的追问如果说select/poll/epoll对比是必考那LT和ET的区别就是必考后的必追问题。我当时第一次被问到ET时有点懵后来想明白了水平触发是“只要缓冲区还有数据就一直通知”边沿触发是“只有状态发生变化时才通知一次”。水平触发的好处是编程简单不足是可能多次唤醒边沿触发更高效但要求一次性把数据读完否则剩余数据可能要等到下一次新数据到达才触发导致“卡包”。所以ET模式下通常需要把fd设置为非阻塞然后用循环read直到返回EAGAIN。笔试题如果让你写一个ET模式的读取逻辑最简单的框架是// 设置非阻塞 int flags fcntl(fd, F_GETFL, 0); fcntl(fd, F_SETFL, flags | O_NONBLOCK); while (1) { ssize_t n read(fd, buf, sizeof(buf)); if (n 0) { // 处理数据 } else if (n 0 errno EAGAIN) { break; // 数据读完了 } else { // 真正的错误处理 break; } }这里有个容易犯的错把EAGAIN当成错误直接退出。实际业务里非阻塞read返回-1且errno是EAGAIN只代表当前没有数据可读不是连接断开。连接断开是read返回0对端close或者返回其他错误。笔试时把这个点圈出来阅卷人会认为你真有实战经验。4. 安全视角的特殊题目不像渗透测试更像防御式开发既然公司主打安全笔试里出现安全相关题目是避免不了的。但我考完的体会是它不要求你像一个攻击者那样写exp而是要求你像一个开发者那样理解漏洞、流量和系统的安全边界。所以准备这部分重点不是背POC而是建立“防御思维”。4.1 给一段PCAP让你判断异常流量怎么答才不丢分有一类题非常经典给出一段Wireshark抓包截图或者一段流量统计让你判断这台主机是否出了安全问题。比如内网一台服务器频繁向外部发起SYN请求又或者某个IP在短时间内扫描了大量端口。这类题考察的不是记忆力而是分析路径。我会按三步走看时间线流量是持续均匀的还是突发脉冲式的扫描和攻击行为通常有明显的突发性。看连接模式大量针对不同目的IP或不同端口的尝试且连接都未完成大概率是端口扫描或蠕虫扩散行为。看载荷特征DNS查询是否出现超长TXT记录、HTTP请求是否有明显的注入特征。答题时要把这三步说清楚再给结论。比如“从流量看源IP对同一目标IP的连续端口进行了探测且每个连接都只发SYN而不完成握手这是典型的SYN扫描行为”。面试官要的不是你说“这是攻击”而是你展示出完整的判断依据。4.2 常见漏洞原理与修复从开发者角度答安全公司笔试里的Web漏洞题答法跟渗透测试岗有区别。它会更偏“开发人员如何避免写出漏洞代码”。我遇到过的相关考点有SQL注入、XSS、CSRF、缓冲区溢出。拿SQL注入来说只写“用预编译语句防SQL注入”能拿基本分但如果能继续说明为什么预编译有效——因为SQL语句结构在编译阶段已确定用户输入只会被当参数处理而不会改变语法结构——这就能拿高分。XSS的考点集中在存储型、反射型和DOM型三者的区别。我的记法是存储型是恶意脚本存到了服务端反射型是脚本在URL里DOM型是脚本在前端DOM解析过程中执行。防御上核心是输出编码和输入过滤尤其注意在HTML属性、JavaScript、CSS等不同上下文里要做不同的编码处理。缓冲区溢出这类题目在C语言程序员的安全笔试里也出现过。我不建议在文章里写攻击细节但至少要知道防御手段栈保护canary、数据执行保护NX、地址空间随机化ASLR以及源码中避免使用不安全的字符串函数。作为一个网络开发工程师写网络协议解析代码时最容易踩的坑就是“根据报文长度拷贝数据而不校验”这类代码是缓冲区溢出漏洞的重灾区。4.3 安全产品背后的网络开发任务才是这部分题目的真正来源我在考场上遇到安全相关的题目时总会想到奇安信这些安全产品背后那些开发工作。比如终端安全产品里有个模块负责采集网络连接信息它要hook或读取系统网络状态再把数据结构化上报代码安全检测产品要对代码仓库做静态扫描涉及文件解析和规则匹配。这些模块对网络开发的依赖恰恰体现在笔试那些“奇怪”的题目里。最典型的是流量检测尤其是加密流量检测。2019年的时候越来越多流量走HTTPS传统深度包检测DPI失效了。安全产品的解法开始转向前向扫描、指纹识别和元数据采集。这种题目不会直接考你“加密流量怎么检测”但会用一道抓包题问你“如何在不解密的情况下识别出常见协议的流量”。答案要从TLS握手阶段的服务器名字SNI、证书字段、握手报文大小分布等特征入手。这些都不是纯攻击知识而是网络开发与安全检测的交叉领域。5. 手写代码题两道典型题怎么做才算答到点子上笔试最后一般有一两道手写代码题。题目看起来可能跟网络不沾边但仔细想每一道都能映射到实际网络开发场景。这一章我复盘两道让我印象深刻的典型题。5.1 第一道基础题滑动窗口求最长无重复子串这道题在很多公司笔试里都有但网络开发岗也愿意出因为它考的是基本的编程能力和复杂度意识。题目是给一个字符串找出其中不含重复字符的最长子串长度。我当时用了滑动窗口思路代码如下def length_of_longest_substring(s: str) - int: window set() left 0 max_len 0 for right, ch in enumerate(s): while ch in window: window.remove(s[left]) left 1 window.add(ch) max_len max(max_len, right - left 1) return max_len这题的得分点在于第一能不能想到用双指针维护一个动态窗口第二能不能解释为什么复杂度是O(n)而不是O(n^2)。关键在于窗口左端的指针只会向右移动所以整体是线性的。这个算法在真实网络开发里有个直接映射流量识别中的状态管理。比如处理TCP流时需要在一个连接上维护“哪些字节已经处理过、哪些还留在缓冲区”的窗口状态。能写明白滑动窗口的人对TCP接收缓冲区的管理理解也更深入。面试官不一定会明说但你的代码风格会暴露你有没有这种思维。5.2 第二道网络场景题一致性哈希的实现思路还有一类编程题不会直接考LeetCode而是考工程场景。我印象比较深的是“假设有N台后端服务器如何设计一个负载均衡算法使客户端请求尽量均匀分布同时服务器扩缩容时影响最小”。标准答案是带虚拟节点的一致性哈希。笔试里写完整实现太长但至少要写出思路和关键点。我会这样答把服务器节点通过哈希函数映射到一个0到2^32-1的环形空间。把请求的某个标识也哈希到环上沿环顺时针找到第一个服务器节点。为解决分布不均和节点变化影响大的问题为每个物理节点生成若干个虚拟节点分散在环上。新增或删除节点时只需要重新分配该节点到下一节点之间的数据其他节点不受影响。如果笔试要求给出实现片段可以简化成这个伪代码import hashlib class ConsistentHash: def __init__(self, nodesNone, virtual_nodes150): self.virtual_nodes virtual_nodes self.ring {} self.sorted_keys [] if nodes: for node in nodes: self.add_node(node) def _hash(self, key): return int(hashlib.md5(key.encode()).hexdigest(), 16) def add_node(self, node): for i in range(self.virtual_nodes): h self._hash(f{node}-{i}) self.ring[h] node self.sorted_keys.append(h) self.sorted_keys.sort() def get_node(self, key): if not self.ring: return None h self._hash(key) for kh in self.sorted_keys: if h kh: return self.ring[kh] return self.ring[self.sorted_keys[0]]笔试答题时不必写出完整类但要把“哈希环”“顺时针查找”“虚拟节点”三个关键词写出来。面试官真正想看的是你有没有考虑过“节点变化时如何最小化影响”。这类问题在网关、负载均衡、分布式缓存中非常常见也是网络开发岗位比普通后端更容易遇到的高频工程问题。5.3 手写代码的隐性得分点很多人笔试编程题没过不是算法不会而是代码太毛糙。我给自己列了一个“上考场前默念清单”变量命名要见名知意不要用a、b、c。哪怕在试卷上也要像在写正式代码一样。边界条件必须考虑输入为空怎么办数组越界怎么办数值溢出怎么办写完代码要主动算一下时间复杂度。题目下方如果写了“请说明算法复杂度”千万别空着。如果题目没让你写注释至少要在关键步骤加一行注释表明你清楚这一步在干什么。这套清单在我后来面试其他公司时也一直在用。笔试不只是考察结果更是考察“你平时写代码的习惯”。一个能在接口判断上考虑周全的人到了生产环境写网络程序时踩坑的概率也会低很多。6. 笔试后的面试追问链路和备考复盘笔试结束不代表这场招聘考察结束。面试环节往往会围绕你在笔试里的答案继续追问而且是那种“你越深入越问越细”的方式。这一章写写我印象最深的一连串追问以及回头看时的复盘建议。6.1 面试官顺着笔试答案追问的一个典型链路我记得笔试里有一道题考到了select函数的缺点。我当时的回答是“select有1024个fd上限而且每次调用都要把所有fd集合从用户态拷贝到内核态效率不高。”面试官点了点头接着问“那epoll为什么没有1024这个限制”我答“因为epoll通过epoll_create创建一张内核事件表通过epoll_ctl往里添加fd没有用固定大小的位图。”面试官继续追问“epoll_wait返回后你是怎么知道是哪个fd就绪的”我说“epoll_wait会把就绪fd放入events数组通过遍历events数组获取而不是遍历所有fd。”他又问“如果epoll_wait一次性返回了几万个就绪fd而你只有一个线程去处理会不会有问题”这个问题就有点深了。我当时愣了一下然后回答“可以引入多线程或者线程池多个worker线程各自调用epoll_wait但要注意惊群问题。Linux 4.5之后引入了EPOLLEXCLUSIVE事件可以指定只唤醒一个等待者。或者主线程只做事件分发把具体业务丢给工作线程处理。”面试官点头又抛了一个更实际的“这样设计之后单个线程处理不过来怎么办”我答“可以按连接哈希分配到多个线程每个线程独立维护一个epoll实例。这样每个连接只属于一个线程避免跨线程竞争。”整条追问环节结束之后我特别庆幸自己曾经在Linux上实际跑过epoll的demo而不是只背概念。面试官的问题看似随机实际都是在确认“你说会用epoll那你到底用到了什么程度”。如果你只背了对比表到这里基本就接不住了。6.2 如果你是准备类似岗位的求职者四周时间可以这样安排在经历了2019年这次春招之后我总结了一套备考时间分配方案之后推荐给学弟学妹反馈都不错。以四个星期为例时间段重点内容具体行动第一周TCP/IP协议栈精读TCP三次握手、四次挥手、状态迁移用Wireshark抓取本机HTTP请求并对照报文背熟常用端口号第二周Linux系统编程手写socket回显服务端练习IPC、信号、守护进程把fork、exec、wait的父子关系理清楚第三周并发与性能对比select、poll、epoll在Linux上分别实现一遍观察CPU占用加深对阻塞、非阻塞、同步、异步的理解第四周安全基础与编程刷题整理SQL注入、XSS、CSRF、缓冲区溢出的原理与防御每天2-3道手写题重点练双指针、滑动窗口、哈希表如果你时间更紧可以把第一周和第二周合并但不要跳过epoll的实践。纸上谈兵和真正跑一遍面试一开口就能听出来。6.3 我后来复盘发现的几个坑有几个坑是我自己踩过、后来看别人也在踩的稍微展开说一下。第一个坑是把安全知识准备得太深反而忽略了基本功。我当时花了大量时间看渗透测试方法论结果笔试里大部分渗透相关内容都是选择题反而网络的简答题占了最高比重。安全公司的网络开发岗“安全”是行业属性“网络开发”才是岗位本质顺序不能反。第二个坑是写代码只写函数体不写异常处理。面试官对“如果accept失败怎么办”“如果read被信号中断怎么办”这类问题特别敏感。我当时笔试的socket代码没写错误分支幸好面试环节有解释机会不然直接就被筛掉了。从那次以后我写任何代码demo都会把错误处理写上哪怕只写一行也能体现工程意识。第三个坑是面试时不懂装懂。面到后面面试官问了一个关于内核协议栈收包流程的问题我其实只熟悉应用层。当时如果我硬答很可能会把面试引向尴尬。我选择直接说“这块我只了解大致路径链路层和网络层的细节没有实际读过源码后续可以补。”面试官反而点头说知道边界比乱编重要。后来我特意去读了相关源码把这个短板补上了。现在回头看奇安信2019春招的这份网络开发试题难度并不偏但覆盖得非常全面。它逼着我去把计算机网络、Linux编程和并发模型重新过了一遍这种底层的知识体系直到今天都在帮我处理实际问题。如果让我给准备同类岗位的人一句最实在的建议那就是别把“安全”两个字当作全部先把网络编程的基本功练到能随时手写出来的程度这比背多少漏洞列表都有用。