muduo_net代码剖析之Acceptor

Acceptor用于接收client的连接请求,建立连接

1、Acceptor类简介

类Acceptor主要功能socket、bind、listen,并调用注册的回调函数来处理新到的连接

2、Acceptor连接建立 /处理时序图

muduo_net代码剖析之Acceptor_第1张图片
1:当loop()函数监听到通道acceptChannel_有事件到来,即listen套接字可读时
2:acceptChannel_->handleEvent()
3:Acceptor::handleRead()
4:handleRead()函数中又调用了accept()接收客户端的请求
5:连接建立后,会调用注册的回调函数newConnectionCallback_()

Acceptor .h头文件

class Acceptor : noncopyable
{
 public:
  typedef std::function<void (int sockfd, const InetAddress&)> NewConnectionCallback;

  Acceptor(EventLoop* loop, const InetAddress& listenAddr, bool reuseport);
  ~Acceptor();

  void setNewConnectionCallback(const NewConnectionCallback& cb)
  { newConnectionCallback_ = cb; }

  bool listenning() const { return listenning_; }
  
  void listen();

 private:
  void handleRead();

  EventLoop* loop_;
  Socket acceptSocket_;  //监听套接字
  Channel acceptChannel_;//通道
  NewConnectionCallback newConnectionCallback_;
  bool listenning_;
  int idleFd_;
};

3、源码剖析

构造函数

Acceptor创建非阻塞的listen socket和channel,并且将Acceptor::handleRead函数设置为acceptChannel_的Read Callback

Acceptor::Acceptor(EventLoop* loop, const InetAddress& listenAddr, bool reuseport)
  : loop_(loop), //所属的loop
    acceptSocket_(sockets::createNonblockingOrDie(listenAddr.family())), //创建非阻塞的listen套接字
    acceptChannel_(loop, acceptSocket_.fd()), //创建监听Channel
    listenning_(false), //是否正在监听
    idleFd_(::open("/dev/null", O_RDONLY | O_CLOEXEC)) //预留idlefd
{
  assert(idleFd_ >= 0);
  acceptSocket_.setReuseAddr(true); //设置地址、端口复用
  acceptSocket_.setReusePort(reuseport);
  acceptSocket_.bindAddress(listenAddr); //bind

  //设置ReadCallback,下面在Acceptor::listen()中acceptChannel_.enableReading();
  //==>当acceptChannel_有读事件(接收到新连接)时,将调用回调函数Acceptor::handleRead()
  acceptChannel_.setReadCallback(  
      std::bind(&handleRead, this));
}


void Acceptor::handleRead() 
{
  loop_->assertInLoopThread();
  InetAddress peerAddr;
  int connfd = acceptSocket_.accept(&peerAddr);//accept新连接
  if (connfd >= 0) //如果accept返回成功
  {
    if (newConnectionCallback_) //调用newConnectionCallback_回调函数
    {
      newConnectionCallback_(connfd, peerAddr);
    }
    else
    {
      sockets::close(connfd);
    }
  }
  else
  {
    LOG_SYSERR << "in Acceptor::handleRead";
    if (errno == EMFILE) //解决太多的文件描述符的错误:使用idlefd
    {
      ::close(idleFd_); 
      idleFd_ = ::accept(acceptSocket_.fd(), NULL, NULL); 
      ::close(idleFd_); 
      idleFd_ = ::open("/dev/null", O_RDONLY | O_CLOEXEC);
    }
  }
}

Acceptor::listen(),这个函数顾名思义,就是开始监听对端的连接请求

void Acceptor::listen()
{
  loop_->assertInLoopThread();
  listenning_ = true;
  acceptSocket_.listen();
  acceptChannel_.enableReading(); //关心读事件
}

③ 设置连接建立成功后的回调函数:setNewConnectionCallback

accept返回后,即连接建立成功后,会执行注册的newConnectionCallback_函数

//设置[连接建立成功的回调函数]
void setNewConnectionCallback(const NewConnectionCallback& cb)
{ newConnectionCallback_ = cb; }

4、示例代码

#include "Acceptor.h"
#include "EventLoop.h"
#include "InetAddress.h"
#include "SocketsOps.h"
#include 
 
void newConnection(int sockfd, const muduo::InetAddress& peerAddr)
{
  printf("newConnection(): accepted a new connection from %s\n",
         peerAddr.toHostPort().c_str());
  ::write(sockfd, "How are you?\n", 13);
  muduo::sockets::close(sockfd);
}
 
int main()
{
  printf("main(): pid = %d\n", getpid());
 
  muduo::InetAddress listenAddr(9981);
  muduo::EventLoop loop;
 
  muduo::Acceptor acceptor(&loop, listenAddr);
  acceptor.setNewConnectionCallback(newConnection);
  acceptor.listen();
 
  loop.loop();
}

你可能感兴趣的:(Muduo库源码剖析)