poll简介和源码

简介

  poll跟select功能类似,可以监听多个文件描述符(以下简称fd),当监听的fd就绪时就可以open进行业务处理了,因此需要死循环查询监听的文件描述符是否就绪,两者的最主要的区别是select监听的fd有上限,poll没有,本章主要简单描述一下poll。

函数原型:

  

#include <poll.h>

int poll(struct pollfd *fds, nfds_t nfds, int timeout);
fds通常是一个数组,nfds是它的数组大小,timeout超时时间单位是毫秒,poll会阻塞直到数组中的某些fd就绪时,返回它就绪fd的个数,当阻塞超时返回0,发生异常返回-1。作为web服务器,通常fds第0个元素监听的是web socket的fd,当第0个fd就绪时,就可以accpet获取到客服端的fd,然后放到第>0个位置,poll继续监听它。
struct pollfd {
               int   fd;         /* file descriptor */
               short events;     /* requested events */
               short revents;    /* returned events */
 };

 events是需要poll监听的事件,多个事件用 | 连接,revents是当监听的事件就绪时才有值。

例子

//提供socket服务相关函数
#include "socklib.c"
//业务逻辑处理
#include "handler.c"
#include <poll.h>
#include <signal.h>

#define NFDSSIZE 1024
//初始化poll监听的fd为-1,意味着没有需要监听的fd
void init_fd(struct pollfd *pfd);
//等待poll事件就绪并打开fd,处理业务逻辑
void wait_poll(struct pollfd *pfd, nfds_t nfds, int sock);
//收尾工作
void clearup(int signum);


int sock;
struct pollfd pfds[NFDSSIZE];

int main(int argc, char const *argv[])
{
    if (argc < 2)
    {
        exit_on_error("参数过少");
    }

    sock = make_socket_server(atoi(argv[1]));
    if (sock == -1)
    {
        oops("make_socket_server()");
    }
    //Ctrl+C时close sock fd
    signal(SIGINT, clearup);
    signal(SIGQUIT, clearup);

    for (size_t i = 0; i < NFDSSIZE; i++)
    {
        init_fd(&pfds[i]);
    }
    //第0个位置永远保存服务端sockfd,当sockfd就绪时就可以accpt了,第>0个位置存的客户端sockfd
    pfds[0].fd = sock;
    pfds[0].events = POLLIN | POLLRDNORM;
    pfds[0].revents = 0;
    while (1)
    {
        int retval = poll(pfds, NFDSSIZE, 5000);
        if (retval == -1)
        {
            perror("poll()");
        }
        else if (retval == 0)
        {
            printf("poll timeout!\n");
        }else {
            wait_poll(pfds, NFDSSIZE, sock);
        }
    }
    clearup(0);
    return EXIT_FAILURE;
}

void init_fd(struct pollfd *pfd)
{
    pfd->fd = -1;
    pfd->events = 0;
    pfd->revents = 0;
}
void wait_poll(struct pollfd *pfds, nfds_t nfds, int sock)
{
    int connect_fd;
    if (pfds[0].revents & POLLIN || pfds[0].revents & POLLRDNORM)
    {
        connect_fd = accept(sock, NULL, NULL);
        if (connect_fd == -1)
        {
            perror("accept()");
        }
        else
        {
            printf("accept connect fd:%d\n", connect_fd);
            
            size_t i;
            for (i = 1; i < NFDSSIZE; i++)
            {
                //找到空闲的元素,connect fd保存到这个位置
                if (pfds[i].fd == -1)
                {
                    pfds[i].fd = connect_fd;
                    pfds[i].events = POLLIN | POLLRDNORM;
                    pfds[i].revents = 0;
                    break;
                }
            }
            if (i == nfds)
            {
                printf("达到最大连接数!\n");
                close(connect_fd);
            }
            
        }
    }
    else
    {
        for (size_t i = 1; i < NFDSSIZE; i++)
        {
            //connect fd read ready!
            if (pfds[i].fd != -1 && (pfds[i].revents & POLLIN || pfds[i].revents & POLLRDNORM))
            {
                printf("connect fd %d available to read!\n", pfds[i].fd);
                handle_call(&pfds[i].fd);
                close(pfds[i].fd);
                init_fd(&pfds[i]);
            }
        }
    }
    
}

void clearup(int signum)
{
    close(sock);
    exit(1);
}

 

posted @ 2022-04-15 14:33  风的低吟  阅读(574)  评论(0编辑  收藏  举报