古月不傲 发表于 2021-1-26 21:23

事件循环超简化版本

Epoll
#ifndef __EPOLL_H__
#define __EPOLL_H__

#include <iostream>
#include <memory>
#include <sys/epoll.h>
#include <vector>

class Channel;
class Epoll
{
        public:
                Epoll();

                // 注册通道
                void updateChannel(Channel *channel);
                // 处理通道
                void waitEvent(std::vector<Channel *> *activeChannel);
        private:
                int m_epollFd;
                std::vector<struct epoll_event> m_events;
};

#endif

#include "Channel.h"
#include "Epoll.h"
#include <errno.h>
#include <cstring>
#include <assert.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <signal.h>
#include <poll.h>
#include <vector>
#include <netinet/in.h>   // INADDR_ANY
#include <errno.h>
#include <arpa/inet.h> // inet_ntoa
#include <cstring>
#include <unistd.h>


Epoll::Epoll() :
        m_epollFd(::epoll_create1(EPOLL_CLOEXEC)),
        m_events(512)
{

}

Channel *qqqq;
// 注册通道
void Epoll::updateChannel(Channel *channel)
{
        qqqq = channel;
        struct epoll_event event {};

        event.events = channel->getEvents();
        //event.data.u32 = 55;
        event.data.ptr = channel;
        int fd = channel->getFd();

        printf("channel = %p\n", channel);

        if (epoll_ctl(m_epollFd, EPOLL_CTL_ADD, fd, &event) < 0)
        {
                printf("error!\n");
        }
}

// 处理通道
void Epoll::waitEvent(std::vector<Channel *> *activeChannel)
{
        int num = epoll_wait(m_epollFd, &*m_events.begin(), 512, -1);

        printf("num = %d\n", num);
        if (num == -1)
                printf("error: %s\n", strerror(errno));

        struct sockaddr_in client_addr {};
    socklen_t addr_len = sizeof(struct sockaddr);

        for (int i = 0; i < num; i++)
        {
                Channel *channel = static_cast<Channel *>(m_events.data.ptr);
                //uint32_t channel = static_cast<uint32_t>(m_events.data.u32);
                //printf("channel = %p\n", channel);
                //printf("1 events = %d\n", channel->getEvents());
                //printf("cb = %d\n", channel->getFd());
                // 用的lt模式 所有要accept把数据接收走,否则会一直触发
                accept(channel->getFd(), (struct sockaddr *)&client_addr, &addr_len);
                //channel->getCb()();
                //qqqq->getCb()();

                //printf("events = %d\n", m_events.events);
                // 设置一下就绪事件,准备处理
                channel->setRevent(m_events.events);
                activeChannel->push_back(channel);
        }
}


Channel
#ifndef __CHANNEL_H__
#define __CHANNEL_H__

#include <functional>
#include <sys/epoll.h>

class EventLoop;

class Channel
{
        public:
                Channel(EventLoop *loop, int fd);

        public:
                typedef std::function<void ()> ReadCallBack;

                // 设置可读事件
                void setReadCallBack(ReadCallBack cb);
                // 注册可读事件
                void enableRead();

                // 移除可读事件
                void disableRead();

                // 设置就绪事件,用于后续处理
                void setRevent(int revents);
                // 处理就绪事件
                void handleEvent();

                int getFd() const
                { return m_fd; }

                int getEvents() const
                { return m_events; }

                ReadCallBack getCb() const
                { return m_readCb; }

        private:       
                inline static const int kNoneEvent = -1;
                inline static const int kReadEvent = EPOLLIN;
                inline static const int kWriteEvent = EPOLLOUT;

                EventLoop                 *m_loop;
                ReadCallBack         m_readCb;
                int                         m_events;
                int                         m_revents;
                int                         m_fd;
};

#endif

#include "Channel.h"
#include "EventLoop.h"

Channel::Channel(EventLoop *loop, int fd)
        : m_loop(loop), m_fd(fd), m_events(0), m_revents(0), m_readCb {}
{

}

// 设置可读事件
void Channel::setReadCallBack(ReadCallBack cb)
{
        m_readCb = std::move(cb);       
       
        // 测试 这里没有丢失
        m_readCb();
}

// 注册可读事件
void Channel::enableRead()
{
        m_events |= kReadEvent;       
        m_loop->update(this);
}

// 移除可读事件
void Channel::disableRead()
{
        m_events |= kNoneEvent;       
}

// 设置就绪事件,用于后续处理
void Channel::setRevent(int revents)
{
        m_revents = revents;
}

// 处理就绪事件
void Channel::handleEvent()
{
        // 处理读事件
        if (m_revents & EPOLLIN)
                m_readCb();
}

EventLoop
#ifndef __EVENTLOOP_H__
#define __EVENTLOOP_H__

#include <memory>

class Channel;
class Epoll;

class EventLoop
{
        public:
                EventLoop();
                void loop();

                // 注册通道
                void update(Channel *channel);
        private:       
                std::shared_ptr<Epoll> m_epoll;
};

#endif

#include "EventLoop.h"
#include <vector>
#include "Epoll.h"
#include "Channel.h"

EventLoop::EventLoop() :
        m_epoll(std::make_shared<Epoll>())
{

}

void EventLoop::loop()
{
        std::vector<Channel *> channels;

        while (1)
        {
                // 等待就绪事件到来
                m_epoll->waitEvent(&channels);

                // 处理就绪事件
                for (int i = 0; i < channels.size(); i++)
                        channels->handleEvent();
        }
}

// 注册通道
void EventLoop::update(Channel *channel)
{
        m_epoll->updateChannel(channel);       
}

测试
#include <iostream>
#include <functional>
#include <sys/types.h>
#include <sys/socket.h>
#include <signal.h>
#include <poll.h>
#include <vector>
#include <netinet/in.h>   // INADDR_ANY
#include <errno.h>
#include <arpa/inet.h> // inet_ntoa
#include <cstring>
#include <unistd.h>

#include "EventLoop.h"
#include "Channel.h"

int listen_fd = -1;

class Accepts
{
public:
        typedef std::function<void()> CallBack;
        Accepts(EventLoop *loop, CallBack cb) : m_loop(loop),
                                                                                        m_cb(std::move(cb)),
                                                                                        m_channel(loop, listen_fd)
        {
                // 设置回调
                m_channel.setReadCallBack(std::bind(&Accepts::handleRead, this));

                // 加入到epoll
                m_channel.enableRead();
        }

private:
        void handleRead()
        {
                // 调用回调
                printf("回调\n");
                m_cb();
        }

private:
        Channel m_channel;
        CallBack m_cb;
        EventLoop *m_loop;
};
void callback()
{
        printf("新的客户端连接过来了\n");
}

void func()
{
        signal(SIGPIPE, SIG_IGN);
        signal(SIGCHLD, SIG_IGN);

        listen_fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);

        struct sockaddr_in server_addr
        {
        };
        server_addr.sin_family = AF_INET;
        server_addr.sin_port = htons(5578);
        server_addr.sin_addr.s_addr = htonl(INADDR_ANY);

        int on = 1;
        int ret;

        setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on));
        bind(listen_fd, (const struct sockaddr *)&server_addr, sizeof(server_addr));

        listen(listen_fd, 1);

        EventLoop loop;
        // 这里写成了临时对象用完到下一句就会被析构 找了好久蛋疼
        //Accepts(&loop, callback);
        Accepts as(&loop, callback);

        loop.loop();
}

int main(void)
{
        func();

       
        return 0;
}
页: [1]
查看完整版本: 事件循环超简化版本