1、epoll()

  epoll()是Linux特有的I/O复用函数,它的实现与使用上和select()、poll()、有很大差异。

  epoll()用一组函数来完成任务,而不是单个函数;其次,epoll()把文件描述放到内核事件表中,只需一个额外的文件描述符,来标识内核中唯一的这个事件表。

  需要使用的API:

  int epoll_create(int size);

  int epoll_ctl(int epfd, int op, int fd, struct epoll_event *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 */
};

  int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);

2、epoll_wait()

  关键:对epoll_wait()函数的核心理解

  (1)、返回值:事件表中就绪客户端的个数;

  (2)、参数events:将事件表中的就绪客户端的信息放到了events数组中。

3、epoll()的核心思想

  :就是创建一个内核事件表,存放所监听客户端的套接字和当前的事件,在利用epoll_wait()函数查找就绪的套接字,最后经过增加、删除、修改利用epoll_ctl()函数进行;当然了,这其中还有一批搭配使用的宏;

3、代码实现

(1)、utili.h

#include
#include
#include
#include
#include
#include
#include
#include

#include

#define SERVER_IP "127.0.0.1"
#define SERVER_PORT  8787
#define LISTEN_QUEUE 5
#define SIZE 10
#define BUFFER_SIZE 256

#include
#define OPEN_MAX 1000

#include
#define FDSIZE      1000
#define EPOLLEVENTS 100

(2)、ser.c

#include"../utili.h"

static int socket_bind(const char *ip, int port){
    int listenfd = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in addrSer;
    addrSer.sin_family = AF_INET;
    //addrSer.sin_addr.s_addr = inet_addr(ip);
    inet_pton(AF_INET, ip, &addrSer.sin_addr);
    addrSer.sin_port = htons(port);
    bind(listenfd, (struct sockaddr*)&addrSer, sizeof(struct sockaddr));
    return listenfd;
}

static void add_event(int epollfd, int fd, int state){
    struct epoll_event ev;
    ev.events = state;
    ev.data.fd = fd;
    epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev);
}

static void delete_event(int epollfd, int fd, int state){
    struct epoll_event ev;
    ev.events = state;
    ev.data.fd = fd;
    epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, &ev);
}
static void modify_event(int epollfd, int fd, int state){
    struct epoll_event ev;
    ev.events = state;
    ev.data.fd = fd;
    epoll_ctl(epollfd, EPOLL_CTL_MOD, fd, &ev);
}

static void handle_accept(int epollfd, int listenfd){
    int clifd;
    struct sockaddr_in addrCli;
    socklen_t len = sizeof(struct sockaddr);
    clifd = accept(listenfd, (struct sockaddr*)&addrCli, &len);
    if(clifd != -1){
        add_event(epollfd, clifd, EPOLLIN);
    }
}

static void do_read(int epollfd,  int fd, char *buf){
    int nread = read(fd, buf, BUFFER_SIZE);
    if(nread == -1){
        close(fd);
        delete_event(epollfd, fd, EPOLLIN);
    }else{
        printf("read msg:>%s\n",buf);
        modify_event(epollfd, fd, EPOLLOUT);
    }
}
static void do_write(int epollfd, int fd, char *buf){
    int nwrite = write(fd, buf, strlen(buf)+1);
    if(nwrite == -1){
        close(fd);
        delete_event(epollfd, fd, EPOLLOUT);
    } else{
        modify_event(epollfd, fd , EPOLLIN);
    }
    memset(buf, 0, BUFFER_SIZE);

}

static void handle_events(int epollfd, struct epoll_event *events, int num,
                            int listenfd, char *buf){
    int i;
    int fd;
    for(i=0; i 
  

(3)、cli.c

#include"../utili.h"

static void add_event(int epollfd, int fd, int state){
    struct epoll_event ev;
    ev.events = state;
    ev.data.fd = fd;
    epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev);
}

static void delete_event(int epollfd, int fd, int state){
    struct epoll_event ev;
    ev.events = state;
    ev.data.fd = fd; 
    epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, &ev);
}

static void modify_event(int epollfd, int fd, int state){
    struct epoll_event ev; 
    ev.events = state;
    ev.data.fd = fd; 
    epoll_ctl(epollfd, EPOLL_CTL_MOD, fd, &ev);
}



static void do_read(int epollfd,  int fd, int sockfd, char *buf){
    int nread = read(fd, buf, BUFFER_SIZE);
    if(nread == -1) {
        close(fd);
        delete_event(epollfd, fd, EPOLLIN);
    }else{
        if(fd == STDIN_FILENO)
            add_event(epollfd, fd, EPOLLIN);
        else{
            delete_event(epollfd, fd, EPOLLIN);
            add_event(epollfd, STDOUT_FILENO, EPOLLOUT);
        }
    }
    printf("Ser :>%s", buf);
}

static void do_write(int epollfd, int fd, int sockfd, char *buf){
    int nwrite = write(fd, buf, strlen(buf)+1);
    if(nwrite == -1){
        perror("write");
        close(fd);
    }else{
        if(fd == STDOUT_FILENO){
            delete_event(epollfd, fd, EPOLLOUT);
        }else{
            modify_event(epollfd, fd, EPOLLIN);
        }
    }    
    memset(buf, 0, BUFFER_SIZE);
}


static void handle_events(int epollfd, struct epoll_event *events, int num,
                            int sockfd, char *buf){
    int i;
    int fd;
    for(i=0; i 
  

运行结果

  服务器端就是等待客户端的使用;

客户端1

客户端2

利用epoll()函数,不用轮询每个套接字,效率更高效一些;