zoukankan      html  css  js  c++  java
  • 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有个感性认识。

    ——————
    无论在哪里做什么,只要坚持服务、创新、创造价值,其他的东西自然都会来的。
  • 相关阅读:
    Echarts饼图页面加载后默认凸出某块
    垂直居中及水平垂直居中方案(共15种)
    CSS Flex布局
    iview04
    重写react-navigation的stackNaviagtor产生的默认导航栏header样式
    RN 去掉Text组件文本的内边距
    RN项目导入到 最新的Android studio
    React Native 设置APP名称、logo图标、启动页
    react native 规避8081端口被占用,同时运行多个RN项目
    Android studio 的SDK默认安装路径找不到AppData文件
  • 原文地址:https://www.cnblogs.com/pied/p/3039088.html
Copyright © 2011-2022 走看看