select函数实例代码

select函数简解:
    selct 称之为多路复用IO,使用它可以让程序阻塞在select上,而非实际IO函数上.

    int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
             nfds: fd_set描述符集中 {最大描述符+1}
          readfds: 读描述符集
         writefds: 写描述符集
        exceptfds: 异常描述符集
          timeout: 超时时间,1)当timeout为NULL时,select将阻塞到有读或写或异常描述符就绪才返回。
                            2)当timeout中tv_sec==0且tv_usec==0时,表示不等待,扫描一次马上返回。
                            3)当timeout中tv_sec!=0且tv_usec!=0时,表示在指定时间内没有就绪描述符就返回。函数返回0

注意:                         
1)正常情况下返回就绪描述符个数!
2)同时会将未就绪的描述符置零,所以select每次返回后我们都应将需用监听的描述符重新添加到描述符集中。
3)为了可移植,当设置了超时时间时也应当从新赋值。
4)使用select函数尽量不要与非系统IO混用


以下是对描述符集操作的函数:
    void FD_CLR(int fd, fd_set *set);
            从描述符集set中清除描述符fd

    int  FD_ISSET(int fd, fd_set *set);
            判断描述符fd 是否在描述符集set中,是,返回非0;否,返回0

    void FD_SET(int fd, fd_set *set);
            将描述符fd 添加到描述符集set中

    void FD_ZERO(fd_set *set);
            对描述符集进行清零,当我们新定义一个描述集时,最好使用此函数进行清零,
简单的服务器回射程序:

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

#include "common.h"

#define SERV_PORT   10086

typedef struct sockaddr SA;

int main(void)
{
    int                 listenfd, connfd;
    struct sockaddr_in  cliaddr, servaddr;
    socklen_t           clientlen;


    if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        err_quit("socket error");
    }

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family         =   AF_INET;
    servaddr.sin_port           =   htons(SERV_PORT);
    servaddr.sin_addr.s_addr    =   htonl(INADDR_ANY);

    if (bind(listenfd, (SA *)&servaddr, sizeof(servaddr)) < 0) {
        err_quit("bind error");
    }

    if (listen(listenfd, 5) < 0) {
        err_quit("listen error");
    }


    fd_set rfds, allfd;
    int maxfd, maxi = -1;

//method one:
    //int maxfd;
    //if ((maxfd = sysconf(_SC_OPEN_MAX)) < 0) {
    //  err_sys("sysconf error");
    //} 
    //
    //int clinet[maxfd];
//-----------------------------------------------------

//method two:
//在sys/select.h中定义了一个FD_SETSIZE其表示fd_set描述符总数。
    int client[FD_SETSIZE];
//-----------------------------------------------------

    int nready;
    int i, nread;
    int sockfd;
    char buf[MAXLINE];

    FD_ZERO(&allfd);
    FD_SET(listenfd, &allfd);
    maxfd = listenfd;

    for (i=0; i<FD_SETSIZE; ++i) {
        client[i] = -1;
    }


    for ( ; ; ) {

        rfds = allfd;

        nready = select(maxfd+1, &rfds, NULL, NULL, NULL);
        if (nready < 0) {
            err_quit("select error");
        }

        if (FD_ISSET(listenfd, &rfds)) {

#ifdef DEBUG
    printf("have descriptor....\n");
#endif

            clientlen = sizeof(cliaddr);
            connfd = accept(listenfd, (SA *)&cliaddr, &clientlen);
            if (connfd < 0) {
                err_quit("accept error");
            }

            for (i=0; i<FD_SETSIZE; ++i) {
                if (client[i] < 0) {
                    client[i] = connfd;
                    break;
                }
            }

            if (i == FD_SETSIZE) {
                err_quit("too many clients");
            }

            FD_SET(connfd, &allfd);

            if (connfd > maxfd) {
                maxfd = connfd;
            }

            if (i > maxi) {
                maxi = i;
            }

            if (--nready <= 0) {
                continue;
            }
        }

        for (i=0; i<=maxi; ++i) {
            if ((sockfd = client[i]) < 0) {
                continue;
            }

            if (FD_ISSET(sockfd, &rfds)) {

#ifdef  DEBUG
    printf("fd: %d\n", sockfd);
#endif

                if ((nread = read(sockfd, buf, MAXLINE)) == 0) {
                    close(sockfd);
                    FD_CLR(sockfd, &allfd);
                    client[i] = -1;
                } else {
                    if (write(sockfd, buf, nread) != nread) {
                        err_msg("fail to write...");
                    }
                }

                if (--nready <= 0) {
                    continue;
                }
            }
        }
    }

    return EXIT_SUCCESS;
}
posted @ 2017-08-17 16:28  gluo-dreamer  阅读(1743)  评论(0编辑  收藏  举报