面试题答案
一键面试设计思路
- 连接管理:
- 使用
epoll
创建一个epoll
实例,用于监控所有客户端连接的文件描述符。 - 当有新连接到来时,通过
accept
获取新连接的文件描述符,并将其添加到epoll
监控列表中。 - 对于已建立的连接,通过
epoll_wait
等待事件发生,如可读(有数据到达)或可写(可以发送数据)。
- 使用
- 消息收发机制:
- 当
epoll_wait
返回可读事件时,从对应的文件描述符读取数据。为提高效率,采用合适的缓冲区大小,如使用固定大小的缓冲区或动态分配缓冲区。 - 处理读取到的数据,如解析消息格式、分发消息等。
- 当需要发送数据时,等待
epoll_wait
返回可写事件,然后将数据从缓冲区发送出去。
- 当
- 避免epoll惊群问题:
- 使用
epoll
的EPOLLEXCLUSIVE
标志,该标志可以确保一个文件描述符上的事件只会唤醒一个线程来处理,从而避免惊群。 - 或者使用
SO_REUSEPORT
选项,在多个进程或线程监听同一个端口时,内核会自动将连接均匀分配到各个监听套接字上,减少惊群的可能性。
- 使用
实现要点
- 初始化:
- 创建
epoll
实例:epoll_create1(0)
。 - 创建监听套接字,绑定地址和端口,设置为非阻塞模式。
- 将监听套接字添加到
epoll
实例中,监听EPOLLIN
事件。
- 创建
- 新连接处理:
- 当
epoll_wait
检测到监听套接字有EPOLLIN
事件时,调用accept
接受新连接,得到新连接的文件描述符。 - 将新连接的文件描述符设置为非阻塞模式,并添加到
epoll
实例中,监听EPOLLIN
事件。
- 当
- 消息读取:
- 当
epoll_wait
检测到某个连接有EPOLLIN
事件时,调用recv
或read
函数从该连接的文件描述符读取数据。 - 处理读取到的数据,如解析协议、存储消息等。
- 当
- 消息发送:
- 当需要发送数据时,先将数据准备好,放入发送缓冲区。
- 等待
epoll_wait
检测到该连接有EPOLLOUT
事件时,调用send
或write
函数将数据从发送缓冲区发送出去。
- 错误处理:
- 对
epoll
相关函数(如epoll_create1
、epoll_ctl
、epoll_wait
)的返回值进行检查,处理可能的错误。 - 对
accept
、recv
、send
等函数的返回值进行检查,处理连接异常、数据读写错误等情况,如关闭连接、从epoll
实例中移除文件描述符等。
- 对