【C++上岸】C++常见面试题目 — 网络编程篇
网络编程在C++后端/游戏服务器/音视频/高性能服务等领域是高频考察点。
下面这些题目基本覆盖了主流互联网公司近几年C++岗位的网络相关真实面试题,按难度和出现频率大致排序。
基础 & 中频题(几乎必问)
- socket编程中 listen 的 backlog 参数到底代表什么?如果 backlog 设置为1,会有什么实际效果?
- accept() 返回的新连接 socket fd 和原始 listen fd 有什么本质区别?它们的文件描述符指向的内核对象是否一样?
- TCP 三次握手和四次挥手详细流程?哪些包可以合并?为什么 TIME_WAIT 状态要等待 2MSL?
- 什么是 TCP 的半连接队列(SYN队列)和全连接队列(accept队列)?如何查看和调整它们的大小?(ss -ltn 能看到什么?)
- close() 一个 socket 后,为什么还会出现大量 TIME_WAIT?如何优雅地减少 TIME_WAIT?(SO_REUSEADDR、SO_REUSEPORT、tcp_tw_reuse、tcp_tw_recycle 的区别与风险?)
- epoll 的 LT 和 ET 两种工作模式分别是什么意思?在 ET 模式下有哪些必须注意的编程细节?
- epoll 和 poll/select 相比有哪些优势?epoll_create、epoll_ctl、epell_wait 三个函数的参数和返回值分别代表什么?
- 一个已经建立的 TCP 连接,双方都没有 close,如果中间路由器突然断电了,双方如何感知到连接已经失效?(保活机制、SO_KEEPALIVE 的作用和参数)
- 什么是 TCP 的 Nagle 算法和延迟 ACK?它们在什么场景下会导致延迟?如何关闭它们?
- send() / write() 返回值小于要发送的字节数时应该怎么处理?有没有可能 send() 直接返回 -1 且 errno 是 EAGAIN?
中高级 & 高频题(大厂爱问)
- 非阻塞 socket + epoll ET 模式下,read()/recv() 应该循环读到多少才停?怎么判断真正读完了?
- write()/send() 在非阻塞模式下一次性写不完数据,应该怎么处理剩余数据?常见的两种方案是什么?
- 什么是 TCP 的 send buffer 和 receive buffer?它们的大小如何查看和调整?(/proc/sys/net/ipv4/tcp_wmem 和 tcp_rmem)
- 一个 TCP 连接上同时存在大量小包发送时,性能瓶颈可能出现在哪里?如何优化?
- 解释一下 TCP 的滑动窗口、拥塞窗口、慢启动、拥塞避免、快速重传、快速恢复的过程。
- 什么是 TCP 的 head-of-line blocking(队头阻塞)?HTTP/1.1、HTTP/2、HTTP/3 分别是如何解决或缓解这个问题的?
- 在使用 epoll 时,如果一个 fd 同时可读可写,epoll_wait 返回后应该先处理读还是先处理写?为什么?
- 多线程 Reactor vs 单线程 Reactor vs 多线程 Proactor 模型分别是什么?各自优缺点?muduo、libevent、libev、asio 大致属于哪一类?
- 如何用 C++ 实现一个简单的协程网络库?(难点:保存上下文、调度、与 epoll 的集成)
- 如果让你设计一个支持十万并发的单进程网络服务器,你会怎么组织代码结构?会使用哪些关键技术/设计模式?
框架 & 工程题(偏大厂/资深)
- muduo 网络库的核心类有哪些?EventLoop、Channel、Poller、TimerQueue、Acceptor、Connector、TcpServer、TcpConnection 分别负责什么?
- muduo 中为什么 TcpConnection 没有暴露 fd 给用户,而是封装了 sendInLoop()?
- muduo 的定时器是怎么实现的?TimerQueue 使用了什么数据结构?如何做到 O(log n) 插入和 O(1) 拿到最近定时器?
- asio 的 io_context 和 strand 分别解决什么问题?post() 和 dispatch() 的区别是什么?
- protobuf + muduo / asio / brpc 组合使用时,常见的封包拆包方式有哪些?(长度前缀 + 包体、google::protobuf::Message 的 SerializeToArray)
- 如何在 C++ 中实现一个基于 epoll 的高性能 HTTP/1.1 服务器?需要处理哪些边界情况?(Connection: keep-alive、chunked、pipeline、异常关闭检测)
- 什么是 TCP 的 zero window 探测?如何避免自己陷入 zero window 状态?
- 在高并发场景下,如何避免 accept 惊群问题?(SO_REUSEPORT 的原理和注意事项)
- 解释一下 epoll 的水平触发和边缘触发在实际编码中导致的经典 bug 案例(至少说出两种)。
- 如果让你实现一个支持 WebSocket 的服务器,你会怎么设计协议升级、帧解析、心跳、断线重连逻辑?
更偏底层 / 性能优化 / 故障排查方向(资深/架构)
- epoll 的内核实现里,红黑树和就绪链表分别起什么作用?copy 到用户态的 epoll_event 是怎么组织的?
- epoll 的 ET 模式下为什么必须使用 non-block fd?如果用了 block fd 会发生什么?
- accept4() 相比 accept() 多了什么能力?(SOCK_NONBLOCK、SOCK_CLOEXEC)
- TCP 的 SYN cookie 是如何工作的?它解决了什么问题?
- 在 Linux 上如何查看某个进程的 TCP 连接状态分布?(ss -m、ss -o、/proc/net/tcp)
- tcpdump 抓包时如何只抓某个连接的完整握手和挥手过程?(写出过滤表达式)
- 一个连接在 CLOSE_WAIT 状态卡住了,可能的原因有哪些?怎么快速定位?
- 大量 ESTABLISHED 但没有数据交互的连接,应该怎么处理?(SO_LINGER、tcp_fin_timeout)
- 如何用 C++ 实现一个简单的 HTTP/3(QUIC)客户端或服务器?(需要依赖哪些库?ngtcp2、lsquic、quiche)
- 在 C++ 高性能网络服务中,你最常用的性能分析工具和指标有哪些?(perf、火焰图、strace、bpftrace、sar、netstat -s、ss -tm)
建议复习优先级(按真实面试命中率排序)
- TCP 三次握手、四次挥手、TIME_WAIT、SO_REUSEADDR/PORT
- epoll LT/ET、非阻塞读写完整处理流程
- muduo / asio 核心类职责与经典设计
- 滑动窗口、拥塞控制、Nagle、延迟 ACK
- accept 惊群、SO_REUSEPORT
- send/recv 返回值处理、缓冲区管理
- WebSocket 协议升级与帧格式
- HTTP/2 队头阻塞 vs HTTP/3 QUIC
如果想针对其中某几道题要详细答案、代码示例、画图解释、或者想模拟面试被追问的连环炮,随时告诉我~
祝上岸顺利!