TcpServer主要功能是管理新的连接到来时创建的TcpConnection,是直接提供给用户使用的类,生命周期由用户控制。Acceptor是创建在TcpServer内部的对象,内部会有一个Channel来专门处理新连接到来事件,新连接到来最终会回调给TcpServer的newconnection来创建新连接,其实前几期muduo内部的机制都讲完了,如果能够理解前面的部分,这两个类基本看下就能知道作用了。
TcpServer
成员变量:
private:
EventLoop* loop_; // the acceptor loop
const string hostport_;
const string name_;
std::unique_ptr<Acceptor> acceptor_;
std::unique_ptr<EventLoopThreadPool> eventLoopThreadPool_;
ConnectionCallback connectionCallback_;
MessageCallback messageCallback_;//回调函数处理消息
WriteCompleteCallback writeCompleteCallback_;
ThreadInitCallback threadInitCallback_;
std::atomic<int> started_;
int nextConnId_;
ConnectionMap connections_;
loop是主线程循环,hostport是传入的需要监听的端口,name是给服务端标记的名字,acceptor是一个新连接接受的对象,eventLoopThreadPool是线程池对象,之后创建了几个回调函数,回调了一些函数来处理一些自定义的消息,之后started_是线程池启动的标志位,nextConnid是标记连接的序号,最后的ConnectionMap是一个存放TcpConnection的容器。
重要函数及作用:
创建
TcpServer::TcpServer(EventLoop* loop,
const InetAddress& listenAddr,
const std::string& nameArg,
Option option)
: loop_(loop),
hostport_(listenAddr.toIpPort()),
name_(nameArg),
acceptor_(new Acceptor(loop, listenAddr, option == kReusePort)),
//threadPool_(new EventLoopThreadPool(loop, name_)),
connectionCallback_(defaultConnectionCallback),
messageCallback_(defaultMessageCallback),
started_(0),
nextConnId_(1)
{
acceptor_->setNewConnectionCallback(std::bind(&TcpServer::newConnection, this, std::placeholders::_1, std::placeholders::_2));
}
可以看到,在构造函数参数中传入了主线程循环,监听socket地址信息,初始化参数列表中用传入的参数和一些固定值初始化了一些变量,new了一个新连接接受处理类acceptor,设置了外部回调,然后在函数体中注册了一个这个类最关键的回调——新连接回调。
启动线程池
void TcpServer::start(int workerThreadCount/* = 4*/)
{
if(started_ == 0) //没有启动
{
//启动线程池管理
eventLoopThreadPool_.reset(new EventLoopThreadPool());
eventLoopThreadPool_->init(loop_, workerThreadCount);
eventLoopThreadPool_->start();
//threadPool_->start(threadInitCallback_);
//assert(!acceptor_->listenning());
//将函数对象放入队列或者立即执行
loop_->runInLoop(std::bind(&Acceptor::listen, acceptor_.get()));//监听端口并注册进多路复用
started_ = 1;
}
}
创建线程池,在线程池中会根据workerThreadCount创建对应线程,之后在当前循环(主线程循环)中进行端口的监听以及注册,置启动标志位为1。
新连接到来
void TcpServer::newConnection(int sockfd, const InetAddress& peerAddr)
{
loop_->assertInLoopThread();
//给新连接分配线程
EventLoop* ioLoop = eventLoopThreadPool_->getNextLoop();
char buf[32];
snprintf(buf, sizeof buf, ":%s#%d", hostport_.c_str(), nextConnId_);
++nextConnId_;
string connName = name_ + buf;
LOGD("TcpServer::newConnection [%s] - new connection [%s] from %s", name_.c_str(), connName.c_str(), peerAddr.toIpPort().c_str());
InetAddress localAddr(sockets::getLocalAddr(sockfd));
// FIXME poll with zero timeout to double confirm the new connection
// FIXME use make_shared if necessary
TcpConnectionPtr conn(new TcpConnection(ioLoop, connName, sockfd, localAddr, peerAddr));
//放入map容器管理
connections_[connName] = conn;
conn->setConnectionCallback(connectionCallback_);//指向业务层Session
conn->setMessageCallback(messageCallback_);
conn->setWriteCompleteCallback(writeCompleteCallback_);
conn->setCloseCallback(std::bind(&TcpServer::removeConnection, this, std::placeholders::_1)); // FIXME: unsafe
//该线程分离完io事件后,立即调用TcpConnection::connectEstablished
ioLoop->runInLoop(std::bind(&TcpConnection::connectEstablished, conn));
}
由Accepter检测到新连接回调到TcpServer::newConnection,创建相应的TcpConnection并传入eventloop,对端地址簇,本段地址簇等信息,最后将TcpConnection传入Map容器,并向其注册一些回调函数。最后在对应线程的eventloop中调用连接建立函数。
移除连接
void TcpServer::removeConnection(const TcpConnectionPtr& conn)
{
// FIXME: unsafe
loop_->runInLoop(std::bind(&TcpServer::removeConnectionInLoop, this, conn));
}
void TcpServer::removeConnectionInLoop(const TcpConnectionPtr& conn)
{
//主线程执行
loop_->assertInLoopThread();
LOGD("TcpServer::removeConnectionInLoop [%s] - connection %s", name_.c_str(), conn->name().c_str());
size_t n = connections_.erase(conn->name()); //引用计数减1,当前应该是2
//(void)n;
//assert(n == 1);
if (n != 1)
{
//出现这种情况,是TcpConneaction对象在创建过程中,对方就断开连接了。
LOGD("TcpServer::removeConnectionInLoop [%s] - connection %s, connection does not exist.", name_.c_str(), conn->name().c_str());
return;
}
EventLoop* ioLoop = conn->getLoop();
ioLoop->queueInLoop(std::bind(&TcpConnection::connectDestroyed, conn));
//执行完这个函数 会释放handleclose栈上对象 引用计数-1
//当前应该是1
}
当连接断开时通过对应Channel的HandleEvent最终会调用到removeConnection函数,在函数中将removeConnectionInLoop加入主线程执行队列,之后在主线程执行removeConnectionInLoop函数。在removeConnectionInLoop中将需要断开连接的TcpConnection从map容器中移除,再在对应的线程eventloop中将其销毁,关于TcpConnection的生命周期还请看上篇博客。
结束
void TcpServer::stop()
{
if (started_ == 0)
return;
for (ConnectionMap::iterator it = connections_.begin(); it != connections_.end(); ++it)
{
TcpConnectionPtr conn = it->second;
it->second.reset();
conn->getLoop()->runInLoop(std::bind(&TcpConnection::connectDestroyed, conn));
conn.reset();
}
eventLoopThreadPool_->stop();
started_ = 0;
}
结束线程池,主动关闭销毁每个连接,没啥好讲的。
Acceptor
成员变量:
private:
EventLoop* loop_;
Socket acceptSocket_; //用于服务端监听的真正的socket
Channel acceptChannel_;
NewConnectionCallback newConnectionCallback_;
bool listenning_;
loop是主线程循环,也从TcpServer中传入loop,acceptSocket是服务端监听socket,Channel是专门用于接受连接事件,放在了主IO线程的通道,newConnectionCallback_是注册回调,指向了TcpServer::newConnection(),listenning是监听中标志位。
重要函数及作用:
初始化
Acceptor::Acceptor(EventLoop* loop, const InetAddress& listenAddr, bool reuseport)
: loop_(loop),
acceptSocket_(sockets::createNonblockingOrDie()),
acceptChannel_(loop, acceptSocket_.fd()),
listenning_(false)
{
#ifndef _WIN64
idleFd_ = ::open("/dev/null", O_RDONLY | O_CLOEXEC);
#endif
acceptSocket_.setReuseAddr(true);
acceptSocket_.setReusePort(reuseport);
acceptSocket_.bindAddress(listenAddr);
acceptChannel_.setReadCallback(std::bind(&Acceptor::handleRead, this));
}
由TcpServer创建,传入主线程循环loop,监听地址信息等参数,参数初始化列表中构造了acceptSocket和acceptChannel,函数体中设置socket信息以及设置了Channel到TcpServer的回调函数。
监听
void Acceptor::listen()
{
loop_->assertInLoopThread();
listenning_ = true;
acceptSocket_.listen(); //监听对应端口
acceptChannel_.enableReading(); //注册到poll中
}
开始监听端口,并将acceptChannel注册到IO复用poll中去。
处理新连接事件
void Acceptor::handleRead()
{
loop_->assertInLoopThread();
InetAddress peerAddr;
//FIXME loop until no more
int connfd = acceptSocket_.accept(&peerAddr); //返回创建的新的套接字
if (connfd >= 0)
{
string hostport = peerAddr.toIpPort();
LOGD("Accepts of %s", hostport.c_str());
//newConnectionCallback_实际指向TcpServer::newConnection(int sockfd, const InetAddress& peerAddr)
if (newConnectionCallback_)
{
newConnectionCallback_(connfd, peerAddr);
}
else
{
sockets::close(connfd);
}
}
else
{
LOGSYSE("in Acceptor::handleRead");
#ifndef _WIN64
if (errno == EMFILE)
{
::close(idleFd_);
idleFd_ = ::accept(acceptSocket_.fd(), NULL, NULL);
::close(idleFd_);
idleFd_ = ::open("/dev/null", O_RDONLY | O_CLOEXEC);
}
#endif
}
}
由IO多路复用检测到事件,通过Channel处理可读事件,回调到该函数的handleRead(),最终触发TcpServer::newConnection创建新连接。