Web框架Socket模块设计与实现

模块概述

Socket模块是整个Web框架的网络通信基础,采用面向对象的设计方式,实现了TCP网络通信的完整功能。

类结构设计

1. 基础Socket类 (socket.h)

  • 提供统一的接口:bind、listen、connect、accept等
  • 实现了多个socket优化配置选项

2. 服务端Socket和客户端Socket

  • 继承于socket基类
  • 对业务进行针对性简化

3. Socket处理器 (socket_handler.h)

  • 内置epoll和服务器监听句柄(服务器唯一实例)
  • 内部提供handler接口对新连接执行处理(获取工厂实例,assign任务)

常见问题解答(Q&A)

Q1: 项目中使用了epoll进行IO多路复用,为什么选择epoll而不是select/poll?epoll的EPOLLONESHOT标志位的作用是什么?

A1: 这个问题可以从以下几个方面回答:

  1. epoll相比select/poll的优势:

    • select/poll每次调用都需要将fd集合从用户态拷贝到内核态,而epoll通过mmap实现内核与用户空间的共享内存
    • select/poll都需要遍历整个fd集合,而epoll采用回调机制,只关注发生事件的fd
    • select最大支持1024个fd,poll没有限制但性能会随fd数量增长而下降,epoll则基本不受限制
  2. 在代码中EPOLLONESHOT的使用:

1
2
3
void SocketHandler::attach(int sockfd) {
m_epoll.add(sockfd, (EPOLLIN | EPOLLHUP | EPOLLERR | EPOLLONESHOT));
}

EPOLLONESHOT确保一个socket连接在任意时刻只被一个线程处理,防止多线程下的并发问题。

Q2: 项目中ServerSocket的构造函数中设置了多个socket选项,请解释这些选项的作用及其对性能的影响。

A2: 参考 server_socket.cpp 中的实现:

  1. set_recv_buffer/set_send_buffer : 设置10KB的收发缓冲区,用于调节数据传输的缓冲大小
  2. set_linger : 控制socket关闭时的行为,设置为true且timeout为0表示立即关闭
  3. set_keepalive : 保持连接活跃,定期检测连接状态
  4. set_reuseaddr : 允许地址重用,服务器重启时可以立即绑定端口

Q3: 项目中如何处理socket的异常情况?比如客户端异常断开、连接超时等。

A3: 主要通过以下机制处理:

  1. epoll事件监控:
1
2
3
4
5
6
7
if (m_epoll.is_set(i, EPOLLHUP)) {
log_error("socket hang up by peer: conn=%d", connfd);
Singleton<TaskFactory>::instance()->remove(connfd);
} else if (m_epoll.is_set(i, EPOLLERR)) {
log_error("socket error: conn=%d", connfd);
Singleton<TaskFactory>::instance()->remove(connfd);
}
  1. 资源清理:
  • 使用TaskFactory管理连接对应的任务
  • 及时清理断开的连接
  • 完善的错误日志记录

Q4: 项目中Socket模块使用了哪些设计模式?为什么要使用这些模式?

A4: 主要使用了以下设计模式:

  1. 单例模式:SocketHandler采用单例模式,确保全局只有一个socket管理器
  2. 工厂模式:TaskFactory负责创建和管理任务
  3. 策略模式:通过继承Socket基类实现ServerSocket和ClientSocket,提供不同的连接策略

Q5: 项目如何保证长连接的稳定性?如何处理心跳检测?

A5: 主要通过以下机制实现:

  1. keepalive机制:
1
2
3
4
5
6
7
8
bool Socket::set_keepalive() {
int flag = 1;
if (setsockopt(m_sockfd, SOL_SOCKET, SO_KEEPALIVE, &flag, sizeof(flag)) < 0) {
log_error("socket set_keep_alive error: errno=%d errmsg=%s", errno, strerror(errno));
return false;
}
return true;
}
  1. 超时检测:
  • 通过epoll的timeout参数实现超时检测
  • 配合TaskFactory管理连接状态
  • 异常情况及时清理资源