吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 1336|回复: 0
收起左侧

[C&C++ 转载] 事件循环超简化版本

  [复制链接]
古月不傲 发表于 2021-1-26 21:23
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;
}

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-5-13 04:04

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表