IO多路转接之poll函数详解

poll系统调用与select相似
select详解见博客:https://blog.csdn.net/smx_dd/article/details/85052852
也是在指定时间内轮询一定数量的文件描述符,来测试其中是否有就绪者。
poll原型:
int poll(struct pollfd* fds,nfds_t nfds,int timeout);
fds:是一个pollfd结构类型的数组,它指定我们感兴趣的文件描述符上发生的可读、可写、异常事件。
pollfd结构体定义如下:

struct pollfd {
 int fd; /* file descriptor */
 short events; /* requested events */
 short revents; /* returned events */
};

pollfd结构包含3个部分:fd为文件描述符、events为监听的事件集合、revents为返回的事件集合
events和revents取值:
poll事件类型
nfds:指定被监听的fds事件集合大小
nfds_t定义如下:

typedef unsigned long int nfds_t;

timeout:超时时间,和select类似,单位为毫秒。
返回值:返回值小于0说明出错,等于0说明超时,大于0表示poll由于监听描述符就绪而返回。

在网络编程中,socket可读就绪情况如下:
1.客户端连接到来,监听socket可读。
2.客户端数据到来,客户端socket可读。

poll系统调用优点:
1.pollfd结构包含了要监视的event和发⽣的event,不再使⽤select“参数-值”传递的⽅式. 接⼝使⽤⽐select更⽅便.
2.poll并没有最⼤数量限制 (但是数量过⼤后性能也是会下降).
缺点:
1.和select一样,需要轮询pollfd来获取就绪描述符。
2.每次调⽤poll都需要把⼤量的pollfd结构从⽤户态拷⻉到内核中.

使用poll函数实现tcp服务器,打破传统单线程不能处理多个客户端请求:

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

int main(int argc,char *argv[])
{
    if(argc!=2)
    {
        printf("Usage: ./name port!\n");
    }
    int i,j;
    struct sockaddr_in server_addr;
    socklen_t len=sizeof(server_addr);
    server_addr.sin_family=AF_INET;
    server_addr.sin_port=htons(atoi(argv[1]));
    server_addr.sin_addr.s_addr=INADDR_ANY;
    int listen_fd=socket(AF_INET,SOCK_STREAM,0);
    if(listen_fd<0)
    {
        perror("create socket error!");
        return 1;
    }
    int ret=bind(listen_fd,(struct sockaddr*)&server_addr,len);
    if(ret<0)
    {
        perror("bind error!");
        return 1;
    }
    ret=listen(listen_fd,5);
    if(listen_fd<0)
    {
        perror("listen error!");
        return 1;
    }
    struct pollfd fd_list[1024];
    for(i=0;i<1024;i++)
    {
        fd_list[i].fd=-1;
        fd_list[i].events=0;
        fd_list[i].revents=0;
    }
    for(i=0;i<1024;i++)
    {
        if(fd_list[i].fd==-1)
        {
            fd_list[i].fd=listen_fd;
            fd_list[i].events=POLLIN;
            break;
        }
    }
    while(1)
    {
        ret=poll(fd_list,1024,2000);
        if(ret<0)
        {
            perror("poll error!");
            continue;
        }
        else if(ret==0)
        {
            printf("time out!\n");
            continue;
        }
        for(i=0;i<1024;i++)
        {
            if(fd_list[i].fd==-1)
            {
                continue;
            }
            if(fd_list[i].revents!=POLLIN)
            {
                continue;
            }
            if(fd_list[i].fd==listen_fd)
            {
                struct sockaddr_in client_addr;
                int new_fd=accept(listen_fd,(struct sockaddr*)&client_addr,&len);
                if(new_fd<0)
                {
                    perror("accept error!");
                    continue;
                }
                printf("a new client connected!");
                for(j=0;j<1024;j++)
                {
                    if(fd_list[j].fd==-1)
                    {
                        fd_list[j].fd=new_fd;
                        fd_list[j].events=POLLIN;
                        break;
                    }
                }
            }
            else
            {
                char buff[1024]={0};
                int rlen=recv(fd_list[i].fd,buff,1023,0);
                if(rlen<0)
                {
                    perror("recv error!");
                    continue;
                }
                else if(rlen==0)
                {
                    printf("client close!\n");
                    close(fd_list[i].fd);
                    fd_list[i].fd=-1;
                    continue;
                }
                printf("client: %s\n",buff);
            }
        }
    }
    close(listen_fd);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值