epoll理解_條件觸發和邊緣觸發基礎複習

epoll 的理解與應用

select 缺點:

  • 效率太低
  • 每次向操作系統傳輸對象信息

epoll的優點:

  • 無編寫針對文件描述符的循環語句
  • 無需每次傳遞監控對象信息
#include <sys/epoll.h>
int epoll_create(int size) 創建保存epoll文件描述符的空間
    size 實例大小 可忽略
    創建於套接字相同的資源,也是文件描述符返回
       int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout); 等待發生變化
    失敗返回 -1
   int epoll_ctl(int epfd, int op, int fd, struct epoll_event * event): 向空間註冊並註銷文件描述符
            成功0 失敗-1
    epfd epoll 例程的文件描述符
            op 指定對象的操作
           	fd 對象的文件描述符
            event 事件類型
struct epoll_event {
    __uint32_t events; //發生的事件情況
    epoll_data_t data;
}
typedef union epoll_data {
    void *ptr;
    int fd;
    __unint32_t u32;
    __unint64_t u64;
}epoll_dada_t;

參數:

EPOLL_CTL_ADD 註冊

。。。。。_DEL 刪除

。。。。。_MOD 更改

具體服務端代碼如下:

#include <stdio.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <string.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/epoll.h>

#define BUF_SIZE 100
#define SIZE 50

void error(char *message) {
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(1);
}

int main(int argc, char *argv[]) {
    int ser_sock, cli_sock;
    struct sockaddr_in se_adr, cl_adr;
    socklen_t adr_sz;
    int str_len, i;
    char buf[4];

    struct epoll_event *ep_events;
    struct epoll_event event;
    int epfd, event_cnt;

    ser_sock = socket(PF_INET, SOCK_STREAM, 0);
    memset(&se_adr, 0, sizeof(se_adr));
    se_adr.sin_family = AF_INET;
    se_adr.sin_addr.s_addr = htonl(INADDR_ANY);
    se_adr.sin_port = htons(atoi(argv[1]));
    if (bind(ser_sock, (struct sockaddr*)&se_adr, sizeof(se_adr)) == -1)
        error("bind() error");
    listen(ser_sock, 5);
    epfd = epoll_create(SIZE);
    ep_events = malloc(sizeof(struct epoll_event)*SIZE);

    event.events = EPOLLIN;
    event.data.fd = ser_sock;
    epoll_ctl(epfd, EPOLL_CTL_ADD, ser_sock, &event);
    while (1) {
        event_cnt = epoll_wait(epfd, ep_events, SIZE, -1);
        if (event_cnt == -1)
            error("wait error");
        puts("wait......");
        for (int i = 0; i < event_cnt; ++i) {
            if (ep_events[i].data.fd == ser_sock) {
                adr_sz = sizeof(cl_adr);
                cli_sock = accept(ser_sock, (struct sockaddr*) &cl_adr, &adr_sz);
                event.events = EPOLLIN;
                event.data.fd = cli_sock;
                epoll_ctl(epfd, EPOLL_CTL_ADD, cli_sock, &event);
                printf("new connected ......\n");
            }
            else {
                str_len = read(ep_events[i].data.fd, buf, SIZE);
                if (str_len == 0) {
                    epoll_ctl(epfd, EPOLL_CTL_DEL, ep_events[i].data.fd, NULL);
                    close(ep_events[i].data.fd);
                    printf("disconnect %d\n", ep_events[i].data.fd);
                }
                else {
                    write(ep_events[i].data.fd, buf, str_len);
                }
            }
        }
    }
    close(ser_sock);
    close(epfd);
    return 0;
}

1. 條件觸發與邊緣觸發

邊緣觸發 是指每當狀態變化時發生一個io事件;

條件觸發 是隻要滿足條件就發生一個io事件

1.1 條件觸發

​ 就是在每當收到客戶端數據都會註冊事件,在輸入緩存區還剩的情況下會一直註冊。

select 是條件觸發

上述的服務端就屬於條件觸發

1.2 邊緣觸發

當客戶端接收事件時,只註冊一次。

  • 通過errno變量驗證錯誤原因
  • 爲完成非阻塞I/o,更改套接字特性
#include <fcntl.h>
int fcntl(int filedes, int cmd,.....);
	->成功返回cmd相關參數, 失敗返回-1
        filedes 文件描述符
        cmd 表示函數調用的目的

修改爲非阻塞模式

int flag = fcntl(fd, F_GETEL, 0);
fcntl(fd, F_SETFL, flag|O_NONBLOCK);

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

#define BUF_SIZE 100
#define SIZE 50

void error(char *message) {
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(1);
}

void setmode(int fd) {
    int flage = fcntl(fd, F_GETFL, 0);
    fcntl(fd, F_SETFL, flage|O_NONBLOCK);
}

int main(int argc, char *argv[]) {
    int ser_sock, cli_sock;
    struct sockaddr_in se_adr, cl_adr;
    socklen_t adr_sz;
    int str_len, i;
    char buf[4];

    struct epoll_event *ep_events;
    struct epoll_event event;
    int epfd, event_cnt;

    ser_sock = socket(PF_INET, SOCK_STREAM, 0);
    memset(&se_adr, 0, sizeof(se_adr));
    se_adr.sin_family = AF_INET;
    se_adr.sin_addr.s_addr = htonl(INADDR_ANY);
    se_adr.sin_port = htons(atoi(argv[1]));
    if (bind(ser_sock, (struct sockaddr*)&se_adr, sizeof(se_adr)) == -1)
        error("bind() error");
    listen(ser_sock, 5);
    epfd = epoll_create(SIZE);
    ep_events = malloc(sizeof(struct epoll_event)*SIZE);

    setmode(ser_sock);
    event.events = EPOLLIN;
    event.data.fd = ser_sock;
    epoll_ctl(epfd, EPOLL_CTL_ADD, ser_sock, &event);
    while (1) {
        event_cnt = epoll_wait(epfd, ep_events, SIZE, -1);
        if (event_cnt == -1)
            error("wait error");
        puts("wait......");
        for (int i = 0; i < event_cnt; ++i) {
            if (ep_events[i].data.fd == ser_sock) {
                adr_sz = sizeof(cl_adr);
                cli_sock = accept(ser_sock, (struct sockaddr*) &cl_adr, &adr_sz);
                event.events = EPOLLIN|EPOLLET;
                event.data.fd = cli_sock;
                epoll_ctl(epfd, EPOLL_CTL_ADD, cli_sock, &event);
                printf("new connected ......\n");
            }
            else {
                while (1) {
                    str_len = read(ep_events[i].data.fd, buf, SIZE);
                    if (str_len == 0) {
                        epoll_ctl(epfd, EPOLL_CTL_DEL, ep_events[i].data.fd, NULL);
                        close(ep_events[i].data.fd);
                        printf("disconnect %d\n", ep_events[i].data.fd);
                        break;
                    }
                    else if (str_len < 0){
                        if (errno == EAGAIN)
                            break;
                    }
                    else {
                        write(ep_events[i].data.fd, buf, str_len);
                    }
                }
            }
        }
    }
    close(ser_sock);
    close(epfd);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章