select的限制与poll的使用

select的限制

select的并发数受到两个限制:1.一个进程能打开的最大描述符数量;2.select中fd_set集合容量的限制(FD_SETSIZE)

关于进程的最大描述符数量:
ulimit -n:查看一个进程能打开的最大描述符数量
ulimit -n 2048:将最大描述符数量更改为2048,其它数量也可以,需root权限

//最大描述符测试,如果数量是1024的情况下,不出意外程序会在i=1021时达到最大值,因为0,1,2被标准输入输出占有
int main(int argc,char *argv[]){
    int i=0;
    while(1){
        int sockfd;
        struct sockaddr_in servaddr;
        char buf[1024];
 
        if((sockfd=socket(PF_INET,SOCK_STREAM,0)) < 0){
            printf("%d
",i);
            err_quit("socket");
        }
 
        bzero(&servaddr,sizeof(servaddr));
        servaddr.sin_family=AF_INET;
        servaddr.sin_addr.s_addr=inet_addr("127.0.0.1");
        servaddr.sin_port=htons(5566);
 
        int ret;
        ret=connect_timeout(sockfd,&servaddr,5);
        if(ret == -1 && errno == ETIMEDOUT){
            puts("timeout ...");
            return 1;
        }else if(ret == -1)
            err_quit("connect");
 
        bzero(buf,sizeof(buf));
        printf("%d
",++i);
    }
}

关于FD_SETSIZE的最大集合:
上面的客户端同时开三个连接上一版的服务器,过一会儿就能看到效果,程序会在accept返回-1

poll的使用

#include <unistd.h>
#include <poll.h>
#include <netdb.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
 
#define MAX(a,b) a>b?a:b;
 
void err_quit(const char *s){
    perror(s);
    exit(1);
}
 
ssize_t readn(int fd,void *buff,size_t count){
    char *buffp;
    ssize_t nread;
    size_t nleft;
 
    buffp=(char *)buff;
    nleft=count;
    while(nleft > 0){
        if((nread = read(fd,buffp,nleft)) < 0){
            if(errno == EINTR)
                continue;
            else
                return -1;
        }else if(nread == 0)
            break;
        nleft -= nread;
        buffp += nread;
    }
    return count-nleft;
}
 
ssize_t writen(int fd,const void *buff,size_t n){
    size_t nleft;
    ssize_t nwritten;
    const char *ptr;
 
    ptr=buff;
    nleft=n;
    while(nleft > 0){
        if((nwritten=write(fd,ptr,nleft)) < 0){
            if(nwritten < 0 && errno == EINTR)
                continue;
            else
                return -1;
        }else if(nwritten == 0)
            break;
        nleft -= nwritten;
        ptr += nwritten;
    }
    return n-nleft;
}
 
ssize_t recv_peek(int fd,void *buf,size_t len){
    ssize_t ret;
    while(1){
        ret=recv(fd,buf,len,MSG_PEEK);
        if(ret == -1 && errno == EINTR)
            continue;
        return ret;
    }
}
 
ssize_t readline(int fd,void *buf,size_t maxline){
    ssize_t ret;
    size_t nread;
    size_t nleft;
    char *bufp;
 
    bufp=buf;
    nleft=maxline;
    while(1){
        ret=recv_peek(fd,buf,nleft);
        if(ret < 0)
            return ret;
        else if(ret == 0)
            return ret;
 
        nread=ret;
        int i;
        for(i=0;i<nread;i++){
            if(bufp[i] == '
'){
                ret=readn(fd,bufp,i+1);
                if(ret != i+1)
                    err_quit("readn");
 
                return ret;
            }
        }
 
        if(nread > nleft)
            err_quit("readn");
 
        nleft -= nread;
        ret=readn(fd,bufp,nread);
        if(ret != nread)
            err_quit("readn");
 
        bufp += nread;
    }
 
    return -1;
}
 
int accept_timeout(int fd,struct sockaddr_in *addr,unsigned int wait_seconds){
    int ret;
    socklen_t addrlen=sizeof(struct sockaddr_in);
 
    if(wait_seconds > 0){
        fd_set accept_fdset;
        struct timeval timeout;
 
        FD_ZERO(&accept_fdset);
        FD_SET(fd,&accept_fdset);
 
        timeout.tv_usec=0;
        timeout.tv_sec=wait_seconds;
        do{
            ret=select(fd+1,&accept_fdset,NULL,NULL,&timeout);
        }while(ret < 0 && errno == EINTR);
 
        if(ret == 0){
            errno = ETIMEDOUT;
            return -1;
        }else if(ret == -1)
            return -1;
    }
 
    if(addr != NULL)
        ret=accept(fd,(struct sockaddr *)addr,&addrlen);
    else
        ret=accept(fd,NULL,NULL);
    if(ret == -1)
        err_quit("accept");
 
    return ret;
}
 
int main(int argc,char *argv[]){
    int i,maxi,tmpfd,sockfd,connfd;
    socklen_t len;
    struct sockaddr_in addr,client;
    int nready;
    struct pollfd clientfd[2048];
    ssize_t n;
    char buf[1024];
 
    if((sockfd=socket(PF_INET,SOCK_STREAM,0)) < 0)
        err_quit("sockfd");
 
    bzero(&addr,sizeof(addr));
    addr.sin_family=AF_INET;
    addr.sin_addr.s_addr=htonl(INADDR_ANY);
    addr.sin_port=htons(5566);
 
    int on=1;
    if(setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)) <0)
        err_quit("setsockopt");
 
    if(bind(sockfd,(struct sockaddr *)&addr,sizeof(addr))<0)
        err_quit("bind");
 
    if(listen(sockfd,10)<0)
        err_quit("listen");
 
    maxi=0;
    for(i=0;i<2048;i++)
        clientfd[i].fd=-1;
 
    clientfd[0].fd=sockfd;
    clientfd[0].events= POLLIN;
    while(1){
        nready=poll(clientfd,maxi+1,-1);
 
        if(nready == -1){
            if(errno == EINTR)
                continue;
            else
                err_quit("select");
        }
 
        if(clientfd[0].revents & POLLIN){
            len=sizeof(client);
            connfd=accept(sockfd,(struct sockaddr *)&client,&len);
            if(connfd < 0)
                err_quit("accept");
 
            for(i=0;i<2048;i++){
                if(clientfd[i].fd < 0){
                    clientfd[i].fd=connfd;
                    clientfd[i].events=POLLIN;
                    if(i > maxi)
                        maxi=i;
                    break;
                }
            }
            if(i == 2048)
                err_quit("too many clients");
 
            if(--nready <= 0)
                continue;
        }
 
 
        for(i=1;i<=maxi;i++){
            if((tmpfd=clientfd[i].fd) < 0)
                continue;
            if(clientfd[i].revents & POLLIN){
                bzero(buf,sizeof(buf));
                if((n=readline(tmpfd,buf,sizeof(buf))) == 0){
                    close(tmpfd);
                    clientfd[i].fd=-1;
                }
                write(STDOUT_FILENO,buf,n);
                writen(tmpfd,buf,n);
 
                if(--nready <= 0)
                    break;
            }
        }
    }
}
原文地址:https://www.cnblogs.com/cfans1993/p/6131892.html