关于epoll解说请参考:
下面是使用实例,也可以参考man epoll Ubuntu上的实例
#define BUFFSIZE 1024
#define PORT 5588
using namespace std;
#define ERR_EXIT(a) do \
{ \
printf("%s", a); \
} while (0);
typedef vector<struct epoll_event> EventList;
template<typename T>
void log(T msg)
{
cout<<msg<<endl;
}
void activate_nonblock(int fd)
{
int ret;
int flags=fcntl(fd,F_GETFL);
if(flags == -1)
{
ERR_EXIT("fcntl");
}
flags |= O_NONBLOCK;
ret = fcntl(fd,F_SETFL,flags);
if(ret ==-1)
{
ERR_EXIT("fcntl");
}
}
int initSock()
{
int fd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in sockaddr_t;
memset(&sockaddr_t, 0, sizeof(sockaddr_t));
sockaddr_t.sin_family = AF_INET;
sockaddr_t.sin_port = htons(PORT);
sockaddr_t.sin_addr.s_addr = htonl(INADDR_ANY);
/*设置为非阻塞*/
// int flags = fcntl(fd, F_GETFL, 0);
// fcntl(fd, F_SETFL, flags|O_NONBLOCK);
//设置地址重复利用
int on = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
{
log("setsockopt");
}
if (bind(fd, (struct sockaddr*)&sockaddr_t, sizeof(sockaddr_t)) < 0 )
{
log("bind is failed");
return -1;
}
if(listen(fd, SOMAXCONN) < 0)
{
log("listen is failed");
return -1;
}
return fd;
}
int acceptPool(int fd)
{
int acceptfd;
struct sockaddr_in clientAddr;
socklen_t len = sizeof(clientAddr);
char readbuff[BUFFSIZE];
EventList events(10);
struct epoll_event ev;
int epollfd = epoll_create1(EPOLL_CLOEXEC);
ev.events = EPOLLIN;//设置关注事件
ev.data.fd = fd;
if(epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) < 0)
{
log("epoll_ctl is errno");
exit(EXIT_FAILURE);
}
int retVal = 0;
while(1)
{
retVal = epoll_wait(epollfd, &*events.begin(), static_cast<int>(events.size()), -1);
if (retVal < 0 && errno == EINTR)
{
continue;
}
else if (retVal < 0)
{
log("epoll_wait is errno");
return -1;
}
if (events.size() == retVal)
{
events.resize(events.size() * 2);
}
cout<<"things size is :"<<events.size()<<endl;
for (int i = 0; i < events.size(); ++i)
{
if (events[i].data.fd == fd)
{
acceptfd = accept(events[i].data.fd, (struct sockaddr*)&clientAddr,&len);
if (acceptfd < 0)
{
log("accept is errno");
return -1;
}
activate_nonblock(acceptfd);
ev.data.fd = acceptfd;
ev.events = EPOLLIN; //设置关注事件
epoll_ctl(epollfd, EPOLL_CTL_ADD, acceptfd, &ev); //将新的连接添加到关注的集合
log("have a client connect");
}
else if (events[i].events & EPOLLIN)
{
memset(readbuff, 0, sizeof(readbuff));
int ret = read(events[i].data.fd, readbuff, sizeof(readbuff));
if (ret < 0)
{
log("read erron");
break;
}
else if (ret == 0)
{
log("close a client");
close(events[i].data.fd);
epoll_ctl(epollfd, EPOLL_CTL_DEL, events[i].data.fd, &events[i]);
continue;
}
log(readbuff);
write(events[i].data.fd, readbuff, strlen(readbuff));
}
}
}
return 0;
}
int main(int argc, char const *argv[])
{
int fd = initSock();
acceptPool(fd);
return 0;
}
epoll LT 模式:水平触发,当内核缓冲区为空时(write)或为满时(read)触发
epoll ET模式:边缘触发,当内核缓冲区为由满到空时(write)或为由空到满时(read)触发