linux c/c++网络编程之—epoll 模型

linux 内核2.4版本以上开始支持epoll, epoll相比select性能有较大的提升,首先支持的连接数基本不受限制,只受到内存等系统资源的限制,epoll是一种异步通知机制,只有有网络事件发生了,就会主动加入监听集合,select需要轮训事件集合,这样效率会低很多,尤其连接数多,但大部分连接不活跃的情况,select 的效率会低很多。目前大部分的linux网络库,底层都是epoll实现。下面只是一个最基本的epoll模型的实例
#include   
#include   
#include   
#include   
#include  
#include  
#include   
#include   
#include   
#include   
using namespace std;

class epoll_server
{
	public:
		epoll_server();
		virtual ~epoll_server();
		bool init(int port, int sock_count);
		bool init(const char* ip, int port, int sock_count);
		int epoll_server_wait(int time_out);
		int accept_new_client();
		int recv_data(int sock, char* recv_buf);
		int send_data(int sock, char* send_buf, int buf_len);
		void run(int time_out);

	private:
		int m_listen_sock;
		int m_epoll_fd;
		int m_max_count;
		struct epoll_event *m_epoll_events;
};

epoll_server::epoll_server()
{
	m_listen_sock = 0;
	m_epoll_fd = 0;
	m_max_count = 0;
	m_epoll_events = NULL;
}

epoll_server::~epoll_server()
{
	if (m_listen_sock > 0)
	{
		close(m_listen_sock);
	}

	if (m_epoll_fd > 0)
	{
		close(m_epoll_fd);
	}
}


bool epoll_server::init(int port , int sock_count)
{
	m_max_count = sock_count;	
	struct sockaddr_in server_addr;
	memset(&server_addr, 0, sizeof(&server_addr));
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(port);
	server_addr.sin_addr.s_addr = htonl(INADDR_ANY);		

	m_listen_sock = socket(AF_INET, SOCK_STREAM, 0);
	if(m_listen_sock == -1)
	{
		exit(1);
	}
	
	if(bind(m_listen_sock, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1)
	{
		exit(1);
	}
	
	if(listen(m_listen_sock, 5) == -1)
	{
		exit(1);
	}

	m_epoll_events = new struct epoll_event[sock_count];
	if (m_epoll_events == NULL)
	{
		exit(1);
	}

	m_epoll_fd = epoll_create(sock_count);
	struct epoll_event ev;
	ev.data.fd = m_listen_sock;
	ev.events  = EPOLLIN;
	epoll_ctl(m_epoll_fd, EPOLL_CTL_ADD, m_listen_sock, &ev);
}

bool epoll_server::init(const char* ip, int port , int sock_count)
{	
	m_max_count = sock_count;
	struct sockaddr_in server_addr;
	memset(&server_addr, 0, sizeof(&server_addr));
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(port);
	server_addr.sin_addr.s_addr = inet_addr(ip);		

	m_listen_sock = socket(AF_INET, SOCK_STREAM, 0);
	if(m_listen_sock == -1)
	{
		exit(1);
	}
	
	if(bind(m_listen_sock, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1)
	{
		exit(1);
	}
	
	if(listen(m_listen_sock, 5) == -1)
	{
		exit(1);
	}

	m_epoll_events = new struct epoll_event[sock_count];
	if (m_epoll_events == NULL)
	{
		exit(1);
	}

	m_epoll_fd = epoll_create(sock_count);
	struct epoll_event ev;
	ev.data.fd = m_listen_sock;
	ev.events  = EPOLLIN;
	epoll_ctl(m_epoll_fd, EPOLL_CTL_ADD, m_listen_sock, &ev);
}

int epoll_server::accept_new_client()
{
	sockaddr_in client_addr;
	memset(&client_addr, 0, sizeof(client_addr));
    socklen_t clilen = sizeof(struct sockaddr); 
    int new_sock = accept(m_listen_sock, (struct sockaddr*)&client_addr, &clilen);
	struct epoll_event ev;
	ev.data.fd = new_sock;
	ev.events  = EPOLLIN;
	epoll_ctl(m_epoll_fd, EPOLL_CTL_ADD, new_sock, &ev);
	return new_sock;
}

int epoll_server::recv_data(int sock, char* recv_buf)
{
	char buf[1024] = {0};
	int len = 0;
	int ret = 0;
	while(ret >= 0)
	{
		ret = recv(sock, buf, sizeof(buf), 0);
		if(ret <= 0)
		{
			struct epoll_event ev;
			ev.data.fd = sock;
			ev.events  = EPOLLERR;
			epoll_ctl(m_epoll_fd, EPOLL_CTL_DEL, sock, &ev);
			close(sock);
			break;
		}
		else if(ret < 1024)
		{
			memcpy(recv_buf, buf, ret);
			len += ret;	
			struct epoll_event ev;
			ev.data.fd = sock;
			ev.events  = EPOLLOUT;
			epoll_ctl(m_epoll_fd, EPOLL_CTL_MOD, sock, &ev);
			break;
		}
		else
		{
			memcpy(recv_buf, buf, sizeof(buf));
			len += ret;
		}
	}

	return ret <= 0 ? ret : len;
}

int epoll_server::send_data(int sock, char* send_buf, int buf_len)
{
	int len = 0;
	int ret = 0;
	while(len < buf_len)
	{
		ret = send(sock, send_buf + len, 1024, 0);
		if(ret <= 0)
		{
			struct epoll_event ev;
			ev.data.fd = sock;
			ev.events  = EPOLLERR;
			epoll_ctl(m_epoll_fd, EPOLL_CTL_DEL, sock, &ev);
			close(sock);
			break;
		}
		else
		{
			len += ret;
		}

		if(ret < 1024)
		{
			break;
		}
	}

	if(ret > 0)
	{
		struct epoll_event ev;
		ev.data.fd = sock;
		ev.events  = EPOLLIN;
		epoll_ctl(m_epoll_fd, EPOLL_CTL_MOD, sock, &ev);
	}

	return ret <= 0 ? ret : len;
}

int epoll_server::epoll_server_wait(int time_out)
{
	int nfds = epoll_wait(m_epoll_fd, m_epoll_events, m_max_count, time_out);
}

void epoll_server::run(int time_out)
{
	char *recv_buf = new char[65535];
	char *send_buf = new char[65535];
	while(1)
	{
		int ret = epoll_server_wait(time_out);
		if(ret == 0)
		{
			cout<<"time out"<

你可能感兴趣的:(linux c/c++网络编程之—epoll 模型)