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"<