epoll_wait(2)
SYNOPSIS
#include <sys/epoll.h>
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
DESCRIPTION
epoll_wait()系统调用等待文件描述符epfd引用的epoll实例上的事件. 事件指向的内存区域将包含可用于调用者的事件. 由epoll_wait()返回maxevents. maxevents参数必须大于零.
timeout参数指定epoll_wait()将阻塞的毫秒数. 调用会一直阻塞, 直到以下情况之一出现:
- 文件描述符递送一个事件
- 调用被信号中断
- 超时
注意:超时的间隔将四舍五入到系统时钟粒度, 并且内核调度延迟意味着阻塞间隔可能会少量超出. 指定超时为-1时, 会导致epoll_wait()无限期阻塞. 当然, 指定超时等于零会导致epoll_wait()立即返回, 即使没有事件可用.
struct epoll_event 被定义为:
typedef union epoll_data {
void *ptr;
int fd;
uint32_t u32;
uint64_t u64;
} epoll_data_t;
struct epoll_event {
uint32_t events; /* Epoll events */
epoll_data_t data; /* User data variable */
};
RETURN VALUE
成功: epoll_wait() 返回为所请求的I / O准备好的文件描述符数, 如果在请求的超时期间没有文件描述符就绪, 则为零.
错误: 返回-1, 并且设置errno.
ERRORS
- EBADF epfd 不是合适的文件描述符
- EFAULT events 所指的内存区域不可通过写权限访问.
- EINTR 在任何请求的事件发生之前或超时到期之前, 该调用被信号处理程序中断.
- EINVAL epfd 不是文件描述符. 或maxevents 小于等于0.
以上是实现需要的函数.
具体实现
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/epoll.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <unistd.h>
#define MAX_EVENT 50
/* 将套接字设置为非阻塞 */
void setnonblocking(int fileno)
{
int flags;
if((flags = fcntl(fileno, F_GETFL)) < 0) {
perror("fcntl get error");
exit(EXIT_FAILURE);
}
flags |= O_NONBLOCK;
if(fcntl(fileno, F_SETFL, flags) < 0) {
perror("fcntl set error");
exit(EXIT_FAILURE);
}
}
void do_something(int sockfd)
{
char buff[4096];
char head[] = "HTTP/1.1 200 OK\r\nContent-type: text/html\r\nServer: MyServer/2.3.3 (DebianOS)\r\n\r\n";
char send[] = "<html><title>test</title><body><h1>This is a Demo Server!!</h1></body></html>";
read(sockfd, buff, 4096);
write(sockfd, head, sizeof(head));
write(sockfd, send, sizeof(send));
printf("%s", buff);
}
int main(void)
{
int connfd;
struct sockaddr_in servaddr;
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_addr.s_addr = INADDR_ANY;
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(2333);
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
listen(sockfd, 1024);
struct epoll_event ev, events[MAX_EVENT];
int nfds, epollfd;
if((epollfd = epoll_create1(0)) == -1) {
perror("epoll_create1 error");
exit(EXIT_FAILURE);
}
ev.events = EPOLLIN;
ev.data.fd = sockfd;
if(epoll_ctl(epollfd, EPOLL_CTL_ADD, sockfd, &ev) == -1) {
perror("epoll_ctl error");
exit(EXIT_FAILURE);
}
while(true) {
if((nfds = epoll_wait(epollfd, events, MAX_EVENT, -1)) == -1) {
perror("epoll_wait error");
exit(EXIT_FAILURE);
}
for(int n = 0; n < nfds; ++n) {
if(events[n].data.fd == sockfd) {
socklen_t socklen = sizeof(servaddr);
connfd = accept(sockfd, (struct sockaddr *)&servaddr, &socklen);
if(connfd == -1) {
perror("accept error");
exit(EXIT_FAILURE);
}
setnonblocking(connfd);
ev.events = EPOLLIN | EPOLLET;
ev.data.fd = connfd;
if(epoll_ctl(epollfd, EPOLL_CTL_ADD, connfd, &ev) == -1) {
perror("epoll_ctl: connfd");
exit(EXIT_FAILURE);
}
} else {
do_something(events[n].data.fd);
close(events[n].data.fd);
events[n].data.fd = -1;
}
}
}
return 0;
}
截个图: