muduo_net代码剖析之Acceptor

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

1、Acceptor类简介

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

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

在这里插入图片描述
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 <stdio.h>
 
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();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值