一、
二、各类含义
1、EventLoop类
在Muduo网络库中,EventLoop类是核心组件之一。它的作用是**提供事件循环机制,
**负责管理和调度各种事件(如I/O事件、定时器事件),确保这些事件能够及时被处理,从而实现高效的网络通信。
1.1EventLoop的工作流程大致如下:
创建一个EventLoop对象。
将需要监控的文件描述符和对应的事件类型注册到EventLoop中。
启动事件循环,进入循环体。
在循环体中,使用epoll等系统调用等待事件的发生。
当有事件发生时,调用相应的回调函数来处理这些事件。
重复步骤4和5,直到事件循环停止。
1.2主要属性
looping_:标志事件循环是否正在运行。
quit_:标志是否需要退出事件循环。
poller_:指向Poller对象的指针,Poller封装了具体的I/O多路复用机制(如epoll)。
activeChannels_:存储当前活跃的Channel对象列表。
currentActiveChannel_:当前正在处理的Channel对象。
eventHandling_:标志是否正在处理事件。
callingPendingFunctors_:标志是否正在调用待处理的任务。
mutex_:用于保护任务队列的互斥锁。
pendingFunctors_:待处理任务的队列。
threadId_:运行该EventLoop的线程ID。
timerQueue_:定时器队列,用于管理定时器事件。
1.3主要方法
loop(): 启动事件循环。该方法会进入循环体,不断地等待并处理事件,直到调用quit()方法。
quit(): 退出事件循环。该方法会设置quit_标志,在安全的时机退出事件循环。
runInLoop(Functor cb): 在当前事件循环中执行指定的任务。如果在其他线程中调用该方法,会将任务添加到pendingFunctors_队列中。
queueInLoop(Functor cb):将任务添加到待处理任务队列中,在事件循环的下一次迭代时执行。
updateChannel(Channel channel): 更新一个Channel,即在Poller中更新该Channel所关注的事件。
removeChannel(Channel channel):移除一个Channel,即在Poller中取消对该Channel的关注。
hasChannel(Channel channel):检查Poller中是否包含指定的Channel。
wakeup(): 唤醒事件循环,使其从阻塞状态中退出。通常用于在其他线程中添加任务后通知事件循环执行。
doPendingFunctors():执行待处理任务队列中的所有任务。该方法在事件循环中调用,以确保所有任务都能在事件循环中安全地执行。
handleRead():处理读事件,通常用于处理唤醒事件循环的事件。
handleError():处理错误事件。
1.4事件循环工作流程
启动事件循环:
调用loop()方法,进入事件循环。
等待事件:
调用Poller的poll()方法等待事件发生。
处理事件:
遍历活跃的Channel列表,调用每个Channel的事件处理回调函数。
处理定时器事件:
检查并处理到期的定时器事件。
执行待处理任务:
调用doPendingFunctors()方法,执行在其他线程中添加的任务。
重复循环:
重复上述步骤,直到调用quit()方法退出事件循环。
2、Poller类
Poller类是EventLoop的一个重要组件,负责具体的“I/O多路复用机制”的 “封装”。
Poller类是一个“抽象基类”,它提供了统一的接口,以便不同的具体实现(如使用epoll或poll)
可以继承并实现这些接口(对应两个派生类:PollPoller和EpollPoller)。
具体使用中会根据环境变量的设置选择是使用epoll还是poll方法。
Poller类的主要作用是:管理和分发I/O事件。(实际操作的不是I/O事件,而是Channel类!!)
2.1 主要属性
ownerLoop_:指向所属的EventLoop对象。确保Poller在正确的事件循环线程中被使用。
channels_:保存文件描述符到Channel对象的映射,便于快速查找。
2.2 主要方法
virtual Timestamp poll(int timeoutMs, ChannelList activeChannels) = 0*:
纯虚函数,“等待事件发生”并将活跃的Channel“填充到”activeChannels列表中。timeoutMs指定等待事件的超时时间。
virtual void updateChannel(Channel channel) = 0*:
纯虚函数,更新指定的Channel。通常涉及将该Channel的文件描述符和事件类型“添加或修改”到多路复用机制中。
virtual void removeChannel(Channel channel) = 0*: 纯虚函数,从多路复用机制中“移除”指定的Channel。
bool hasChannel(Channel channel) const*: 检查Poller中是否包含指定的Channel。通过查找channels_映射实现。
2.3 主要工作流程
创建并初始化Poller:
在创建EventLoop对象时,会根据系统和配置选择具体的Poller实现(如EPollPoller或PollPoller)。
添加、更新和移除Channel:
通过调用updateChannel和removeChannel方法,管理Channel对象及其关注的事件。
等待事件:
在事件循环中,调用poll方法“等待事件发生”,并获取活跃的Channel列表。
分发事件:
将活跃的事件“分发给”相应的Channel对象,Channel对象再调用预先设置的回调函数处理事件。
3、Channel类
在 Muduo 网络库中,Channel 类是一个关键组件,用于表示和管理 文件描述符fd及其相关的 I/O 事件。
它负责将底层的 “I/O 事件” 和 应用层的“回调函数”关联起来,使得事件处理更加抽象和灵活。
3.1 主要属性
loop_: 指向所属的 EventLoop 对象,确保 Channel 所属的事件循环。
fd_:文件描述符,表示这个 Channel 关注的具体文件描述符。
events_:表示当前 Channel 感兴趣的事件,由“位掩码”表示,如 EPOLLIN, EPOLLOUT 等。
revents_:表示实际发生的事件,由 EventLoop 设置。
index_:用于在 Poller 中记录 Channel 的状态(是否在 epoll 或 poll 的关注列表中)。
tied_:表示是否与某个对象(如 TcpConnection)绑定,防止对象在事件处理过程中被销毁。
eventHandling_:标志当前是否正在处理事件。
addedToLoop_:标志当前 Channel 是否已经添加到事件循环中。
readCallback_、writeCallback_、errorCallback_、closeCallback_:一系列的回调函数,用于处理不同类型的事件。
3.2 主要方法
void handleEvent(Timestamp receiveTime);
用途:处理发生的事件,根据 revents_ 的值“调用相应的回调函数”。
参数:receiveTime,表示事件发生的时间戳。
实现逻辑:根据 revents_ 的值,依次调用(错误、关闭、读、写)事件的回调函数。
setReadCallback:设置读事件回调函数;
setWriteCallback:设置写事件回调函数;
setErrorCallback:设置错误事件回调函数;
setCloseCallback:设置关闭事件回调函数。
void setReadCallback(ReadEventCallback cb) { readCallback_ = std::move(cb); } // 设置读事件回调函数。
void setWriteCallback(EventCallback cb) { writeCallback_ = std::move(cb); } // 设置写事件回调函数。
void setErrorCallback(EventCallback cb) { errorCallback_ = std::move(cb); }
void setCloseCallback(EventCallback cb) { closeCallback_ = std::move(cb); }
用途:将用户定义的回调函数**Callback_,绑定到相应的事件上。
参数:回调函数对象,使用 std::function(包装器) 封装。
事件“启用/禁用”
void enableReading() { events_ |= kReadEvent; update(); } //事件启用
void enableWriting() { events_ |= kWriteEvent; update(); } //事件启用
void disableReading() { events_ &= ~kReadEvent; update(); } //事件禁用
void disableWriting() { events_ &= ~kWriteEvent; update(); } //事件禁用
void disableAll() { events_ = kNoneEvent; update(); } //事件禁用
用途:启用或禁用 Channel 对特定事件的监听。
实现逻辑:修改 events_ 的值,并调用 update() 方法将修改通知给 Poller。
update()
用途:将 Channel 的状态更新到 Poller 中。
实现逻辑:调用 EventLoop 的 updateChannel 方法,将当前 Channel 的状态同步到 Poller。
void Channel::update() {
addedToLoop_ = true;
loop_->updateChannel(this);
}
remove()
用途:从 Poller 中移除当前 Channel。
实现逻辑:调用 EventLoop 的 removeChannel 方法,从 Poller 中删除当前 Channel。
void Channel::remove() {
addedToLoop_ = false;
loop_->removeChannel(this);
}
tie()
void tie(const std::shared_ptr<void>& obj);
用途:将 Channel 绑定到一个对象(通常是 TcpConnection),防止在处理事件时该对象被销毁。
参数:一个 std::shared_ptr<void> 对象。
实现逻辑:存储 weak_ptr,在处理事件时检查对象是否有效。
void Channel::tie(const std::shared_ptr<void>& obj) {
tie_ = obj;
tied_ = true;
}
其他辅助方法
int fd() const { return fd_; } // 返回文件描述符。
int events() const { return events_; } // 返回当前感兴趣的事件。
void set_revents(int revt) { revents_ = revt; } // 设置实际发生的事件。
bool isNoneEvent() const { return events_ == kNoneEvent; } // 检查是否没有感兴趣的事件。
4、TcpConnection类
在 Muduo 网络库中,TcpConnection 类是一个重要的组件,表示一个“已建立的TCP连接” 和 控制该TCP连接的方法
(连接建立和关闭和销毁),以及这个TCP连接的服务端和客户端的套接字地址信息等。
它封装了 socket 文件描述符,并提供了“处理连接”的各种事件和操作的功能。
TcpConnection 类主要负责(管理连接的生命周期、数据的读写、回调函数的调用)等。
4.1 主要属性
loop_:所属的 EventLoop 对象,表示这个连接归属于哪个事件循环。
name_:连接的名称,通常用来唯一标识一个连接。
state_:连接的状态,如连接建立、连接关闭等。
channel_:对应的 Channel 对象,用于管理 socket 的事件。
socket_:封装的 socket 文件描述符。
inputBuffer_:这是一个Buffer类,是该TCP连接对应的用户接收缓冲区。
outputBuffer_:也是一个Buffer类,不过是用于“暂存”那些暂时发送不出去的待发送数据。
因为Tcp发送缓冲区是有大小限制的,假如达到了高水位线,就没办法把发送的数据
通过send()直接拷贝到Tcp发送缓冲区,而是暂存在这个outputBuffer_中,等TCP发送缓冲区有空间了,
触发可写事件了,再把outputBuffer_中的数据拷贝到Tcp发送缓冲区中。
connetionCallback_、messageCallback_、writeCompleteCallback_、closeCallback_:
用户会自定义 [连接建立/关闭后的处理函数] 、[收到消息后的处理函数]、[消息发送完后的处理函数]以及Muduo库中定义的[连接关闭后的处理函数]。
这四个函数都会分别注册给这四个成员变量保存。
4.2 主要方法
内部事件处理:handleRead()、handleWrite()、handleClose()、handleError()
私有成员方法,在一个“已经建立好的TCP连接”上主要会发生四类事件:可读事件、可写事件、连接关闭事件、错误事件。
当“事件监听器”监听到一个连接发生了以上的事件,那么就会在EventLoop中“调用”这些事件对应的处理函数,
同时,accept返回已连接套接字所绑定的Channel中注册了这四种回调函数。
void handleRead(Timestamp receiveTime);
void handleWrite();
void handleClose();
void handleError();
// 处理读、写、关闭和错误事件,由 Channel 对象调用。
连接状态的获取和设置
const std::string& name() const { return name_; }
const InetAddress& localAddress() const { return localAddr_; }
const InetAddress& peerAddress() const { return peerAddr_; }
bool connected() const { return state_ == kConnected; }
// 获取连接的名称、本地地址、对端地址和连接状态。
回调函数的设置
void setConnectionCallback(const ConnectionCallback& cb) { connectionCallback_ = cb; }
void setMessageCallback(const MessageCallback& cb) { messageCallback_ = cb; }
void setWriteCompleteCallback(const WriteCompleteCallback& cb) { writeCompleteCallback_ = cb; }
void setCloseCallback(const CloseCallback& cb) { closeCallback_ = cb; }
// 设置(连接、消息、写入完成和关闭)的回调函数。
发送数据
void send(const std::string& message);
void send(Buffer* buf);
// 发送数据,将数据添加到输出缓冲区,并调用 `handleWrite` 方法进行实际发送。
关闭连接
void shutdown();
// 关闭写端,触发连接关闭过程。
强制关闭
void forceClose();
// 强制关闭连接,不等待缓冲区的数据发送完毕。
连接建立和销毁
void connectEstablished();
void connectDestroyed();
// 连接建立时的初始化操作 和 连接销毁时的清理操作。
5、Acceptor类
Acceptor 类在 Muduo 网络库中是一个关键组件,主要负责“接受新的客户端连接”并将其传递给“用户定义的回调函数”。
Acceptor 封装了底层的监听 socket 和 Channel,并提供了对新连接的处理逻辑。
5.1 主要属性
loop_:所属的 EventLoop 对象,表示这个 Acceptor 归属于哪个事件循环。
acceptSocket_:监听 socket,封装了底层的 socket 文件描述符。
acceptChannel_:用于监听事件的 Channel 对象。
listenning_:表示是否处于监听状态。
idleFd_:预留的文件描述符,用于处理文件描述符耗尽的情况。
newConnectionCallback_:新连接到达时的回调函数。
5.2 主要方法
监听
void listen();
用途:启动监听 socket 开始接受新的连接。
实现逻辑:调用 Socket 对象的 listen 方法,并将 acceptChannel 设置为可读状态以处理新的连接。
设置回调函数
void setNewConnectionCallback(const NewConnectionCallback& cb) { newConnectionCallback_ = cb; }
用途:设置新连接到达时的回调函数。
处理新连接
void handleRead();
用途:处理新的连接请求,接受连接并调用用户定义的回调函数。
实现逻辑:调用 Socket 对象的 accept 方法获取新的连接文件描述符,并调用 newConnectionCallback_ 处理新连接。
6、TcpServer类
TcpServer 类在 Muduo 网络库中是一个高层次的网络服务器类,负责管理多个 TCP 连接,
并提供了一些便捷的方法来 设置各种回调函数和启动服务器。
它结合了 Acceptor、TcpConnection 等类来处理新的连接和数据传输。
主要属性
loop_:主 EventLoop 对象,用于处理主线程中的事件。
ipPort_:服务器的 IP 和端口。
name_:服务器名称。
acceptor_:Acceptor 对象,负责接受新连接。
threadPool_:用于处理多个 EventLoop 线程的线程池。
connectionCallback_:连接建立或关闭时的回调函数。
messageCallback_:消息到达时的回调函数。
writeCompleteCallback_:数据写入完成时的回调函数。
connections_:管理所有活动连接的容器。
主要方法
void start(); // 启动服务器
// 设置回调函数
void setConnectionCallback(const ConnectionCallback& cb) { connectionCallback_ = cb; }
void setMessageCallback(const MessageCallback& cb) { messageCallback_ = cb; }
void setWriteCompleteCallback(const WriteCompleteCallback& cb) { writeCompleteCallback_ = cb; }
void setThreadNum(int numThreads); // 设置线程数量
void newConnection(int sockfd, const InetAddress& peerAddr); // 处理新连接
// 移除连接
void removeConnection(const TcpConnectionPtr& conn);
void removeConnectionInLoop(const TcpConnectionPtr& conn);