Muduo之TcpConnection源碼分析筆記

Muduo之TcpConnection源碼分析筆記

上一節中我們分析到當TcpServer(Acceptor)檢測到讀事件時,就會創建一個TcpConnection對象,那麼這裏我們就分析下TcpConnection的細節。

首先我們看下TcpConnection的類數據成員:

以及如下是TcpConnection的構造函數:(PS:其實我們假象認爲TcpConnection就是一個socket和一大堆回調函數的集合,代表一個和對端的TCP連接,而TcpConnection裏面自然包含了Channel和EventLoop對象)

TcpConnection::TcpConnection(EventLoop* loop,
                             const string& nameArg,
                             int sockfd,
                             const InetAddress& localAddr,
                             const InetAddress& peerAddr)
  : loop_(CHECK_NOTNULL(loop)),
    name_(nameArg),
    state_(kConnecting),
    reading_(true),
    socket_(new Socket(sockfd)),
    channel_(new Channel(loop, sockfd)),
    localAddr_(localAddr),
    peerAddr_(peerAddr),
    highWaterMark_(64*1024*1024)
{
  channel_->setReadCallback(
      boost::bind(&TcpConnection::handleRead, this, _1));
  channel_->setWriteCallback(
      boost::bind(&TcpConnection::handleWrite, this));
  channel_->setCloseCallback(
      boost::bind(&TcpConnection::handleClose, this));
  channel_->setErrorCallback(
      boost::bind(&TcpConnection::handleError, this));
  LOG_DEBUG << "TcpConnection::ctor[" <<  name_ << "] at " << this
            << " fd=" << sockfd;
  socket_->setKeepAlive(true);
}

從上面的類圖可以大概的知道TcpConnection擁有的數據成員,圖中省略了一些public接口。

因爲TcpConnection是當有連接請求的時候創建的,那麼就應該有相應的socket fd。

而在構造函數中我們可以看到創建了Channel對象,之前我們說過Channel是對socket以及回調函數的封裝,Acceptor裏面都有channel,那麼針對TcpConnection也應該有該socketfd以及回調函數的封裝,初始化Channel的過程就是將socket和looper關聯的過程。另外構造函數中前幾句都是對於channel對象中回調函數的一些初始化。那麼當TcpConnection創建完成之後又怎麼樣了呢?我們看到在TcpServer::newConnection()裏面最後有這麼一句話:

ioLoop->runInLoop(boost::bind(&TcpConnection::connectEstablished, conn));

我們看到這裏將新建的TcpConnection加入到了選區的EventLoop任務隊列裏面。我們看下EventLoop::runInLoop()的代碼可以知道這裏執行上就是調用了TcpConnection::connectEstablished()。我們來看下它的代碼:

void TcpConnection::connectEstablished()
{
  loop_->assertInLoopThread();
  assert(state_ == kConnecting);
  setState(kConnected);
  channel_->tie(shared_from_this());
  channel_->enableReading();

  connectionCallback_(shared_from_this());
}

因爲連接這時候是處於accept()之後的因此狀態是kConnected,我們可以看到channel->enableReading()而這句代碼就是將該Channel加入到EventLoop當中去的。 這個因爲涉及到Channel的方法我們在之後的內容裏面講解。

總結

當TcpServer::newConnection()創建了TcpConnection之後並調用EventLoop::runInLoop()之後就將該Channel加入到了EventLoop當中去了。之後所有該連接的操作都是由該EventLoop所屬的線程處理,Acceptor不再控制,它又回到之前的poll的地方靜靜地等待下一個連接的到來。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章