muduo的Tcpserver类源码分析
TcpServer是创建一个服务器的开始。
TcpServer class的功能是管理accept(2)获得的TcpConnection。TcpServer是供用户直接使用的,生命期由用户控制
TcpServer新建连接的相关函数调用顺序如图下所示:
其中Channel::handleEvent()的触发条件是listening socket可读,表明有新连接到达。TcpServer会为新连接创建对应的TcpConnection对象。
TcpServer class的接口和属性如下图所示:
主要讲下TcpServer主要的几个函数
首先讲下TcpServer的构造函数:
TcpServer::TcpServer(EventLoop* loop,
const InetAddress& listenAddr,
const string& nameArg,
Option option)
: loop_(CHECK_NOTNULL(loop)),
ipPort_(listenAddr.toIpPort()),
name_(nameArg),
acceptor_(new Acceptor(loop, listenAddr, option == kReusePort)),
threadPool_(new EventLoopThreadPool(loop, name_)),
connectionCallback_(defaultConnectionCallback),
messageCallback_(defaultMessageCallback),
nextConnId_(1)
{
acceptor_->setNewConnectionCallback(
std::bind(&TcpServer::newConnection, this, _1, _2));
}
最重要的是 acceptor_(new Acceptor(loop, listenAddr, option == kReusePort)),服务器首先需要一个监听套接字来监听是否有新的连接加入,而Acceptor负责监听套接字的创建和端口绑定。
void start(){
threadPool_->start(threadInitCallback_); //启动线程池管理器
loop_->runInLoop(
std::bind(&Acceptor::listen, get_pointer(acceptor_))); //把Acceptor::listen()加入调度队列或立即调用
};
//处理监听套接字接收到的新的连接请求
//此函数被注册到Acceptor::newConnectionCallback(在TcpServer的构造函数中注册),之后被Acceptor::handleRead()中accept()新连接后调用
void TcpServer::newConnection(int sockfd, const InetAddress& peerAddr);
{
EventLoop* ioLoop=threadPool_->getNextLoop(); //线程池中取一个线程分配给新建连接 RR方式
TcpConnectionPtr conn(new TcpConnection(ioLoop,
connName,
sockfd,
localAddr,
peerAddr)); // 创建一个TcpConnextion对象,表示每一个已连接
connections_[connName] = conn;
conn->setConnectionCallback(connectionCallback_); // connectionCallback_,messageCallback_,writeCompleteCallback_需要用户来提供,应该会注册到TcpConnection中的Channel对象的中
conn->setMessageCallback(messageCallback_);
conn->setWriteCompleteCallback(writeCompleteCallback_);
conn->setCloseCallback(
std::bind(&TcpServer::removeConnection, this, _1)); // FIXME: unsafe
ioLoop->runInLoop(std::bind(&TcpConnection::connectEstablished, conn));
}
我的理解是首先创建一个EventLoop(有点儿主线程的意思,),创建一个TcpServer来管理监听的套接字和连接套接字的信息,Acceptor class负责监听套接字,这是一个内部类,对外是隐藏的。当poll被监听套接字**时,调用AcceptChannel中的handleEvent(),在handleEvent()中从线程池中取得一个线程(采用RR的方法),并且new一个TcpConnection对象,TcpConnection负责管理连接套接字,每一个连接套接字有一个TcpConnection相对应,这个线程负责处理该已连接套接字。