C++ Muduo网络库基本流程跟踪,学习下

6 篇文章 0 订阅


C++ Muduo网络库基本流程跟踪:


例子中的入口点:

int main()

{

         EventLoop loop;

         TcpServer server(&loop, listenAddr,"name");

         server.start();

         loop.loop();
}

 

看TcpServer构造函数:

TcpServer::TcpServer(EventLoop* loop,

                     const InetAddress& listenAddr,

                     const string& nameArg,

                     Option option)

  : loop_(CHECK_NOTNULL(loop)),

    hostport_(listenAddr.toIpPort()),

    name_(nameArg),

    acceptor_(new Acceptor(loop, listenAddr, option == kReusePort)),

    threadPool_(new EventLoopThreadPool(loop, name_)),

    connectionCallback_(defaultConnectionCallback),

    messageCallback_(defaultMessageCallback),

    nextConnId_(1)

{

  acceptor_->setNewConnectionCallback(

      boost::bind(&TcpServer::newConnection, this, _1, _2));

}

 

在声明server时候调用TcpServer的构造函数:

0.初始化线程池(暂不说)

1.初始化listen套接字类Acceptor

2.初始化默认的连接和接收消息回调

3.设置acceptor的新连接回调为TcpServer::newConnection

 

 

跟进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_)));

  }

}

 

1.启动线程池

2.调用acceptor_->listen()开始监听新连接

void Acceptor::listen()

{

  loop_->assertInLoopThread();

  listenning_ = true;

  acceptSocket_.listen();

  acceptChannel_.enableReading();  

}

 

acceptChannel_.enableReading();// 这里将acceptor套接字加入到loop中的poller的in事件中,当有新连接上来的时候,会回调到acceptor_->handleRead(),当连接成功,会回调到server->newConnection(),嘿嘿。

 

 

看看TcpServer::newConnection()做了什么:

void TcpServer::newConnection(int sockfd, const InetAddress& peerAddr)

{

  loop_->assertInLoopThread();

  EventLoop* ioLoop = threadPool_->getNextLoop();

  char buf[32];

  snprintf(buf, sizeof buf, ":%s#%d", hostport_.c_str(), nextConnId_);

  ++nextConnId_;

  string connName = name_ + buf;

 

  LOG_INFO<< "TcpServer::newConnection ["<< name_

           << "]- new connection [" << connName

           << "]from " << peerAddr.toIpPort();

  InetAddress localAddr(sockets::getLocalAddr(sockfd));

  // FIXMEpoll with zero timeout to double confirm the new connection

  // FIXMEuse make_shared if necessary

  TcpConnectionPtr conn(new TcpConnection(ioLoop,

                                         connName,

                                         sockfd,

                                         localAddr,

                                         peerAddr));

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

}

 

创建新连接shared_ptr对象:TcpConnectionPtr,设置Channel的读,写事件回调(TcpConnection构造函数中设置),设置接收完整的一个packet的回调messageCallback,完全写出数据时候的回调writeCompleteCallback,关闭套接字回调removeConnection,执行TcpConnection::connectEstablish(这里只是回调到用户设置的新连接上来的回调),所以当一个新连接上来的时候,流程是这样的:

Acceptor::handleRead()->TcpServer::newConnection()->TcpServer::connectionCallback_()

 

看看TcpConnection::connectionEstablished():

void TcpConnection::connectEstablished()

{

  loop_->assertInLoopThread();

  assert(state_ == kConnecting);

  setState(kConnected);

  channel_->tie(shared_from_this());

  channel_->enableReading();

 

  connectionCallback_(shared_from_this());

}

 

1.设置状态为连接

2.将套接字加入到poller的in事件中

3.回调用户设置的connectionCallback_

 

 

接着看loop.loop():

 

void EventLoop::loop()

{

  assert(!looping_);

  assertInLoopThread();

  looping_ = true;

  quit_ = false//FIXME: what if someone calls quit() before loop() ?

  LOG_TRACE<< "EventLoop " << this << " start looping";

 

  while (!quit_)

  {

    activeChannels_.clear();

    pollReturnTime_ = poller_->poll(kPollTimeMs, &activeChannels_);

    ++iteration_;

    if (Logger::logLevel() <=Logger::TRACE)

    {

      printActiveChannels();

    }

    // TODOsort channel by priority

    eventHandling_ = true;

    for (ChannelList::iterator it = activeChannels_.begin();

        it != activeChannels_.end(); ++it)

    {

      currentActiveChannel_ = *it;

      currentActiveChannel_->handleEvent(pollReturnTime_);

    }

    currentActiveChannel_ = NULL;

    eventHandling_ = false;

    doPendingFunctors();

  }

 

  LOG_TRACE<< "EventLoop " << this << " stop looping";

  looping_ = false;

}

 

1.loop只能在本线程执行(assertInLoopThread())

2.循环执行网络poller

3.处理网络事件currentActiveChannel_->handleEvent(pollReturnTime_);当在poll所有channels的时候,会处理channel的读,写事件回调,这个时候会调用到TcpConnection的读写事件回调(在TcpConnection构造函数中不是设置了channel的回到么)

4.处理其他线程调用本线程事件?doPendingFunctors()

 

 

基本流程也就这样了吧,当然,里面还涉及很多细节。很多地方还是值得学习的。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值