前言
这个假期跟着教学视频手写了muduo库,该muduo库是经过改造,不依赖boost库,用C++11重构。
手写muduo库的过程虽然有些枯燥,但学会的东西确实也很多。因为本人基础较差,因此代码几乎全是照抄老师,若涉及侵权请提醒在下删除。
下面附上代码,以及我在写完全部代码后对整个muduo库的调用过程的部分理解,感兴趣的朋友可以看看。
muduo网络库核心代码模块
Channel
其内部成员主要有fd,events(fd感兴趣的事件),loop(用以管理channel和poller,也是channel调用poller的桥梁),以及部分回调函数
Poller 和EPollPoller
其主要作用其实就是epoll_wait,epoll_ctl等作用
EventLoop
事件循环
Socket
获取套接字,设置其配置信息
Acceptor
主要封装了listenfd相关的操作 socket bind listen baseLoop
Buffer
缓冲区
TcpConnection
客户端连接后对应一个TcpConnection
TcpServer
代码
Acceptor
Buffer
Callbacks
Channel
CurrentThread
DefaultPoller
EPollPoller
EventLoop
EventLoopThread
EventLoopThreadPool
InetAddress
Logger
noncopyable
Poller
Socket
TcpConnection
TcpServer
testserver测试代码
Thread
Timestamp
个人理解
1.mainloop初始化的过程,以及设置新连接回调函数的过程
在TcpServer的构造函数中,将TcpServer::newConnection绑定给了Acceptor::newConnectionCallback,(该函数实际是打包chaneel,然后轮询,找subloop)。
在Acceptor的构造函数中,将Acceptor::handleRead绑定给acceptChannel::readCallback
( Acceptor::handleRead的作用就是调用Acceptor::newConnectionCallback,也就是TcpServer::newConnection)。
意思就是调用readCallback就是调用TcpServer::newConnection
重点来了,acceptChannel::readCallback什么时候调用?
答案:在调用Channel::handleEventWithGuard 时,而调用Channel::handleEvent调用Channel::handleEventWithGuard。
那么什么时候调用了Channel::handleEvent呢?在EventLoop中。
我们知道在调用muduo库时,创建了一个loop_,并且最后loop_.loop()开启事件循环。这个loop_就是mainloop的这个loop。查看EventLoop::loop下的代码时发现
while(!quit_)
{
activeChannels_.clear();
pollReturnTime_ = poller_->poll(kPollTimeMs, &activeChannels_);
for (Channel *channel : activeChannels_)
{
channel->handleEvent(pollReturnTime_);
}
doPendingFunctors();
}
channel->handleEvent(pollReturnTime_); 这句代码调用了Channel::handleEven。
再仔细看,for (Channel *channel : activeChannels_)意思是从activeChannel里面来取Channel来调用该Channel的Channel::handleEven。而 activeChannels_ 由谁来设置呢?
别急,我们再看到上面那行代码 pollReturnTime_ = poller_->poll(kPollTimeMs, &activeChannels_);
EventPoller::poll里面实现的是epoll_wait
当其检测到有客户端到来时就会解除阻塞,然后它就会调用EventPoller::fillActiveChannels函数
void EPollPoller::fillActiveChannels(int numEvents, ChannelList *activeChannels) const
{