muduo 22 Acceptor

Acceptor在muduo库中用于处理新用户连接,它创建非阻塞socket,监听连接,并将新连接转换为Channel,分配给工作线程。当有新连接时,Acceptor调用回调函数,通过轮询选择subLoop进行处理,确保线程安全和高效并发。
摘要由CSDN通过智能技术生成

目录

 Acceptor成员变量:

Acceptor成员函数:

Acceptor::Acceptor

createNonblocking():创建socket套接字函数,创建一个非阻塞的IO

Acceptor::~Acceptor()

Acceptor::listen()

Acceptor::handleRead()

Acceptor.h

Acceptor.cc


 muduo库是一个Multiple Reactors模型,多反应堆模型。

        通过setThreadNumber来设置底层的线程数量,一个IO线程(mainReactor)和多个工作线程(subReactor)

         Acceptor的作用就是处理accept,监听新用户连接,新用户连接响应以后,拿到和客户端通信的clientfd打包成Channel,然后根据muduo的轮询算法找到一个subloop,并把Channel给到这个subloop,在这之前需要唤醒这个subloop(通过wakeupfd_:每个loop都有一个wakeupfd_,由Linux系统调用的evenfd创建的,一个带有notify,即带有通知机制的fd,通过写读操作通知)通知机制的fd),mainloop可以向subloop随便写一个整数,唤醒subloop,将打包好的Channel扔给subloop,也就是注册到Poller上!


 Acceptor成员变量:

         Acceptor的底层是一个listenfd(封装的acceptSocket_),然后这个listenfd打包成Channel放在一个Poller上监听有没有新的用户连接(acceptChannel_)最终返回发生的事件。

  • loop_:就是baseloop;
  • acceptSocket_:绑定的就是一个listenfd,封装成了Socket;
  • acceptChannel_: listenfd(封装成Channel)也需要一个Poller来监听读写事件的;
  • newConnectionCallback_:作用: Acceptor给你返回一个connectfd,也就是说有新用户连接成功了,接下来,TcpSever通过轮询选择一个subloop唤醒,然后将connectfd打包成Channel给subloop。

Acceptor成员函数:

Acceptor::Acceptor

         构造函数中会创建一个非阻塞的fd ① ,创建一个由这个fd创建的Channel ②,设置套接字选项 ③ ,然后给这个Channel绑定一个handleRead回调函数 ④ 。


createNonblocking():创建socket套接字函数,创建一个非阻塞的IO

        SOCK_NONBLOCK:  在非阻塞模式下,当执行读取或写入操作时,如果没有数据可用或无法立即写入数据,函数会立即返回,并不会阻塞线程。这使得程序可以继续执行其他任务或处理其他事件,而不必等待套接字操作完成。

        SOCK_CLOEXEC: 当执行exec系统掉用时,操作系统会自动关闭该套接字,确保不会被继承到新的线程中,比如说避免子进程继承父进程的fd,这样可以避免在新程序中不再使用的套接字持续占用资源,并且可以简化代码中资源管理。


Acceptor::~Acceptor()

 

Acceptor::listen()

启动 Socket的listen函数开始监听;

将该Channel更新为可读事件,交给poller去监听。

Acceptor::handleRead()

①:调用Socket中的accept函数接收新连接,返回connfd;

②:有新的连接之后去执行newConnectionCallback_回调函数,该回调函数由TcpServer设置

Acceptor.h

#pragma once 

#include "noncopyable.h"
#include "Socket.h"
#include "Channel.h"
#include "InetAddress.h"

#include <functional>

class EventLoop;
class InetAddress;

class Acceptor
{
public:
    using NewConnectionCallback = std::function<void(int sockfd, const InetAddress&)>;
    Acceptor(EventLoop *loop, const InetAddress&listenAddr, bool reuseport);
    ~Acceptor();

    void setNewConnectionCallback(const NewConnectionCallback &cb)
    {
        newConnectionCallback_ = std::move(cb);
    }
    bool listenning() const  { return listenning_; }
    void listen();

private:
    void handleRead();
    EventLoop *loop_;
    Socket acceptSocket_;
    Channel acceptChannel_;
    NewConnectionCallback newConnectionCallback_;
    bool listenning_;
};

Acceptor.cc

#include "Acceptor.h"
#include "Logger.h"
#include "InetAddress.h"

#include <sys/types.h>    
#include <sys/socket.h>
#include <errno.h>
#include <unistd.h>


static int createNonblocking()//创建非阻塞的I/O 
{
    int sockfd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);//SOCK_STREAM:TCP套接字
    if (sockfd < 0) 
    {
        LOG_FATAL("%s:%s:%d listen socket create err:%d \n", __FILE__, __FUNCTION__, __LINE__, errno);
    }
    return sockfd;//改
}

Acceptor::Acceptor(EventLoop *loop, const InetAddress &listenAddr, bool reuseport)//构造函数 
    : loop_(loop)
    , acceptSocket_(createNonblocking())//创建socket套接字 
    , acceptChannel_(loop, acceptSocket_.fd())//channel和poller都是通过请求本线程的loop和poller通信 
    , listenning_(false)
{
    acceptSocket_.setReuseAddr(true);//地址重用
    acceptSocket_.setReusePort(true);//端口重用
    acceptSocket_.bindAddress(listenAddr);//bind绑定套接字 
    //TcpServer::start() Acceptor.listen  如果有新用户的连接,就要执行一个回调(connfd=》打包成channel=》唤醒subloop)
    //baseLoop => acceptChannel_(listenfd)有事件发生 => 底层反应堆调用回调 
    acceptChannel_.setReadCallback(std::bind(&Acceptor::handleRead, this));//绑定回调 
}

Acceptor::~Acceptor()
{
    acceptChannel_.disableAll();
    acceptChannel_.remove();
}
 
void Acceptor::listen()
{
    listenning_ = true;
    acceptSocket_.listen();//listen
    acceptChannel_.enableReading();//acceptChannel_ => Poller,监听读事件
}

//listenfd有事件发生了,就是有新用户连接了
void Acceptor::handleRead()
{
    InetAddress peerAddr;
    int connfd = acceptSocket_.accept(&peerAddr);
    if (connfd >= 0)
    {
        if (newConnectionCallback_)
        {
            newConnectionCallback_(connfd, peerAddr);//轮询找到subLoop,唤醒,分发当前的新客户端的Channel
        }
        else//客户端没有办法去服务 
        {
            ::close(connfd);
        }
    }
    else
    {
        LOG_ERROR("%s:%s:%d accept err:%d \n", __FILE__, __FUNCTION__, __LINE__, errno);
        if (errno == EMFILE)
        {
            LOG_ERROR("%s:%s:%d sockfd reached limit! \n", __FILE__, __FUNCTION__, __LINE__);
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值