使用范例:
epoll最多的用途就是socket编程,可以大大提高服务器的性能,此处我们实现一个简单的http服务器。 #define MAXFDS 128
#define EVENTS 100
#define PORT 8080
#define MAXEPOLLSIZE 1024*10
typedef enum
{
false,
true
}bool;
/***************定义处理socket的回调函数类型***********/
typedef int (*socket_pro)(int fd,void *data);
/***************定义回调函数的用户数据***********/
typedef struct userdata
{
int fd;
socket_pro cb;
}userdata_t;
static int epfd;//epoll句柄
/***************发送一个文件数据的函数***********/
static void cws_client_request (int connfd,void *data)
{
struct epoll_event ev = {0};
char buffer[1024*8] = {0};
int ret;
char *requestPath = NULL;
char tmpPath[512] = {"./www/"};
int pagesize = 0;
ret = recv (connfd, buffer, sizeof (buffer) -1, 0);
if (ret > 0)
{
if (strncmp (buffer, "GET ", 4) != 0)
{
printf("bad request.\n");
}
if (strncmp (buffer, "GET /", 5) == 0)
{
if (strncmp (buffer, "GET / ", 6) == 0)
{
strcat(tmpPath, "/index.html");
requestPath = tmpPath;
}
else
{
requestPath = buffer+5;
char * pos = strstr(buffer+5, " ");
strncat(tmpPath, requestPath, pos - requestPath);
requestPath = tmpPath;
}
}
char * badRequest = (char *)"Error 404 Not Found.";
char * httpStatus200 = (char *)"HTTP/1.0 200 OK\r\nContent-Type:text/html\r\n\r\n";
FILE * fp = fopen(requestPath, "r");
FILE * connfp = fdopen(connfd, "w");
if ( connfp == NULL )
{
perror("fdopen error");//cout <
}
if (fp == NULL)
{
setlinebuf(connfp);
fwrite(badRequest, strlen(badRequest), 1, connfp);
fclose(connfp);
}
else
{
setlinebuf(connfp);
//fwrite(httpStatus200, strlen(httpStatus200), 1, connfp);
//fflush(connfp);
while ((ret = fread (buffer, 1, sizeof(buffer) -1, fp)) > 0)
{
fwrite(buffer, 1, ret, connfp);
pagesize += ret;
fflush(connfp);
}
printf("pagesize:%d\n",pagesize);//cout <
fclose(fp);
}
}
//1
close(connfd);
epoll_ctl (epfd, EPOLL_CTL_DEL, connfd, &ev);
}
/***************处理已经连接socket函数***********/
static int __process_data_fd(int fd,void *data)
{
struct epoll_event *ev = (struct epoll_event *)data;
cws_client_request(fd,ev);
free(data);
return;
}
/***************处理监听socket函数***********/
static int __process_listen_fd(int fd,void *data)
{
struct sockaddr_in caddr = {0};
struct epoll_event ev = {0};
int len = sizeof (caddr);
int cfd = accept (fd, (struct sockaddr *) &caddr, (socklen_t *) & len);
if (-1 == cfd)
{
perror("accpet error");//cout << "server has an error, now accept a socket fd" <
break;
}
setNonBlock (cfd);
userdata_t *cb_data = malloc(sizeof(userdata_t));
cb_data->fd = cfd;
cb_data->cb = __process_data_fd;
ev.data.ptr = cfd;
ev.events = EPOLLIN | EPOLLET;
epoll_ctl (epfd, EPOLL_CTL_ADD, cfd, &ev);
return 0;
}
/***************设置描述符为非阻塞***********/
static bool setNonBlock (int fd)
{
int flags = fcntl (fd, F_GETFL, 0);
flags |= O_NONBLOCK;
if (-1 == fcntl (fd, F_SETFL, flags))
{
return false;
}
return true;
}
/***************主函数***********/
int main (int argc, char *argv[])
{
int listen_fd, nfds;
int on = 1;
char buffer[512];
struct sockaddr_in saddr, caddr;
struct epoll_event ev, events[EVENTS];
signal(SIGPIPE, SIG_IGN);
if (fork())
{
exit(0);
}
if (-1 == (listen_fd = socket(AF_INET, SOCK_STREAM, 0)))
{
perror("socket error");//cout << "create socket error!" << endl;
return -1;
}
epfd = epoll_create (MAXFDS);
setsockopt (listen_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on));
bzero (&saddr, sizeof (saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = htons ((short) (PORT));
saddr.sin_addr.s_addr = INADDR_ANY;
if (-1 == bind(listen_fd, (struct sockaddr *) &saddr, sizeof (saddr)))
{
perror("bind error");//cout << " cann't bind socket on server " << endl;
return -1;
}
if (-1 == listen (listen_fd, 32))
{
perror("listen error");//cout << "listen error" << endl;
return -1;
}
userdata_t *cb_data = (userdata_t *)malloc(sizeof(userdata_t));
cb_data->fd = listen_fd;
cb_data->cb = __process_listen_fd;
ev.data.ptr = cb_data;
ev.events = EPOLLIN|EPOLLET;
epoll_ctl (epfd, EPOLL_CTL_ADD, listen_fd, &ev);
for (;;)
{
int i;
nfds = epoll_wait (epfd, events, MAXFDS, -1);
for (i = 0; i < nfds; ++i)
{
userdata_t *cb_data = (userdata_t *)events[i].data.ptr;
cb_data.cb(cb_data.fd,cb_data);
}
}
if (listen_fd > 0)
{
shutdown (listen_fd, SHUT_RDWR);
close (listen_fd);
}
return 0;
}