冬雨财经 发表于 2025-4-9 08:52:15

单reactor实战

前言:reactor作为一种高性能的范式,值得我们学习
本次目标 实现一个基于的reactor 具备echo功能的服务器
核心组件

Reactor本身是靠一个变乱驱动的框架,无疑引出一个类似于moduo的"EventLoop "以及boost.asio中的context而言,不停获取停当变乱,其本质无疑是io多用复路实现的。
下面就是核心功能:
void EventLoop::loop(){
    while(!quit){
    std::vector<Channel*> chs;
      chs = ep->poll();
      for(auto it = chs.begin(); it != chs.end(); ++it){
            (*it)->handleEvent();
      }
    }
}
当变乱检测到了,无疑我们要举行分发,这个所以我们也可以借助一个核心组件
Channel来分发
class Channel
{
private:
    EventLoop *loop;
    int fd;
    uint32_t events;
    uint32_t revents;
    bool inEpoll;
    std::function<void()> callback;
public:
    Channel(EventLoop *_loop, int _fd);
    ~Channel();

    void enableReading();//设置检测什么事件

    int getFd();
    uint32_t getEvents();
    uint32_t getRevents();
    bool getInEpoll();
    void setInEpoll();

    // void setEvents(uint32_t);
    void setRevents(uint32_t);
    void setCallback(std::function<void()>);
};
不难发现,其实这个核心函数为std::function<void()> callback和void setCallback(std::function<void()>);,设置不同变乱的回调函数
void Channel::setCallback(std::function<void()> _cb){
    callback = _cb;
}
有过reactor的基础的人,一样平常都知道我们将业务分成毗连和业务处理
没基础也不要紧可以阅读这个Reactor解析 你也可以直接看图
https://i-blog.csdnimg.cn/direct/9dca24229f0a47439d731b61ddfea0be.png
这就引出了Acceptor类 专门处理毗连的
   

[*]Acceptor类存在于变乱驱动EventLoop类中,也就是Reactor模式的main-Reactor
[*]类中的socket fd就是服务器监听的socket fd,每一个Acceptor对应一个socket fd
[*]这个类也通过一个独有的Channel负责分发到epoll,该Channel的变乱处理函数handleEvent()会调用Acceptor中的继承毗连函数来新建一个TCP毗连
class Acceptor
{
private:
    EventLoop *loop;
    Socket *sock;//每一个Acceptor对应一个socket fd
    Channel *acceptChannel;//这个类也通过一个独有的Channel负责分发到epoll
public:
    Acceptor(EventLoop *_loop);
    ~Acceptor();
    void acceptConnection();
    std::function<void(Socket*)> newConnectionCallback;
    void setNewConnectionCallback(std::function<void(Socket*)>);
};
这就引出为什么 的核心组件其毗连组件Acceptor(EventLoop *_loop);和 void acceptConnection();
Acceptor::Acceptor(EventLoop *_loop) :loop(_loop){

    sock=new Socket();
    InetAddress* addr=new InetAddress("127.0.0.1",8080);
    sock->bind(addr);
    sock->listen();
    sock->setnonblocking();

    acceptChannel=new Channel(_loop,sock->getFd());
    std::function<void()> cb = std::bind(&Acceptor::acceptConnection, this);//注册回调函数 进行连接
    acceptChannel->setCallback(cb);
    acceptChannel->enableReading();//注册事件
    delete addr;

}

void Acceptor::acceptConnection(){
    InetAddress*clnt_addr=new InetAddress();
    Socket* clnt_sock=new Socket(sock->accept(clnt_addr));
    printf("new client fd %d! IP: %s Port: %d\n", clnt_sock->getFd(), inet_ntoa(clnt_addr->getAddr().sin_addr), ntohs(clnt_addr->getAddr().sin_port));
    clnt_sock->setnonblocking();
    newConnectionCallback(sock);
    delete clnt_addr;
}
讲一下这个 newConnectionCallback(sock); 这个就是业务逻辑处理。这份代码的不完整之处就在于 他的目的核心是实现一个功能 echo回响 所以直接毗连之后给了一个echo的业务逻辑。引出一个connect 即每一个毗连都有一个业务处理方法
   Connection类,这个类也有以下几个特点:
   

[*]类存在于变乱驱动EventLoop类中,也就是Reactor模式的main-Reactor
[*]类中的socket fd就是客户端的socket fd,每一个Connection对应一个socket fd
[*]每一个类的实例通过一个独有的Channel负责分发到epoll,该Channel的变乱处理函数handleEvent()会调用Connection中的变乱处理函数来响应客户端请求
class Connection {
private:
    EventLoop *loop;
    Socket *sock;
    Channel *channel;
    std::function<void(Socket*)> deleteConnectionCallback;//
public:
    Connection(EventLoop *_loop, Socket *_sock);
    ~Connection();

    void echo(int sockfd);
    void setDeleteConnectionCallback(std::function<void(Socket*)>);

};
通过这个函数也可以看出一个echo就是一个connection的回调函数。然后我们再来看一下另一个重要的资源释放.设置一个自动释放的connection的回调函数。
void Connection::setDeleteConnectionCallback(std::function<void(Socket*)> _cb){
    deleteConnectionCallback = _cb;
}
也是注册函数
Reactor-server

class Server
{
private:
    EventLoop *loop;
    //ADD 连接逻辑
    Acceptor *acceptor;
    std::map<int, Connection*> connections;//一一对应

public:
    Server(EventLoop*);
    ~Server();

    void handleReadEvent(int);
    void newConnection(Socket *serv_sock);
    void deleteConnection(Socket *sock);
};
这个reactor无疑包含了三个组件 变乱驱动,毗连逻辑和业务逻辑
Server::Server(EventLoop *_loop) : loop(_loop){
    acceptor = new Acceptor(loop);//完成所有的连接步骤 就没设置回调函数
    std::function<void(Socket*)> cb = std::bind(&Server::newConnection, this, std::placeholders::_1);//这个是每次动态
    acceptor->setNewConnectionCallback(cb);//

}
void Server::newConnection(Socket *sock){
    Connection *conn = new Connection(loop, sock);
    std::function<void(Socket*)> cb = std::bind(&Server::deleteConnection, this, std::placeholders::_1);
    conn->setDeleteConnectionCallback(cb);
    connections = conn;

}
void Server::deleteConnection(Socket * sock){
    Connection *conn = connections;
    connections.erase(sock->getFd());
    delete conn;
}


[*]解析
这个reactor-main是不是有三个疑问
[*]为什么毗连步调完成了
[*]他的业务函数也就是echo在哪
[*]为什么用map来装饰Connection
首先我们来回顾一下团体流程,我们要明白一个点 一个socket的绑定IP和端口,不算毗连逻辑,也就是说当你初始化的时候就应该弄好了。
真正的毗连逻辑应该是设置毗连回调函数的时候,例如
Acceptor::Acceptor(EventLoop *_loop) :loop(_loop){

    sock=new Socket();
    InetAddress* addr=new InetAddress("127.0.0.1",8080);
    sock->bind(addr);
    sock->listen();
    sock->setnonblocking();

    acceptChannel=new Channel(_loop,sock->getFd());
    std::function<void()> cb = std::bind(&Acceptor::acceptConnection, this);//注册回调函数
    acceptChannel->setCallback(cb);/
    acceptChannel->enableReading();//注册事件
    delete addr;

}
acceptChannel->setCallback(cb)这个就毗连逻辑,当有客户端来的时候 他就是实行这个逻辑。第一个疑问解决
然后 acceptor->setNewConnectionCallback(cb);这个是不是设置了业务逻辑,因为前面讲过 这个没有线程池而且业务逻辑单一,所有将echo默认每一个毗连的业务逻辑 所有直接再毗连回调的时候设置了一个业务逻辑(你去看connect的构造函数 就会发现他直接绑定了echo做业务逻辑)第二疑问解决
Connection::Connection(EventLoop *_loop, Socket *_sock):loop(_loop),sock(_sock),channel(nullptr){
    //属性
    channel=new Channel(loop,sock->getFd());//
    std::function<void()>cb=std::bind(&Connection::echo,this,sock->getFd());//业务处理函数;
    channel->setCallback(cb);
    channel->enableReading();
}
Connection::~Connection(){
    delete channel;
    delete sock;
}
也就是说 你可以从这下手 换一个业务逻辑 实现其他的业务
第三个疑问:
   对于断开TCP毗连操作,也就是销毁一个Connection类的实例。由于Connection的生命周期由Server举行管理,所以也应该由Server来删除毗连。假如在Connection业务中需要断开毗连操作,也应该和之前一样使用回调函数来实现.使用map就是好删除管理

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 单reactor实战