Linux下Epoll简介

什么是epoll?简单来讲,就是替代select的一种方法。如果不知到select是什么,就不用往下看了。

为什么要替换掉select?大家说,原因有两个:

1)Select有链接数量限制,epoll没有。

2)select在处理大两并发时效率低。

关于第一个原因,搜了下结果如下:

我本人也曾经在项目中用过select和epoll,对于select,感触最深的是linux下select最大数目限制(windows 下似乎没有限制),每个进程的select最多能处理FD_SETSIZE个FD(文件句柄),
如果要处理超过1024个句柄,只能采用多进程了。
常见的使用slect的多进程模型是这样的: 一个进程专门accept,成功后将fd通过unix socket传递给子进程处理,父进程可以根据子进程负载分派。曾经用过1个父进程+4个子进程 承载了超过4000个的负载。
这种模型在我们当时的业务运行的非常好。epoll在连接数方面没有限制,当然可能需要用户调用API重现设置进程的资源限制。

第二个原因,作者在博客里也做了介绍。select最终调用是net/ipv4/tcp.c,一直在做轮寻;而epoll则是等待事件发生时,告诉进程现在的socket是可读还是可写。

对上面内容哦你感兴趣的可以戳这里:http://www.cppblog.com/feixuwu/archive/2010/07/10/119995.html

了解就这么多,很可能是错的,今天只是敲了下demo代码,暂时放这里。

//server.c
#include    <stdio.h>
#include    <string.h>
#include    <fcntl.h>
#include    <sys/epoll.h>
#include    <sys/socket.h>
#include    <netinet/in.h>

#define MAX_SOCKET 10000

void
add_event(int epfd, int fd, struct epoll_event *event)
{
    epoll_ctl(epfd, EPOLL_CTL_ADD, fd, event);
}

void
mod_event(int epfd, int fd, struct epoll_event *event)
{
    epoll_ctl(epfd, EPOLL_CTL_MOD, fd, event);
}

void
del_event(int epfd, int fd, struct epoll_event *event)
{
    epoll_ctl(epfd, EPOLL_CTL_DEL, fd, event);
}

int
init_listen(int epfd, int port)
{
    int listenfd = socket(AF_INET, SOCK_STREAM,  0);
    fcntl(listenfd, F_SETFL, O_NONBLOCK);

    struct epoll_event event;
    event.data.fd = listenfd;
    event.events = EPOLLIN | EPOLLET;
    add_event(epfd, listenfd, &event);

    struct sockaddr_in serveraddr;
    memset(&serveraddr, 0, sizeof(struct sockaddr_in));
    serveraddr.sin_family = AF_INET;
    inet_aton("127.0.0.1",&(serveraddr.sin_addr));
    serveraddr.sin_port = htons(port);
    bind(listenfd, (struct sockaddr *)&serveraddr, sizeof(struct sockaddr_in));
    listen(listenfd, 10);
    return listenfd;
}

void
accept_conn(int epfd, int listenfd)
{
    printf("connection begin...\n");
    socklen_t length;
    struct sockaddr_in clientaddr;
    memset( &clientaddr, 0, sizeof(struct sockaddr_in));
    int fd = accept(listenfd, (struct sockaddr *)&clientaddr, &length);
    fcntl(fd, F_SETFL, O_NONBLOCK);
    printf("connected...\n");

    char *clientip =inet_ntoa(clientaddr.sin_addr);
    if(clientip == NULL) printf("error!\n");
    unsigned short clientport = ntohs(clientaddr.sin_port);
//    printf("client connected: %s:%d\n",clientip, clientport);

    struct epoll_event event;
    event.data.fd = fd;
    event.events = EPOLLIN | EPOLLET;
    add_event(epfd, fd, &event);
}

void
recv_data(int epfd, int fd)
{
    char buffer[1024];
    memset(buffer, 0, sizeof(buffer));

    ssize_t count = read(fd, buffer, sizeof(buffer));
    if (count <= 0){
        close(fd);
        return;
    }

    printf("fd %d recv: %s \n", fd, buffer);

    struct epoll_event event;
    event.data.fd = fd;
    event.events = EPOLLOUT | EPOLLET;
    mod_event(epfd, fd, &event);
}

void
send_data(int epfd, int fd)
{
    char buffer[1024];
    static int i=0;
    memset(buffer, 0, sizeof(buffer));
    i++;
    sprintf(buffer, "hello fd %d,i=%d", fd,i);
    ssize_t count = write(fd, buffer, strlen(buffer));
    if (count <= 0){
        close(fd);
        return;
    }

    printf("fd %d send: %s\n", fd, buffer);

    struct epoll_event event;
    event.data.fd = fd;
    event.events = EPOLLIN | EPOLLET;
    mod_event(epfd, fd, &event);
}

int
main()
{
    int port = 12345;
    int epfd = epoll_create(MAX_SOCKET);
    int listenfd = init_listen(epfd, port);
    printf("fd %d listen: %d\n", listenfd, port);

    while (1) {
        printf("epoll_wait.. \n");
        struct epoll_event events[20];
        int fds = epoll_wait(epfd, events, 20, 5000);
        printf("epoll_wait fds:%d\n", fds);

        int i;
        for (i = 0; i < fds; i++){
            int fd = events[i].data.fd;
            if (fd == listenfd){
                printf("accept_conn...\n");
                accept_conn(epfd, listenfd);
                continue;
            }
            if (events[i].events & EPOLLIN) {
                printf("recv_data fd: %d\n", fd);
                recv_data(epfd, fd);
            }
            if (events[i].events & EPOLLOUT) {
                printf("send_data fd; %d\n", fd);
                send_data(epfd, fd);
            }
        }
    }
    close(epfd);
}

再贴个client:

/client
#include    <sys/types.h>
#include    <sys/socket.h>
#include    <stdio.h>
#include    <netinet/in.h>
#include    <arpa/inet.h>
#include    <unistd.h>
#include    <stdlib.h>


int
main()
{
    int sockfd;
    int len;
    int result;
    char ch[20]={'1','2','3'};

    sockfd = socket(AF_INET, SOCK_STREAM, 0);

    struct sockaddr_in address;
    address.sin_family = AF_INET;
//    strcpy(address.sun_path, "server_socket");
    inet_aton("127.0.0.1",&(address.sin_addr));
    len = sizeof(address);
    address.sin_port = htons(12345);

    result = connect(sockfd, (struct sockaddr *)&address, len);

    if(result == -1) {
        perror("oops; connect failed");
        exit(1);
    }

    write(sockfd, ch, 4);
    read(sockfd, ch, 5);
    printf("char from server = %s \n", ch);
    close(sockfd);
    exit(0);
}

偶得空闲,只为对epool有个感性认识。

posted @ 2013-04-23 22:20  Biiigfish  阅读(592)  评论(1编辑  收藏  举报