Epoll
[C++] 纯文本查看 复制代码 #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[i].data.ptr);
//uint32_t channel = static_cast<uint32_t>(m_events[i].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[i].events);
// 设置一下就绪事件,准备处理
channel->setRevent(m_events[i].events);
activeChannel->push_back(channel);
}
}
Channel
[C++] 纯文本查看 复制代码 #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
[C++] 纯文本查看 复制代码 #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[i]->handleEvent();
}
}
// 注册通道
void EventLoop::update(Channel *channel)
{
m_epoll->updateChannel(channel);
}
测试
[C++] 纯文本查看 复制代码 #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;
}
|