Skip to content

epoll example on Linux

c
#include <stdio.h>
#include <stdlib.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

#define EPOLL_INSTANCE_SIZE 256
#define SERVER_ADDR "0.0.0.0"
#define SERVER_PORT 30000
#define MAX_CONNETIONS 20
#define MAX_EVENTS 20
#define BUF_SIZE 1024

void setnonblocking(int fd) {
    int fl = fcntl(fd, F_GETFL);
    if (fl < 0) {
        perror("fctn(F_GETFL) error");
        exit(1);
    }
    fl |= O_NONBLOCK;
    if (fcntl(fd, F_SETFL, fl) < 0) {
        perror("fcntl(F_SETFL)");
        exit(1);
    }
}

int main(int argc, char const *argv[]) {
    int epfd = epoll_create(EPOLL_INSTANCE_SIZE);  // epfd to an epoll instance

    int listen_fd = socket(AF_INET, SOCK_STREAM, 0);  // IPv4 TCP Socket
    setnonblocking(listen_fd);

    struct epoll_event ev;
    ev.data.fd = listen_fd;
    ev.events = EPOLLIN | EPOLLET;  // read and edge-triggered

    // add listen_fd to epfd with ev is interested
    epoll_ctl(epfd, EPOLL_CTL_ADD, listen_fd, &ev);

    // construct server addr
    struct sockaddr_in server_addr;
    bzero(&server_addr, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    char *addr = SERVER_ADDR;
    inet_aton(addr, &(server_addr.sin_addr));
    server_addr.sin_port = htons(SERVER_PORT);

    bind(listen_fd, (struct sockaddr *)&server_addr, sizeof(server_addr));
    listen(listen_fd, MAX_CONNETIONS);

    struct epoll_event events[MAX_EVENTS];
    struct sockaddr_in client_addr;
    int i;
    char buf[BUF_SIZE];
    int n;
    for (;;) {
        int nfds = epoll_wait(epfd, events, 20, 5000);
        for (i = 0; i < nfds; ++i) {
            if (events[i].data.fd == listen_fd) {
                socklen_t addr_len;
                int fd = accept(listen_fd, (struct sockaddr *)&client_addr,
                                &addr_len);
                if (fd < 0) {
                    perror("accept: fd < 0");
                    exit(1);
                }

                setnonblocking(fd);

                char *s = inet_ntoa(client_addr.sin_addr);
                printf("accept connection from %s:%d\n", s,
                       ntohs(client_addr.sin_port));

                ev.data.fd = fd;
                ev.events = EPOLLIN | EPOLLET;
                epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev);
            } else if (events[i].events & EPOLLIN) {
                int fd = events[i].data.fd;
                if (fd < 0) continue;
                n = read(fd, buf, BUF_SIZE);
                if (n < 0) {
                    if (errno == ECONNRESET) {
                        close(fd);
                        events[i].data.fd = -1;
                    } else {
                        printf("read error\n");
                    }
                } else if (n == 0) {
                    close(fd);
                    events[i].data.fd = -1;
                    printf("peer exit\n");
                } else {
                    printf("received data: %s", buf);
                }

                ev.data.fd = fd;
                ev.events = EPOLLOUT | EPOLLET;
                epoll_ctl(epfd, EPOLL_CTL_MOD, fd, &ev);
            } else if (events[i].events & EPOLLOUT) {
                int fd = events[i].data.fd;

                write(fd, buf, n);
                printf("write data:    %s", buf);

                ev.data.fd = fd;
                ev.events = EPOLLIN | EPOLLET;
                epoll_ctl(epfd, EPOLL_CTL_MOD, fd, &ev);
            }
        }
    }

    return 0;
}

Last updated at: