编写一段代码测试TcpServer类的功能
#include <muduo/net/TcpServer.h>
#include <muduo/net/EventLoop.h>
#include <muduo/net/InetAddress.h>
#include <stdio.h>
using namespace muduo;
using namespace muduo::net;
void onConnection(const TcpConnectionPtr& conn)
{
if (conn->connected())
{
printf("onConnection(): new connection [%s] from %s\n",
conn->name().c_str(),
conn->peerAddress().toIpPort().c_str());
}
else
{
printf("onConnection(): connection [%s] is down\n",
conn->name().c_str());
}
}
void onMessage(const TcpConnectionPtr& conn,
const char* data,
ssize_t len)
{
printf("onMessage(): received %zd bytes from connection [%s]\n",
len, conn->name().c_str());
}
int main()
{
printf("main(): pid = %d\n", getpid());
InetAddress listenAddr(8888);
EventLoop loop;
TcpServer server(&loop, listenAddr, "TestServer");
server.setConnectionCallback(onConnection);
server.setMessageCallback(onMessage);
server.start();
loop.loop();
}
1.构造一个TcpServer
TcpServer server(&loop, listenAddr, "TestServer");
TcpServer的构造函数作用如下:
①.构造一个TcpServer::acceptor_,用于在该服务器上关注侦听套接字是否可读,TcpServer::acceptor_的具体构造过程如下:创建监听套接字Acceptor::acceptSocket_,创建Acceptor::acceptChannel_负责Acceptor::acceptSocket_的I/O事件分发,将Acceptor::handleRead()注册给Channel_::readCallback_,使在Acceptor::acceptSocket_可读时调用Acceptor::handleRead()。
②.将net::defaultConnectionCallback()(此函数定义在Callbacks.h中)注册给TcpServer::connectionCallback_(),将net::defaultMessageCallback()注册给TcpServer::messageCallback_()。
③.调用setNewConnectionCallback(const NewConnectionCallback& cb)将TcpServer::newConnection(int sockfd, const InetAddress& peerAddr)注册给刚刚构造的TcpServer::acceptor_中的Acceptor::newConnectionCallback_(int sockfd, const InetAddress& peerAddr)。
TcpServer构造完成后,若Acceptor::acceptSocket_有事件可读,则函数的调用流程如下:
Channel::handleEvent(Timestamp receiveTime)>>Channel_::readCallback_(Timestamp receiveTime)>>Acceptor::handleRead()>>Acceptor::newConnectionCallback_(int sockfd, const InetAddress& peerAddr)>>TcpServer::newConnection(int sockfd, const InetAddress& peerAddr)
2.注册回调函数
server.setConnectionCallback(onConnection);
server.setMessageCallback(onMessage);
将onConnection()注册给连接建立时的回调函数TcpServer::connectionCallback_()。
将onMessage()注册给消息到达时的回调函数TcpServer::messageCallback_()。
3.启动服务器TcpServer
server.start();
void TcpServer::start()
{
if (!started_)
{
started_ = true;
threadPool_->start(threadInitCallback_);
}
if (!acceptor_->listenning())
{
// get_pointer返回原生指针
loop_->runInLoop(
boost::bind(&Acceptor::listen, get_pointer(acceptor_)));
}
}
TcpServer::start()调用Acceptor::listen()成员函数执行Socket::listen(),之后调用Channel::enableReading()设置通道Acceptor::acceptChannel_关注Acceptor::acceptSocket_可读事件,并调用Channel::update()维护和更新poller中的文件描述符列表PollPoller::pollfds_,用于注册或者更新通道所关注的事件。
函数调用过程如下:
TcpServer::start()
.>>EventLoop::runInLoop(const Functor& cb)>>Acceptor::listen()>>Socket::listen()
.>>Channel::enableReading()>>Channel::update()>>EventLoop::updateChannel(Channel* channel)>>PollPoller::updateChannel(Channel* channel)
4.运行事件循环函数EventLoop::loop()
loop.loop();
void EventLoop::loop()
{
assert(!looping_);
// 断言当前处于创建该对象的线程中
assertInLoopThread();
looping_ = true;
quit_ = false;
LOG_TRACE << "EventLoop " << this << " start looping";
//::poll(NULL, 0, 5*1000);
while (!quit_)
{
//清空vector<Channel*>即ChannelList的成员
activeChannels_.clear();
//调用poll()获得当前活动事件的channel列表activeChannels,并返回当前时间
pollReturnTime_ = poller_->poll(kPollTimeMs, &activeChannels_);
//++iteration_;
if (Logger::logLevel() <= Logger::TRACE)
{
printActiveChannels();
}
// TODO sort channel by priority
eventHandling_ = true;
//依次调用activeChannels_中每个channel的handleEvent()函数
for (ChannelList::iterator it = activeChannels_.begin();
it != activeChannels_.end(); ++it)
{
currentActiveChannel_ = *it;
currentActiveChannel_->handleEvent(pollReturnTime_);
}
currentActiveChannel_ = NULL;
eventHandling_ = false;
//调用pendingFunctors_里面的所有函数
doPendingFunctors();
}
LOG_TRACE << "EventLoop " << this << " stop looping";
looping_ = false;
}
此函数的功能如下:
①.EventLoop::loop()调用PollPoller::poll(int timeoutMs, ChannelList* activeChannels),之后调用::poll(&pollfds_.begin(), pollfds_.size(), timeoutMs),获得在TcpServer::start()中由PollPoller::updateChannel(Channel* channel)更新后pollfds_中的pollfd::revents_不为空的Channel,再调用PollPoller::fillActiveChannels(int numEvents,ChannelList* activeChannels)填充活动通道的列表EventLoop::activeChannels,并返回当前时间。
②.在得到EventLoop::activeChannels后,依次调用EventLoop::activeChannels中每个Channel的Channel::handleEvent(Timestamp receiveTime),处理Channel的事件,Channel::handleEvent(Timestamp receiveTime)调用Channel_::readCallback_(receiveTime),而此前将Acceptor::handleRead()注册给了Channel_::readCallback_(receiveTime),因此回调Acceptor::handleRead(),之后调用Acceptor::newConnectionCallback_(int sockfd, const InetAddress& peerAddr),即TcpServer::newConnection(int sockfd, const InetAddress& peerAddr)。
③.TcpServer::newConnection(int sockfd, const InetAddress& peerAddr)为监听套接字acceptSocket_可读时调用的表示新连接建立的函数,该函数建立一个新的TcpConnection对象,即TcpConnection::conn,TcpConnection::conn构造过程如下:
用文件描述符sockfd构造一个用于IO事件的套接字TcpConnection::socket_,同时构造一个负责TcpConnection::socket_上IO事件的TcpConnection::channel_,之后注册TcpConnection::channel_里面的各个回调函数,调用Channel_::setReadCallback(const ReadEventCallback& cb)将TcpConnection::handleRead(Timestamp receiveTime)注册给通道可读事件到来的时候的回调函数Channel_::readCallback_(),调用Channel_::setWriteCallback(const EventCallback& cb)将TcpConnection::handleWrite()注册给通道可写事件到来的时候的回调函数Channel_::writeCallback_(),调用Channel_::setCloseCallback(const EventCallback& cb)将TcpConnection::handleClose()注册给连接关闭的时候的回调函数Channel_:closeCallback_ (),调用Channel_::setErrorCallback(const EventCallback& cb)将TcpConnection::handleError()注册给发生错误的时候的回调函数Channel_::errorCallback_()。
④.TcpConnection::conn构造完成后,调用TcpConnection::setConnectionCallback(const ConnectionCallback& cb)将TcpServer::connectionCallback_()注册给连接到来时的回调函数TcpConnection::connectionCallback_(),调用TcpConnection::setMessageCallback(const MessageCallback& cb)将TcpServer::messageCallback_()注册给连接到来时的回调函数TcpConnection::messageCallback_(),调用TcpConnection::setWriteCompleteCallback(const WriteCompleteCallback& cb)将TcpServer::writeCompleteCallback_()注册给连接到来时的回调函数TcpConnection::writeCompleteCallback_(),调用TcpConnection::setCloseCallback(const CloseCallback& cb)将TcpServer::removeConnection(const TcpConnectionPtr& conn)注册给连接到来时的回调函数TcpConnection::closeCallback_()。注册完各个回调函数后,通过EventLoop::runInLoop(const Functor& cb)调用TcpConnection::connectEstablished(),调用Channel::enableReading()使Channel::channel_关注TcpConnection::socket_可读事件,并调用Channel::update()维护和更新poller中的文件描述符列表PollPoller::pollfds_,用于注册或者更新Channel::channel_所关注的事件。最后调用TcpConnection::connectionCallback_(),即TcpServer::connectionCallback_(),该函数被onConnection(const TcpConnectionPtr& conn)注册,至此,连接已完成。
⑤.最后,调用EventLoop::doPendingFunctors()把EventLoop::pendingFunctors_里的函数都执行掉。
⑥.由于while (!quit_)仍然成立,继续循环,第二次循环开始时,调用vector::clear()清空当前的活跃通道列表EventLoop::activeChannels_,之后重复①,此时不仅需要关注新连接建立的事件,还需要关注已经建立的连接上的IO事件。
函数调用过程如下:
EventLoop::loop()
.>>PollPoller::poll(int timeoutMs, ChannelList* activeChannels)>>::poll(&pollfds_.begin(), pollfds_.size(), timeoutMs)>>PollPoller::fillActiveChannels(int numEvents,ChannelList* activeChannels)
.>>Channel::handleEvent(Timestamp receiveTime)>>Channel_::readCallback_(receiveTime)>>Acceptor::handleRead()>>Acceptor::newConnectionCallback_(int sockfd, const InetAddress& peerAddr)>>TcpServer::newConnection(int sockfd, const InetAddress& peerAddr)>>TcpConnection::TcpConnection(EventLoop* loop,const string& nameArg, int sockfd, const InetAddress& localAddr, const InetAddress& peerAddr)>>Channel_::setReadCallback(const ReadEventCallback& cb)>>Channel_::setWriteCallback(const EventCallback& cb)>>Channel_::setCloseCallback(const EventCallback& cb)>>Channel_::setErrorCallback(const EventCallback& cb)>>TcpConnection::setConnectionCallback(const ConnectionCallback& cb)>>TcpConnection::setMessageCallback(const MessageCallback& cb)>>TcpConnection::setWriteCompleteCallback(const WriteCompleteCallback& cb)>>TcpConnection::setCloseCallback(const CloseCallback& cb)>>EventLoop::runInLoop(const Functor& cb)>>TcpConnection::connectEstablished()>>Channel::enableReading()>>Channel::update()>>EventLoop::updateChannel(Channel* channel)>>PollPoller::updateChannel(Channel* channel)>>TcpConnection::connectionCallback_()>>TcpServer::connectionCallback_()>>onConnection(const TcpConnectionPtr& conn)
.>>EventLoop::doPendingFunctors()
.>>第二次循环开始,假设有一条消息到来
.>>vector::clear()
.>>PollPoller::poll(int timeoutMs, ChannelList* activeChannels)>>::poll(&pollfds_.begin(), pollfds_.size(), timeoutMs)>>PollPoller::fillActiveChannels(int numEvents,ChannelList* activeChannels)
.>>Channel::handleEvent(Timestamp receiveTime)>>Channel_::readCallback_(receiveTime)>>TcpConnection::handleRead(Timestamp receiveTime)>>TcpConnection::messageCallback_()