C++操作系统与网络编程(特定岗位)
如果你应聘的岗位涉及基础开发、网络编程或高性能计算,这部分内容会是重点。
1. 操作系统
*问题类型:
进程间通信(IPC)的方式(管道、消息队列、共享内存、信号量、信号)?
管道(Pipe)
匿名管道:用于父子进程通信
int fd[2]; pipe(fd); // fd[0]读端, fd[1]写端 if (fork() == 0) { /* 子进程 */ write(fd[1], data, size); } else { /* 父进程 */ read(fd[0], buffer, size); }
命名管道(FIFO):无关进程通信
mkfifo /tmp/myfifo # 终端创建
int fd = open("/tmp/myfifo", O_WRONLY); write(fd, data, size);
消息队列(Message Queue)
#include <sys/msg.h> struct msgbuf { long mtype; char mtext[100]; }; int msqid = msgget(IPC_PRIVATE, 0666); msgsnd(msqid, &msg, sizeof(msg.mtext), 0); msgrcv(msqid, &msg, sizeof(msg.mtext), 1, 0);
共享内存(Shared Memory)
#include <sys/shm.h> int shmid = shmget(IPC_PRIVATE, size, 0666); char* shm = (char*)shmat(shmid, NULL, 0); memcpy(shm, data, size); // 进程间共享 shmdt(shm);
信号量(Semaphore)
#include <sys/sem.h> int semid = semget(IPC_PRIVATE, 1, 0666); semctl(semid, 0, SETVAL, 1); // 初始值=1 struct sembuf op = {0, -1, 0}; // P操作 semop(semid, &op, 1);
信号(Signal)
#include <csignal> signal(SIGUSR1, handler); // 注册处理器 kill(pid, SIGUSR1); // 向进程发信号
线程同步机制(互斥量、信号量、读写锁、条件变量)?
互斥量(Mutex)
#include <mutex> std::mutex mtx; mtx.lock(); // 临界区 mtx.unlock();
信号量(Semaphore) (C++20)
#include <semaphore> std::counting_semaphore<1> sem(1); // 二元信号量 sem.acquire(); // P操作 // 临界区 sem.release(); // V操作
读写锁(Shared Mutex)
#include <shared_mutex> std::shared_mutex rw_lock; // 写锁(独占) { std::lock_guard<std::shared_mutex> lock(rw_lock); } // 读锁(共享) { std::shared_lock<std::shared_mutex> lock(rw_lock); }
条件变量(Condition Variable)
#include <condition_variable> std::mutex mtx; std::condition_variable cv; // 线程A:等待条件 std::unique_lock<std::mutex> lock(mtx); cv.wait(lock, []{ return condition; }); // 线程B:通知条件满足 cv.notify_all();
虚拟内存、物理内存?
特性 虚拟内存 物理内存 本质 进程看到的连续地址空间 实际的 RAM 硬件 管理 操作系统通过 MMU 映射 直接由内存控制器管理 大小 通常远大于物理内存(如 64TB) 受硬件限制(如 32GB) 碎片处理 无需连续物理块 需要连续物理块 C++ 体现 char *p = new char[1e9];
可分配malloc
实际占用物理页交换机制 页面可换出到磁盘 始终驻留 RAM 访问速度 依赖TLB/页表命中 直接访问(约 100ns) 映射关系:
虚拟地址 → MMU(页表查询)→ 物理地址
- 页错误(Page Fault):当访问未映射的虚拟页时触发,操作系统介入处理
C++ 代码验证内存地址:
#include <iostream> int main() { int x; std::cout << "虚拟地址: " << &x << std::endl; // 物理地址需通过操作系统接口获取(如Linux的 /proc/pid/pagemap) }
2. 网络编程
*问题类型:
TCP/IP 协议栈的五层/层模型?
层级 功能 关键协议/设备 物理层 传输比特流,定义物理设备标准(电压、接口类型) 网线、光纤、中继器 数据链路层 帧格式化、错误检测/纠正,控制物理介质访问 以太网(Ethernet)、交换机 网络层 路由寻址、IP分组转发,管理跨网络主机通信 IP、ICMP、路由器 传输层 提供端到端可靠/不可靠传输,流量控制,端口寻址 TCP、UDP 应用层 面向应用程序的数据封装与解析 HTTP、FTP、DNS TCP 和 UDP 的区别、特点和适用场景?
特性 TCP UDP 连接方式 面向连接(三次握手) 无连接 可靠性 可靠(确认重传、有序交付) 不可靠(可能丢包、乱序) 速度 慢(拥塞控制、流量控制) 快(无控制开销) 头部开销 20~60字节 8字节 适用场景 网页浏览(HTTP)、文件传输(FTP)、邮件 视频会议、在线游戏、DNS查询 TCP 交互流程和四次挥手过程?
- 第一次挥手:主动关闭方发送
FIN
报文,进入FIN_WAIT_1
状态。 - 第二次挥手:被动关闭方回复
ACK
报文,进入CLOSE_WAIT
状态;主动方收到后进入FIN_WAIT_2
。 - 第三次挥手:被动方处理完数据后发送
FIN
报文,进入LAST_ACK
状态。 - 第四次挥手:主动方回复
ACK
报文,进入TIME_WAIT
状态;被动方收到后关闭连接。
为什么需要四次?
TCP是全双工通信,需独立关闭两个方向的数据流(如:A关闭发送后,B仍可发送剩余数据)。
- 第一次挥手:主动关闭方发送
TIME_WAIT
状态?- 作用:
- 保证被动关闭方能正确关闭(若
ACK
丢失,可重传FIN
)。 - 防止历史报文干扰新连接(等待2MSL使旧报文消亡)。
- 保证被动关闭方能正确关闭(若
- 持续时间:2MSL(MSL通常30秒,共60秒)。
- 优化方法:
- 开启
tcp_tw_reuse
+tcp_timestamps
(复用TIME_WAIT
连接)。 - 设置
SO_LINGER
(强制跳过TIME_WAIT
,慎用)。
- 开启
- 作用:
阻塞 IO、非阻塞 IO、多路复用 IO (select, poll, epoll) 的区别和优缺点?
模型 工作机制 优点 缺点 阻塞IO 调用后线程挂起,直到数据就绪 编程简单 并发能力差 非阻塞IO 立即返回状态,需轮询检查就绪 避免线程阻塞 轮询消耗CPU 多路复用IO 单线程监听多个fd(select/poll/epoll) 高并发、资源占用少 编程复杂 异步IO 内核完成操作后回调通知 无等待开销 兼容性差(Linux支持弱) 多路复用实现对比:
- select/poll:O(n)遍历所有fd,支持fd数少(默认1024)。
- epoll:O(1)事件通知,支持海量fd(>10万),边缘触发(ET)性能更高。
epoll
的工作模式(水平触发 LT、触发 ET)?模式 触发条件 编程要求 典型场景 水平触发LT fd就绪时持续通知,直到事件处理 简单(不易丢事件) 默认模式,通用场景 边缘触发ET fd状态变化时仅通知一次 严格(需循环读/写) 高性能服务器 ET模式注意事项:
- 需循环读写直到返回
EAGAIN
错误,否则会丢失后续事件。 - 非阻塞fd必需,避免单次未处理完导致线程阻塞。
- 需循环读写直到返回
常见的网络编程模型(单线程、多进程、多线程、Reactor/Proactor)?
- 单线程:
- 所有操作串行执行(如Redis主线程)。
- 简单但无法利用多核,吞吐量低。
- 多进程/多线程:
- 每个连接独立进程/线程(如Apache)。
- 并发能力强,但资源消耗大,上下文切换开销高。
- Reactor模式:
- 核心:事件驱动 + 多路复用。
- 分工:
MainReactor
:处理新连接(单线程)。SubReactor
:处理IO事件(多线程)。
- 应用:Netty、Nginx。
- Proactor模式:
- 异步IO + 回调通知(如Windows IOCP)。
耗大,上下文切换开销高。
- 异步IO + 回调通知(如Windows IOCP)。
- Reactor模式:
- 核心:事件驱动 + 多路复用。
- 分工:
MainReactor
:处理新连接(单线程)。SubReactor
:处理IO事件(多线程)。
- 应用:Netty、Nginx。
- Proactor模式:
- 异步IO + 回调通知(如Windows IOCP)。
- 性能高但Linux支持弱。
- 单线程: