I/O复用——poll

目录

poll API

poll 编程

poll 总结


poll API

poll系统调用 和 select类似,也是在指定时间内轮询一定数量的文件描述符,以测试其中是否有就绪事件。 

poll的原型如下:

头文件:#include <poll.h>

int poll (struct pollfd * fds ,nfds_t nfds ,int timeout)

fds参数:pollfd结构类型的数组,它指定所有我们感兴趣的文件描述上发生的可读、可写和异常等事件。

pollfd结构体的定义如下:

struct pollfd
{
  int fd;    //文件描述符 
  short events;    //注册的事件
  short revents;   //实际发生的事件,由内核填充
};
  • 成员fd:指定文件描述符;
  • 成员events:告诉poll监听fd上的那些事件,它是一系列事件的按位或;
  • 成员revents:由内核修改,通知应用程序fd上实际发生了那些事件;

poll支持的事件如下表所示:

事件描述是否可作为输入是否可作为输出
POLLWRNORM普通数据可写
POLLWRBAND

优先数据可写

POLLRDHUPtcp连接被对方关闭,或者对方关闭了写操作,它由GNU引入
POLLERR错误
POLLHUP挂起。比如管道的写端被关闭后,读端描述符上将收到POLLHUP事件
POLLNVAL文件描述符没有打开
POLLIN数据(包括普通数据和优先数据)可读
POLLRDNORM普通数据可读
POLLRDBAND  优先级带数据可读(Linux不支持)
POLPRI高级优先数据可读,比如tcp带外数据
POLLOUT数据(包括普通数据和优先数据)可写

 

参数nfds:指定被监听事件集合fds的大小,其类型nfds_t的定义如下:

typedef unsigned long int nfds_t;

参数timeout:指定poll的超时值,单位是毫秒。当timeout为-1时,poll调用将阻塞,直到某个事件发生;当timeout为0时,poll调用将立即返回;

poll 编程

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <poll.h>
#include <sys/time.h>

#define FD_MAX    10
int socket_init();
void fds_init(struct pollfd fds[])
{
    for( int i = 0; i < FD_MAX; i++ )
    {
        fds[i].fd = -1;
        fds[i].events = 0;
        fds[i].revents = 0;
    }
}

void fds_add( struct pollfd fds[], int fd)
{
    for( int  i = 0; i < FD_MAX; i++ )
    {
        if ( fds[i].fd == -1 )
        {
            fds[i].fd = fd;
            fds[i].events = POLLIN;//注册读事件
            fds[i].revents = 0;
            break;
        }
    }
}

void fds_del( struct pollfd fds[], int fd)
{
    for( int i = 0; i < FD_MAX; i++ )
    {
        if ( fds[i].fd == fd )
        {
            fds[i].fd = -1;
            fds[i].events = 0;
            fds[i].revents = 0;
            break;
        }
    }
}
int main()
{
    int sockfd = socket_init();
    if( sockfd == -1 )
    {
        printf("socket init failed\n");
        exit(1);
    }

    struct pollfd fds[FD_MAX];
    fds_init(fds);
    fds_add(fds,sockfd);

    while( 1 )
    {
        int n = poll(fds,FD_MAX,5000);
        if ( n < 0 )
        {
            printf("poll err\n");
        }
        else if ( n == 0 )
        {
            printf("time out\n");
        }
        else
        {
            for( int i = 0; i < FD_MAX; i++ )
            {
                if ( fds[i].fd == -1  )
                {
                    continue;
                }

                if ( fds[i].revents & POLLIN )
                {
                    if ( fds[i].fd == sockfd )
                    {
                        struct sockaddr_in caddr;
                        int len = sizeof(caddr);
                        int c = accept(sockfd,(struct sockaddr*)&caddr,&len);
                        if ( c < 0 )
                        {
                            continue;
                        }
                        printf("accept c=%d\n",c);
                        fds_add(fds,c);//新的连接套接字添加到fds,-》poll
                    }
                    else
                    {
                        char buff[128] = {0};
                        int num = recv(fds[i].fd,buff,127,0);
                        if ( num <= 0 )
                        {
                            close(fds[i].fd);
                            fds_del(fds,fds[i].fd);
                            printf("client close\n");
                        }
                        else
                        {
                            printf("recv(%d):%s\n",fds[i].fd,buff);
                            send(fds[i].fd,"ok",2,0);
                        }
                    }
                }
                
            }
        }
    }
}
int socket_init()
{
    int sockfd = socket(AF_INET,SOCK_STREAM,0);
    if( sockfd == -1 )
    {
        return -1;
    }
    
    struct sockaddr_in saddr;
    memset(&saddr,0,sizeof(saddr));
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(6000);
    saddr.sin_addr.s_addr = inet_addr("127.0.0.1");

    int res = bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
    if ( res == -1 )
    {
        return -1;
    }

    res = listen(sockfd,5);
    if ( res == -1 )
    {
        return -1;
    }

    return sockfd;
}

poll 总结

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值