LINUX下poll函数用法

LINUX下poll函数用法


一、函数介绍

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

第一个参数为一个结构体数组,它存储需要监听的文件描述符和需要监听的事件。
结构体定义如下

struct pollfd {
       int fd; /* 待监听的文件描述符*/
       short events; /* 待见听的事件*/
       short revents; /* 返回事件的结果*/
};

events取值POLLIN、POLLOUT、POLLERR分别代表传入传出和错误。
revents可在定义时传入0,满足事件后,回返回POLLIN、POLLOUT、POLLERR。

第二个参数nfds:监听数组的实际有效个数。
第三个参数timeout:超时时长,
传入-1则阻塞等待。
传入0则立即返回,不阻塞进程。
传入>0则等待指定时间,单位为毫秒。
返回值:返回满足对应监听时间的总个数。

二、使用

1.

我写了一个简单的例子,在这个例子中我只监听了套接字的read请求,并将收到的数据进行回显。
文中大写字母开头的函数为我自己重新封装的函数,用法与原来相同并自动检查返回值。我将它放到另一个文件中。

#include "ddd.h"
#include <poll.h>
#define _GNU_SOURCE         /* See feature_test_macros(7) */
#include <signal.h>
int main()
{
    struct pollfd fdds[1024];  //定义待监听的文件描述符集合
    char buf[100];              //定义缓冲区
     socklen_t ss_len;
    struct sockaddr_in addr,ss;         
    int socket_fd,r_fd;
       socket_fd=Socket(AF_INET,SOCK_STREAM,0);
    addr.sin_family=AF_INET;
    addr.sin_addr.s_addr=htonl(INADDR_ANY);
    addr.sin_port=htons(4500);
    int e;
    int opt=1;
    setsockopt(socket_fd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
    //设置套接字为复用
    Bind(socket_fd, (struct sockaddr *)&addr, sizeof(addr));
    //绑定套接字
    if ((e=listen(socket_fd,128))==-1)
    {
        my_error("socket_fd",__LINE__);
    }
    int maxfd=0;//最大可用套接字的下标
    int selet_ret;
    maxfd=0;
    fdds[0].fd=socket_fd;//先将监听用的套接字传入集合中
    fdds[0].events=POLLIN;
    int j=0;
    for (j=1;j<1024;j++)
    {
        fdds[j].fd=-1;  //初始化套接字集合为空
    }
    int i;
    while(1)
    {
        selet_ret=poll(fdds,maxfd+1,-1); //使用poll监测多个等待事件
        if(selet_ret<0)
        {
            my_error("select",__LINE__);
            exit(1);
        }
        if (fdds[0].revents&POLLIN)  //监听是否有connect请求
        {
            ss_len=sizeof(ss);
            r_fd=accept(socket_fd,(struct sockaddr *)&ss,&ss_len);
            printf("ip:%s  port: %u\n",inet_ntoa(ss.sin_addr),ntohs(ss.sin_port));
            for (i=1;i<1024;i++) //找到最小的未使用的文件描述符并break;
            {
                if (fdds[i].fd<0) 
                {
                    fdds[i].fd=r_fd;
                    fdds[i].events=POLLIN;
                    break;
                }
            }
            if (r_fd>maxfd)
            {
                maxfd=r_fd;
            }
            if (--selet_ret<0) //若事件只有connect则回到poll处等待其他事件
            {
                continue;
            }
        }
        for(i=1;i<=maxfd;i++) //逐个查看哪个套接字有请求并处理
        {
            if (fdds[i].fd==-1)
            {
                continue;
            }
            if (fdds[i].revents&POLLIN)
            {
                int ret;
                ret=read(fdds[i].fd,buf,sizeof(buf));
                if (ret==0)
                {
                    close(i);
                    fdds[i].fd=-1;
                }
                else if (ret<0)
                {
                    my_error("read",__LINE__);
                }
                write(fdds[i].fd,buf,ret);
                write(STDOUT_FILENO,buf,ret);
            }
            if (--selet_ret<=0)
            {
                break;
            }

        }

    }
    close(socket_fd);
    return 0;
}
#ifndef _DDD_H_
#define _DDD_H_
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include<errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <sys/time.h>
void my_error(const char *error_string, int line); //错误处理函数
int Socket(int domain, int type, int protocol);
int Connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
int Bind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen);
int Accept(int s, struct sockaddr *addr, socklen_t *addrlen);
#endif
#include "ddd.h"
void my_error(const char *error_string, int line) //错误处理函数
{
    fprintf(stderr, "line:%d",line);
    perror(error_string);
    exit(1);
}
int Socket(int domain, int type, int protocol)
{
    int ret;
    ret = socket(domain, type, protocol);
    if (ret < 0)
    {
        my_error("socket",__LINE__);
        exit(1);
    }
    else return ret;
}
int Connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen)
{
    int ret =connect(sockfd,addr,addrlen);
    if (ret<0)
    {
        my_error("connect",__LINE__);
        exit(1);
    }
    else return 0;
}
int Bind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen)
{
    int ret=bind(sockfd,my_addr,addrlen);
    if (ret < 0)
    {
        my_error("bind",__LINE__);
        exit(1);
    }
}
int Accept(int s, struct sockaddr *addr, socklen_t *addrlen)
{
    int ret=accept(s,addr,addrlen);
    if (ret < 0)
    {
        my_error("accpet",__LINE__);
        exit(1);
    }
    else return ret;
}

  • 5
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux中,poll函数用于等待一个或多个文件描述符的I/O事件。与select和epoll相比,poll函数的不足之处在于效率较低,因为它需要遍历整个文件描述符集合。 在Linux中使用poll函数时,有一个线程资源的限制,即可以同时处理的线程数量有限。这是因为操作系统对每个进程或线程的资源分配是有一定限制的,包括线程栈大小、文件描述符数量、内存使用等等。 当使用poll函数时,每个线程都会占用一定的系统资源。如果创建过多的线程并同时调用poll函数,可能会导致系统资源不足的问题,比如资源耗尽、内存溢出等。因此,需要合理控制线程的数量,以避免资源限制的问题。 为了克服线程资源限制,可以采取以下几种方法: 1. 使用线程池:通过线程池管理线程,在需要使用poll函数的时候从线程池中获取一个线程,并在使用完后将其放回线程池中,避免创建过多的线程,从而降低系统资源的消耗。 2. 调整系统资源限制:通过修改系统配置文件或运行时参数,增加线程栈大小、文件描述符数量等资源限制值,从而扩大系统能够处理的线程数量。但是需要注意,调整这些系统资源限制可能会影响其他方面的性能。 3. 使用更高效的I/O模型:如果对响应时间有严格要求,并且在处理大量并发连接的情况下,考虑使用更高效的I/O模型,如epoll等,以提高系统的性能和资源利用率。 总之,在使用linuxpoll函数时,需要注意线程资源的限制,合理控制线程数量,防止资源耗尽等问题的发生。通过合理的线程管理和配置系统资源限制,可以提高应用程序的性能和可扩展性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值