Muduo库设计(5)——TcpConnection和TcpServer

一、TcpConnection类

TcpConnection类用于管理Acceptor类接收到的每条连接,每当Acceptor类接收到一个新的连接时就创建一个TcpConnection类
每个TcpConnection类有一个唯一的name,每个TcpConnection对象创建时需要传入一个fd,并针对该fd创建一个Channel对象
注意:TcpConnection表示的是一次Tcp连接,它是不可再生的,一旦断开,这个TcpConnection就没啥用了。

TcpConnection::TcpConnection(EventLoop* loop,
                             const std::string& nameArg,
                             int sockfd,
                             const InetAddress& localAddr,
                             const InetAddress& peerAddr)
  : loop_(CHECK_NOTNULL(loop)),
    name_(nameArg),
    state_(kConnecting),
    socket_(new Socket(sockfd)),
    channel_(new Channel(loop, sockfd)),
    localAddr_(localAddr),
    peerAddr_(peerAddr)
{
  channel_->setReadCallback(std::bind(&TcpConnection::handleRead, this));
}

TcpConnection创建完成之后需要调用connectEstablished方法开始监测该Channel上的读事件

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

  connectionCallback_(shared_from_this());    //该回调通知上层调用者已建立好连接(即该连接已经可以开始接受读事件了)
}

当有可读事件时,表示该连接上有新的消息到来

void TcpConnection::handleRead()
{
  char buf[65536];
  ssize_t n = ::read(channel_->fd(), buf, sizeof buf);
  messageCallback_(shared_from_this(), buf, n);
}

二、TcpServer类

TcpServer类用来统一管理Acceptor类和TcpConnection类,TcpServer类持有一个Acceptor类,它负责启动Acceptor类来开始监听本地的一个端口号

TcpServer::TcpServer(EventLoop* loop, const InetAddress& listenAddr)
  : loop_(CHECK_NOTNULL(loop)),
    name_(listenAddr.toHostPort()),
    acceptor_(new Acceptor(loop, listenAddr)),
    started_(false),
    nextConnId_(1)
{
  acceptor_->setNewConnectionCallback(std::bind(&TcpServer::newConnection, this, std::placeholders::_1, std::placeholders::_2));
}

启动acceptor对象开始监听

void TcpServer::start()
{
  if (!started_)
  {
    started_ = true;
  }

  if (!acceptor_->listenning())
  {
    loop_->runInLoop(std::bind(&Acceptor::listen, acceptor_));  //此处acceptor_不要使用unique_ptr,首先编译就不会通过,只有移动语义,不能赋值
  }
}

每当acceptor对象接收到一个新的连接时,TcpServer会在相应的回调函数中创一个TcpConnection,并给这个对象起一个唯一的name,然后启动TcpConnection开始监听读事件,最后把键值对插入到一个map集合中。

void TcpServer::newConnection(int sockfd, const InetAddress& peerAddr)
{
  loop_->assertInLoopThread();
  char buf[32];
  snprintf(buf, sizeof buf, "#%d", nextConnId_);
  ++nextConnId_;
  std::string connName = name_ + buf;                  //给每个连接一个唯一的名字

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

  TcpConnectionPtr conn(new TcpConnection(loop_, connName, sockfd, localAddr, peerAddr));
  
  connections_[connName] = conn;                       //将插入map集合
  
  conn->setConnectionCallback(connectionCallback_);
  conn->setMessageCallback(messageCallback_);
  conn->connectEstablished();                          //开始监测channel上的读事件
}

TcpServer调用的一个示例如下:

void onConnection(const muduo::TcpConnectionPtr& conn)
{
  if (conn->connected())
  {
    printf("onConnection(): new connection [%s] from %s\n", conn->name().c_str(), conn->peerAddress().toHostPort().c_str());
  }
  else
  {
    printf("onConnection(): connection [%s] is down\n", conn->name().c_str());
  }
}

void onMessage(const muduo::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());

  muduo::InetAddress listenAddr(9981);
  muduo::EventLoop loop;

  muduo::TcpServer server(&loop, listenAddr);
  server.setConnectionCallback(onConnection);
  server.setMessageCallback(onMessage);
  
  server.start();

  loop.loop();
}

运行结果如下图:


image.png

你可能感兴趣的:(Muduo库设计(5)——TcpConnection和TcpServer)