网络编程学习路线图
第一阶段:理解整体架构(1-2周)
1. 核心概念理解
你的项目采用了经典的Reactor模式,这是高并发网络编程的标准架构:
// 整体架构层次
应用层 (HttpServer)
↓
传输层 (TcpServer/TcpConnection)
↓
事件层 (EventLoop/Channel)
↓
IO复用层 (EPollPoller)
↓
系统调用层 (epoll)
2. 重点学习顺序
第一步:EventLoop(事件循环核心)
// 这是整个网络库的核心,先理解这个
class EventLoop {
// 核心成员
std::unique_ptr<Poller> poller_; // IO复用
std::unique_ptr<TimerQueue> timerQueue_; // 定时器
ChannelList activeChannels_; // 活跃通道
std::vector<Functor> pendingFunctors_; // 待处理回调
};
学习要点:
loop()
方法是事件循环的核心runInLoop()
和queueInLoop()
是线程间通信的关键wakeup()
机制用于跨线程唤醒
第二步:Channel(事件通道)
// Channel是文件描述符的封装
class Channel {
EventLoop* loop_; // 所属事件循环
const int fd_; // 文件描述符
int events_; // 注册的事件
int revents_; // 实际发生的事件
// 回调函数
ReadEventCallback readCallback_;
EventCallback writeCallback_;
EventCallback closeCallback_;
EventCallback errorCallback_;
};
学习要点:
- Channel是Reactor模式中的事件处理器
- 每个fd对应一个Channel
- 通过回调函数处理各种IO事件
第二阶段:深入IO复用(2-3周)
1. EPollPoller实现
class EPollPoller : public Poller {
private:
int epollfd_; // epoll文件描述符
EventList events_; // 事件列表
public:
Timestamp poll(int timeoutMs, ChannelList* activeChannels) override;
void updateChannel(Channel* channel) override;
void removeChannel(Channel* channel) override;
};
重点学习:
poll()
方法:调用epoll_wait,获取就绪事件updateChannel()
方法:注册/修改/删除事件监听fillActiveChannels()
方法:将epoll事件转换为Channel事件
2. 面试重点准备
// 面试官可能问的问题:
1. 为什么选择epoll而不是select/poll?
- select有文件描述符数量限制
- poll没有数量限制但效率低
- epoll使用事件通知,效率最高
2. epoll的LT和ET模式有什么区别?
- LT:水平触发,事件不处理会重复通知
- ET:边缘触发,只在状态变化时通知一次
3. 如何处理epoll的ET模式?
- 必须循环读取直到EAGAIN
- 避免事件丢失
第三阶段:TCP服务器实现(2-3周)
1. TcpServer架构
class TcpServer {
private:
EventLoop* loop_; // 主事件循环
std::unique_ptr<Acceptor> acceptor_; // 连接接收器
std::shared_ptr<EventLoopThreadPool> threadPool_; // 线程池
ConnectionMap connections_; // 连接管理
};
学习要点:
newConnection()
处理新连接removeConnection()
处理连接断开- 线程池分配连接给工作线程
2. TcpConnection实现
class TcpConnection {
// 状态管理
enum StateE { kConnecting, kConnected, kDisconnecting, kDisconnected };
// 缓冲区
Buffer inputBuffer_; // 输入缓冲区
Buffer outputBuffer_; // 输出缓冲区
// 回调函数
ConnectionCallback connectionCallback_;
MessageCallback messageCallback_;
WriteCompleteCallback writeCompleteCallback_;
};
重点学习:
- 连接状态管理
- 缓冲区设计
- 消息处理流程
第四阶段:HTTP协议实现(2-3周)
1. HTTP解析器
class HttpContext {
// HTTP解析状态机
enum HttpRequestParseState {
kExpectRequestLine,
kExpectHeaders,
kExpectBody,
kGotAll,
};
HttpRequest request_;
HttpRequestParseState state_;
};
学习要点:
- HTTP请求行解析
- HTTP头部解析
- HTTP体解析
- 状态机设计
2. 文件上传处理
class FileUploadContext {
enum class State {
kExpectHeaders, // 等待头部
kExpectContent, // 等待文件内容
kExpectBoundary, // 等待边界
kComplete // 上传完成
};
};
重点学习:
- multipart/form-data解析
- 边界(boundary)处理
- 流式文件处理
第五阶段:并发和线程模型(2-3周)
1. 线程池设计
class EventLoopThreadPool {
private:
EventLoop* baseLoop_; // 主事件循环
std::vector<std::unique_ptr<EventLoopThread>> threads_;
std::vector<EventLoop*> loops_;
std::atomic<int> next_; // 轮询分配
};
学习要点:
- 主线程负责接受连接
- 工作线程处理业务逻辑
- Round-robin分配策略
2. 线程安全
// 关键线程安全机制
1. 跨线程调用:runInLoop/queueInLoop
2. 连接管理:线程安全的连接表
3. 缓冲区:线程安全的读写
面试准备重点
1. 架构图准备
# 准备画图说明
┌─────────────────┐
│ Application │ (HttpServer)
├─────────────────┤
│ Transport │ (TcpServer/TcpConnection)
├─────────────────┤
│ Event Loop │ (EventLoop/Channel)
├─────────────────┤
│ IO Multiplex │ (EPollPoller)
├─────────────────┤
│ System Call │ (epoll)
└─────────────────┘
2. 核心代码片段
// 准备这些关键代码片段
1. EventLoop::loop() - 事件循环核心
2. Channel::handleEvent() - 事件处理
3. EPollPoller::poll() - IO复用
4. TcpConnection::handleRead() - 数据读取
5. HttpContext::parseRequest() - HTTP解析
3. 性能优化点
// 准备性能优化说明
1. 零拷贝:sendfile()系统调用
2. 内存池:减少内存分配开销
3. 对象池:复用连接对象
4. 缓冲区优化:避免频繁拷贝
4. 问题排查思路
// 准备问题排查方法
1. 连接泄漏:检查连接表大小
2. 内存泄漏:使用valgrind检查
3. 性能瓶颈:使用perf分析
4. 死锁问题:检查锁的获取顺序
学习建议
1. 实践顺序
# 按这个顺序动手实践
1. 先写一个简单的echo服务器
2. 添加epoll支持
3. 实现多线程版本
4. 添加HTTP解析
5. 实现文件上传下载
2. 调试技巧
# 调试网络程序的方法
1. 使用strace跟踪系统调用
2. 使用netstat查看连接状态
3. 使用tcpdump抓包分析
4. 使用gdb调试程序逻辑
3. 性能测试
# 性能测试工具
1. ab - Apache基准测试
2. wrk - HTTP压力测试
3. iperf - 网络性能测试
4. 自写测试程序
记住,网络编程是一个实践性很强的领域,光看代码是不够的,一定要动手实践。建议你:
- 先理解整体架构,再深入细节
- 从简单开始,逐步增加复杂度
- 多写测试代码,验证理解
- 准备面试问题,能够清晰表达设计思路
这样学习下来,你就能真正掌握这个网络库,并且能够应对面试官的深度拷打!