• poll


    poll相关的api:

    // 把所有的文件描述符放到pollfd数组里面,每调用一次poll,需要对所有的pollfd数组做一次遍历。
    // "fds"参数是struct pollfd数组
    extern int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout);
    
    /* pollfd封装了感兴趣的事件和实际发生的事件 */
    /* Data structure describing a polling request.  */
    struct pollfd
    {
        int fd;            /* File descriptor to poll.  */
        short int events;        /* Types of events poller cares about.  */
        short int revents;        /* Types of events that actually occurred.  */
    };
    
    /* Type used for the number of file descriptors.  */
    typedef unsigned long int nfds_t;

    网上搜到的代码示例:

    #include <stdio.h>
    #include <fcntl.h>
    #include <netinet/in.h>
    #include <poll.h>
    #include <errno.h>
    
    #define MAXLINE 512
    #define OPEN_MAX 1024
    #define SA struct sockaddr
    
    int main() {
        int listenfd, connfd, sockfd, i, maxi;
        int nready;
        socklen_t clilen;
        ssize_t n;
        char buf[MAXLINE];
        //我们关心的文件描述符
        struct pollfd client[OPEN_MAX];
        struct sockaddr_in servaddr, cliaddr;
        //创建监听套接字
        if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
            printf("socket() error!");
            exit(0);
        }
        //对协议地址进行清零
        bzero(&servaddr, sizeof(servaddr));
        //设置为 IPv4 or IPv6
        servaddr.sin_family = AF_INET;
        //绑定本地端口号
        servaddr.sin_port = htons(9999);
        //任何一个 IP 地址,让内核自行选择
        servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
        //绑定套接口到本地协议地址
        if (bind(listenfd, (SA *) &servaddr, sizeof(servaddr)) < 0) {
            printf("bind() error!");
            exit(0);
        }
        //服务器开始监听
        if (listen(listenfd, 5) < 0) {
            printf("listen() error!");
            exit(0);
        }
        //监听套接字
        client[0].fd = listenfd;
        client[0].events = POLLRDNORM; //读事件
        for (i = 1; i < OPEN_MAX; ++i) {
            client[i].fd = -1;
        }
        maxi = 0;
    
        for (;;) {
            //poll函数的返回值:发生了事件的文件描述符的个数, 它并没有指出哪几个描述符发生了事件.
            //timeout参数为-1,poll阻塞直到描述符有事件发生
            nready = poll(client, maxi + 1, -1);
            //首先检查监听套接字,查看是否有新连接进来
            if (client[0].revents & POLLRDNORM) {
                clilen = sizeof(cliaddr);
                connfd = accept(listenfd, (SA *) &cliaddr, &clilen);
                if (connfd < 0) {
                    continue;
                }
                for (i = 1; i < OPEN_MAX; ++i) {
                    if (client[i].fd < 0) {
                        client[i].fd = connfd;
                        //printf does not work
                        fprintf(stdout, "accept a new client
    ");
                        break;
                    }
                }
                if (i == OPEN_MAX) {
                    fprintf(stdout, "too many clients");
                    exit(0);
                }
                client[i].events = POLLRDNORM;
                if (i > maxi) {
                    maxi = i;
                }
                if (--nready <= 0)    continue;
            }
            //然后检查连接套接字
            for (i = 1; i < OPEN_MAX; ++i) {
                if ((sockfd = client[i].fd) < 0) {
                    continue;
                }
                if (client[i].revents & POLLRDNORM | POLLERR) {
                    if ((n = read(sockfd, buf, MAXLINE)) < 0) {
                        if (errno == ECONNRESET) {
                            close(sockfd);
                            printf("1.close fd %d!
    ", client[i].fd);
                            client[i].fd = -1;
                        } else {
                            printf("read error!
    ");
                        }
                    } else if (n == 0) {
                        close(sockfd);
                        printf("2.close fd %d!
    ", client[i].fd);
                        client[i].fd = -1;
                    } else {
                        write(sockfd, buf, n);
                    }
                    if (--nready <= 0) break;
                }
            }
        }
    }

    使用nc命令作为客户端进行交互:nc localhost 9999

    从这个例子中,能看出poll的缺点。

    poll函数返回发生了事件的描述符个数,我们需要遍历所有的描述符,才能知道具体描述符哪些真实发生了事件。

  • 相关阅读:
    (Android)如何将一个高复用性项目供其他项目使用(jar导出,导入,Is Library)(转)
    Android:SlidingMenu 使用详解 .
    单项链表和双向链表的区别
    LinkedList 与 ArrayList的区别
    完全二叉树与满二叉树
    C/C++之回调函数
    C++静态库与动态库
    C++项目中的extern "C" {}
    C++强大背后
    移动优先与响应式Web设计
  • 原文地址:https://www.cnblogs.com/allenwas3/p/7904305.html
Copyright © 2020-2023  润新知