函数,下面就是代码:
-
#define MAXEVENTS 64
-
-
int
-
main (int argc, char *argv[])
-
{
-
int sfd, s;
-
int efd;
-
struct epoll_event event;
-
struct epoll_event *events;
-
-
if (argc != 2)
-
{
-
fprintf (stderr, "Usage: %s [port]\n", argv[0]);
-
exit (EXIT_FAILURE);
-
}
-
-
sfd = create_and_bind (argv[1]);
-
if (sfd == -1)
-
abort ();
-
-
s = make_socket_non_blocking (sfd);
-
if (s == -1)
-
abort ();
-
-
s = listen (sfd, SOMAXCONN);
-
if (s == -1)
-
{
-
perror ("listen");
-
abort ();
-
}
-
-
efd = epoll_create1 (0);
-
if (efd == -1)
-
{
-
perror ("epoll_create");
-
abort ();
-
}
-
-
event.data.fd = sfd;
-
event.events = EPOLLIN | EPOLLET;
-
s = epoll_ctl (efd, EPOLL_CTL_ADD, sfd, &event);
-
if (s == -1)
-
{
-
perror ("epoll_ctl");
-
abort ();
-
}
-
-
/* Buffer where events are returned */
-
events = calloc (MAXEVENTS, sizeof event);
-
-
/* The event loop */
-
while (1)
-
{
-
int n, i;
-
-
n = epoll_wait (efd, events, MAXEVENTS, -1);
-
for (i = 0; i < n; i++)
-
{
-
if ((events[i].events & EPOLLERR) ||
-
(events[i].events & EPOLLHUP) ||
-
(!(events[i].events & EPOLLIN)))
-
{
-
/* An error has occured on this fd, or the socket is not
-
ready for reading (why were we notified then?) */
-
fprintf (stderr, "epoll error\n");
-
close (events[i].data.fd);
-
continue;
-
}
-
-
else if (sfd == events[i].data.fd)
-
{
-
/* We have a notification on the listening socket, which
-
means one or more incoming connections. */
-
while (1)
-
{
-
struct sockaddr in_addr;
-
socklen_t in_len;
-
int infd;
-
char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
-
-
in_len = sizeof in_addr;
-
infd = accept (sfd, &in_addr, &in_len);
-
if (infd == -1)
-
{
-
if ((errno == EAGAIN) ||
-
(errno == EWOULDBLOCK))
-
{
-
/* We have processed all incoming
-
connections. */
-
break;
-
}
-
else
-
{
-
perror ("accept");
-
break;
-
}
-
}
-
-
s = getnameinfo (&in_addr, in_len,
-
hbuf, sizeof hbuf,
-
sbuf, sizeof sbuf,
-
NI_NUMERICHOST | NI_NUMERICSERV);
-
if (s == 0)
-
{
-
printf("Accepted connection on descriptor %d "
-
"(host=%s, port=%s)\n", infd, hbuf, sbuf);
-
}
-
-
/* Make the incoming socket non-blocking and add it to the
-
list of fds to monitor. */
-
s = make_socket_non_blocking (infd);
-
if (s == -1)
-
abort ();
-
-
event.data.fd = infd;
-
event.events = EPOLLIN | EPOLLET;
-
s = epoll_ctl (efd, EPOLL_CTL_ADD, infd, &event);
-
if (s == -1)
-
{
-
perror ("epoll_ctl");
-
abort ();
-
}
-
}
-
continue;
-
}
-
else
-
{
-
/* We have data on the fd waiting to be read. Read and
-
display it. We must read whatever data is available
-
completely, as we are running in edge-triggered mode
-
and won
main() 首先调用 create_and_bind()来新建一个socket。然后将其设置为非阻塞,再调用 listen (2)。之后,我们新建一个epoll实例inefd,并将监听套接字sfd以采用边沿触发的方式加入它,用以监听输入事件。
在外面的while循环是主要的事件循环。它调用epoll_wait(2),它所在线程以阻塞的方式来等待事件的到来。当事件就绪,epoll_wait(2)在其epoll_event类型的参数中返回相应的事件。
当我们添加新的传入连接,当他们终止时我们删除现有的连接,epoll 的实例 inefdis 的事件循环不断更新。
当事件的状态为可用的时候,他们有以下三种类型:
-
错误:当错误情况发生时,或者事件是不是一个有关数据可以被读取的通知,我们只需关闭相关的描述符。关闭描述符会自动移除其 epoll instanceefd。
-
新的连接:当监听到 descriptorsfdis 已经准备好用于读取的时候,这意味着已经到达一个或多个新的连接。当有新连接时,accept(2)连接,打印关于连接的信息,使传入的 socket 不被阻断,并将其添加到 epoll instanceefd 监听事件。
-
客户端数据:当数据在客户端描述符上为可读状态,我们在 read(2) 中使用 while 循环来读去存储在512位数据块中的数据。这是因为我们现在要读取所有可用的数据,在 edge-triggered 模式下,我们不会进一步获取事件描述符。使用 write(2) 将读取的数据被写入到 stdout (fd=1),如果 read(2) 返回 0,这意味着到达了一个 EOF(End of File),这时我们就可以断开与客户端的连接。如果 read(2) 返回 -1,anderrnois 设置为 EAGAIN,这意味着该事件所有的数据已读完,我们可以返回主循环了。
就是这样,它在一个循环中一遍又一遍地执行,在监听的集合中添加和删除描述。