muduo中的Acceptor类的主要功能是socket、bind、listen,Acceptor用于accept接受TCP连接
一般来说,在上层应用程序中,我们不直接使用Acceptor,而是把它作为TcpServer的成员
TcpServer还包含了一个TcpConnection列表这是一个已连接列表。TcpConnection与Acceptor类似,有两个重要的数据成员,Socket与Channel。
下面分析一个程序的执行步骤:
#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();
}
分析:
TcpServer server(&loop, listenAddr, "TestServer");
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)
{
//对accptor_设置一个回调函数
//Acceptor::handleRead函数中会回调用TcpServer::newConnection
//_1对应的是socket文件描述符,_2对应的是对等方的地址
acceptor_->setNewConnectionCallback(
boost::bind(&TcpServer::newConnection, this, _1, _2));
}
//启动
server.start();
//该函数可以跨线程调用
void TcpServer::start()
{
if (started_.getAndSet(1) == 0)
{
threadPool_->start(threadInitCallback_);
//判断是否处于监听状态
assert(!acceptor_->listenning());
loop_->runInLoop(
//现在服务器处于监听的状态了
boost::bind(&Acceptor::listen, get_pointer(acceptor_)));
}
}
void Acceptor::listen()
{
loop_->assertInLoopThread();
listenning_ = true;
//监听
acceptSocket_.listen();
//关注可读事件,TcpConnection所对应的通道加入到Poller关注
acceptChannel_.enableReading();
}
loop.loop();
void EventLoop::loop()
{
.....
//遍历活动通道进行处理
for (ChannelList::iterator it = activeChannels_.begin();
it != activeChannels_.end(); ++it)
{
//当前的处理通道
currentActiveChannel_ = *it;
//调用handleEvent处理通道
currentActiveChannel_->handleEvent(pollReturnTime_);
}
.....
}
/*
handleEvent()又会调用Acceptor中的handleRead
在Acceptor的构造函数中有handleRead()的注册,
所以能够由handleEvent()找到handleRead()
*/
Acceptor::Acceptor(EventLoop* loop, const InetAddress& listenAddr, bool reuseport)
{
//绑定,监听是下面的listen()函数
acceptSocket_.bindAddress(listenAddr);
//acceptChannel_设置一个读的回调函数
acceptChannel_.setReadCallback(
boost::bind(&Acceptor::handleRead, this));
}
void Acceptor::handleRead()
{
loop_->assertInLoopThread();
//准备一个地址,接受对等方地址
InetAddress peerAddr;
//FIXME loop until no more
//得到了一个连接
int connfd = acceptSocket_.accept(&peerAddr);
if (connfd >= 0)
{
// string hostport = peerAddr.toIpPort();
// LOG_TRACE << "Accepts of " << hostport;
//如果上层定义了回调函数,则执行
if (newConnectionCallback_)
{
//传递套接字以及对等方的地址
newConnectionCallback_(connfd, peerAddr);
}
else
{
sockets::close(connfd);
}
}
}
//一个新的连接之后
void TcpServer::newConnection(int sockfd, const InetAddress& peerAddr)
{
....
//创建一个连接对象
TcpConnectionPtr conn(new TcpConnection(ioLoop,
connName,
sockfd,
localAddr,
peerAddr));
//将连接对象放到一个map容器中
connections_[connName] = conn;
对这个连接对象设置回调函数
conn->setConnectionCallback(connectionCallback_);
conn->setMessageCallback(messageCallback_);
conn->setWriteCompleteCallback(writeCompleteCallback_);
conn->setCloseCallback(
boost::bind(&TcpServer::removeConnection, this, _1)); // FIXME: unsafe
ioLoop->runInLoop(boost::bind(&TcpConnection::connectEstablished, conn));
}
//当连接到来的时候
void TcpConnection::connectEstablished()
{
loop_->assertInLoopThread();
assert(state_ == kConnecting);
setState(kConnected);
//tie的参数是shared_ptr,shared_from_this()获得一个自身的share_ptr对象
channel_->tie(shared_from_this());
//TcpConnection所对应的通道加入到Poller关注
channel_->enableReading();
connectionCallback_(shared_from_this());
}
上面这个程序在连接到来的时候,将TcpConnection所对应的通道加入到Poller关注,此时,如果有可读事件发生,就会由handleEvent()->handleRead(),就可以处理连接通道中的可读事件了
//当一个消息到来的时候,调用handleRead
void TcpConnection::handleRead(Timestamp receiveTime)
{
loop_->assertInLoopThread();
int savedErrno = 0;
ssize_t n = inputBuffer_.readFd(channel_->fd(), &savedErrno);
if (n > 0)
{
//shared_from_this()的作用是转为shared_ptr
messageCallback_(shared_from_this(), &inputBuffer_, receiveTime);
}
//处理连接断开
else if (n == 0)
{
handleClose();
}
else
{
errno = savedErrno;
LOG_SYSERR << "TcpConnection::handleRead";
handleError();
}
}