muduo中TcpServer、TcpConnection执行过程

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();
  }
}

猜你喜欢

转载自blog.csdn.net/wk_bjut_edu_cn/article/details/80898672