浅析muduo网络库

浅析muduo网络库之TcpConnection

2018-01-09  本文已影响104人  谢昆明

1 翠花,上代码


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

代码有点多,挑重点看。
参数有5个,关注下EventLoopsockfd
1)从前面的对EventLoop的分析,可以看出,所有的数据肯定都在EventLoop里面处理。
2)sockfd,这个没啥好介绍的
因此构造也就有那么多的setXXXCallback

2 分析分析这几个Callback

2.1 setReadCallback


void TcpConnection::handleRead(Timestamp receiveTime)
{
  loop_->assertInLoopThread();
  int savedErrno = 0;
  ssize_t n = inputBuffer_.readFd(channel_->fd(), &savedErrno);
  if (n > 0)
  {
    messageCallback_(shared_from_this(), &inputBuffer_, receiveTime);
  }
  else if (n == 0)
  {
    handleClose();
  }
  else
  {
    errno = savedErrno;
    LOG_SYSERR << "TcpConnection::handleRead";
    handleError();
  }
}

读取数据后,调用messageCallback_,异常处理等等

2.2 setWriteCallback


void TcpConnection::handleWrite()
{
  loop_->assertInLoopThread();
  if (channel_->isWriting())
  {
    ssize_t n = sockets::write(channel_->fd(),
                               outputBuffer_.peek(),
                               outputBuffer_.readableBytes());
    if (n > 0)
    {
      outputBuffer_.retrieve(n);
      if (outputBuffer_.readableBytes() == 0)
      {
        channel_->disableWriting();
        if (writeCompleteCallback_)
        {
          loop_->queueInLoop(boost::bind(writeCompleteCallback_, shared_from_this()));
        }
        if (state_ == kDisconnecting)
        {
          shutdownInLoop();
        }
      }
    }
    else
    {
      LOG_SYSERR << "TcpConnection::handleWrite";
      // if (state_ == kDisconnecting)
      // {
      //   shutdownInLoop();
      // }
    }
  }
  else
  {
    LOG_TRACE << "Connection fd = " << channel_->fd()
              << " is down, no more writing";
  }
}

代码里有一行
if (outputBuffer_.readableBytes() == 0)
这个,估计是缓冲区写满了,
接下去禁止写入,而且会调用writeCompleteCallback_

2.3 setCloseCallback

void TcpConnection::handleClose()
{
  loop_->assertInLoopThread();
  LOG_TRACE << "fd = " << channel_->fd() << " state = " << stateToString();
  assert(state_ == kConnected || state_ == kDisconnecting);
  // we don't close fd, leave it to dtor, so we can find leaks easily.
  setState(kDisconnected);
  channel_->disableAll();

  TcpConnectionPtr guardThis(shared_from_this());
  connectionCallback_(guardThis);
  // must be the last line
  closeCallback_(guardThis);
}

乍一看,会递归调用,因为构造函数有这行代码
channel_->setCloseCallback( boost::bind(&TcpConnection::handleClose, this));

找代码看吧

void TcpClient::newConnection(int sockfd)
{
  conn->setCloseCallback(
      boost::bind(&TcpClient::removeConnection, this, _1)); // FIXME: unsafe
}

TcpClient里面,更新了CloseCallback,绕了一大圈。
是不是意味着直接使用TcpConnection,但是没用对会死循环。。。

在析构函数里面,还有一段,估计是怕TcpConnectionPtr没有释放

void removeConnection(EventLoop* loop, const TcpConnectionPtr& conn)
{
  loop->queueInLoop(boost::bind(&TcpConnection::connectDestroyed, conn));
}

TcpClient::~TcpClient()
{
  CloseCallback cb = boost::bind(&detail::removeConnection, loop_, _1);
  loop_->runInLoop(
        boost::bind(&TcpConnection::setCloseCallback, conn, cb));
}

2.4 setErrorCallback

void TcpConnection::handleError()
{
  int err = sockets::getSocketError(channel_->fd());
  LOG_ERROR << "TcpConnection::handleError [" << name_
            << "] - SO_ERROR = " << err << " " << strerror_tl(err);
}

打印错误码

打赏

如果这篇文章解决了您的问题,让我买根烟抽抽。

支付宝.jpg 微信.jpg
上一篇 下一篇

猜你喜欢

热点阅读