zoukankan      html  css  js  c++  java
  • epoll

    epoll的触发方式有水平触发以及边缘触发。

    水平触发相当于高级的select,当可读或可写时就会触发。比如将fd设为可读并交给epoll,只要fd有数据可读都会触发

    边缘触发是在由不可读变为可读一瞬间触发一次。

    #define socket_t int
    
    static void socket_call(const char *label, int result) {
        if (result < 0) {
            fprintf(stderr, "%s : %s", label, strerror(errno));
            abort();
        }
    }
    
    void set_nonblock(socket_t fd) {
    //    int nb;
    //    nb = 1;
    //    return ioctl(fd, FIONBIO, &nb);
        int fl = fcntl(fd, F_GETFL);
        fcntl(fd, F_SETFL, fl | O_NONBLOCK);
    }
    
    socket_t startup(char* _ip, int _port)  //创建一个套接字,绑定,检测服务器
            {
        //sock
        //1.创建套接字
        socket_t sock = socket(AF_INET, SOCK_STREAM, 0);
        socket_call("create socket", sock);
    
        int opt = 1;
        socket_call("set socket options",
                setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)));
    
        //2.填充本地 sockaddr_in 结构体(设置本地的IP地址和端口)
        struct sockaddr_in local;
        local.sin_port = htons(_port);
        local.sin_family = AF_INET;
        local.sin_addr.s_addr = inet_addr(_ip);
    
        //3.bind()绑定
        socket_call("bind socket",
                bind(sock, (struct sockaddr*) &local, sizeof(local)));
        //4.listen()监听 检测服务器
        socket_call("listen socket", listen(sock, 256));
        return sock;    //这样的套接字返回
    }
    
    int main(int argc, char **argv) {
    
        socket_t listen_sock = startup("127.0.0.1", 8081);
    
        int epfd = epoll_create(256);
        struct epoll_event _ev;
        _ev.events = EPOLLIN;
        _ev.data.fd = listen_sock;
    
        epoll_ctl(epfd, EPOLL_CTL_ADD, listen_sock, &_ev);
    
        struct epoll_event revs[128];
    
        int timeout = -1;
        int num = 0;
        int done = 0;
        static int Con_Num = 0;
        static int Client_Write = 0;
        while (!done) {
            switch ((num = epoll_wait(epfd, revs, 128, timeout))) {
            case 0:
                printf("timeout
    ");
                break;
            case -1:
                socket_call("epoll_wait", num);
                break;
            default:
    
                for (int i = 0; i < num; i++) {
                    int rsock = revs[i].data.fd;
    //                printf("even type : %d
    ", revs[i].events);
                    if (rsock == listen_sock && (revs[i].events & EPOLLIN)) {
                        printf("Client Connect Times : %d
    ", ++Con_Num);
                        struct sockaddr_in peer;
                        socklen_t len = sizeof(peer);
                        int new_fd = accept(listen_sock, (struct sockaddr*) &peer,
                                &len);
                        if (new_fd > 0) {
                            printf("get a new client from %s:%d ,give fd : %d
    ",
                                    inet_ntoa(peer.sin_addr), ntohs(peer.sin_port),
                                    new_fd);
                            /*
                             * 设为非阻塞的意义是什么?
                             */
                            set_nonblock(new_fd);
                            _ev.events = EPOLLIN | EPOLLET;
                            _ev.data.fd = new_fd;
                            epoll_ctl(epfd, EPOLL_CTL_ADD, new_fd, &_ev);
                        }
    
                    } else {
                        if (revs[i].events & EPOLLIN) {
                            char buf[5];
                            ssize_t _s = read(rsock, buf, sizeof(buf) - 1);
                            if (_s > 0) {
                                printf("Client Write socket : %d times : %d
    ",
                                        rsock, ++Client_Write);
                                buf[_s] = '';
                                printf("Client Send buf :
    %s", buf);
                                while (true) {
                                    ssize_t _s = read(rsock, buf, sizeof(buf) - 1);
                                    if(_s<0){
                                        printf("%s
    ",strerror(errno));
                                        break;
                                    }
                                    buf[_s] = '';
                                    printf("%s", buf);
                                }
                                printf("
    ");
                            } else if (_s == 0) {
                                printf("Client :%d Close
    ", revs[i].data.fd);
                                epoll_ctl(epfd, EPOLL_CTL_DEL, rsock, NULL);
                                close(rsock);
                            }
    
                        }
                    }
                }
    
            }
        }
    
    }

    为什么需要将socketfd设为非阻塞呢?

    因为如果一个客户端连接的socketfd连接时,客户端写入数据,需要保证客户端的数据完全读取完毕,那么就嵌套一个循环一直read,如果阻塞会在读完数据后阻塞住,而非阻塞则会返回<0且errno变为EAGIN。

    少壮不识cpp,老大方知cpp可怕
  • 相关阅读:
    [Spring Unit Testing] Spring Unit Testing with a Java Context
    [Docker] Benefits of Multi-stage Builds
    [Mockito] Mock List interface
    Android自定义垂直滚动自动选择日期控件
    关于 MVC 字段 默认值
    Qt Creator编译时:cannot open file 'debugQtGuiEx.exe' File not found
    ListView开发笔记
    C/C++误区四:char c = getchar();
    ORACLE 中写入txt文本与从Txt文件中读入数据 修改表结构
    wikioi 1214 线段覆盖
  • 原文地址:https://www.cnblogs.com/Jacket-K/p/8377744.html
Copyright © 2011-2022 走看看