Top Qs
Timeline
Chat
Perspective

Select (Unix)

System call to examine the status of file descriptors of open input/output channels From Wikipedia, the free encyclopedia

Remove ads

select is a system call and application programming interface (API) in Unix-like and POSIX-compliant operating systems for examining the status of file descriptors of open input/output channels.[1] The select system call is similar to the poll facility introduced in UNIX System V and later operating systems. However, with the c10k problem, both select and poll have been superseded by the likes of kqueue, epoll, /dev/poll and I/O completion ports.[2]

One common use of select outside of its stated use of waiting on filehandles is to implement a portable sub-second sleep. This can be achieved by passing NULL for all three fd_set arguments, and the duration of the desired sleep as the timeout argument.

In the C programming language, the select system call is declared in the header file sys/select.h or unistd.h, and has the following syntax:

int select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* errorfds, struct timeval* timeout);
More information Argument, Description ...

fd_set type arguments may be manipulated with four utility macros: FD_SET(), FD_CLR(), FD_ZERO(), and FD_ISSET().

Select returns the total number of bits set in readfds, writefds and errorfds, or zero if the timeout expired, and -1 on error.

The sets of file descriptor used in select are finite in size, depending on the operating system. The newer system call poll provides a more flexible solution.

Remove ads

Example

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <err.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/types.h>
#include <unistd.h>

#define PORT "9421"

void die(const char* msg) {
    perror(msg);
    exit(EXIT_FAILURE);
}

typedef struct addrinfo AddressInfo;

int main(int argc, char* argv[]) {
    int sockfd;
    int newval;
    int maxfd;
    int on = 1;
    int nready;

    AddressInfo* res0;
    AddressInfo* res; 
    AddressInfo* hints;

    char buffer[BUFSIZ];

    fd_set master;
    fd_set readfds;

    int error;

    ssize_t nbytes;

    (void)memset(&hints, '\0', sizeof(struct addrinfo));

    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
    hints.ai_flags = AI_PASSIVE;

    if ((error = getaddrinfo(NULL, PORT, &hints, &res0))) {
        errx(EXIT_FAILURE, "%s", gai_strerror(error));
    }

    for (res = res0; res; res = res->ai_next) {
        if ((sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) == -1) {
            perror("socket()");
            continue;
        }

        if ((setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof(int))) == -1) {
            perror("setsockopt()");
            continue;
        }

        if ((bind(sockfd, res->ai_addr, res->ai_addrlen)) == -1) {
            perror("bind()");
            continue;
        }

        break;
    }

    if (sockfd == -1) {
        return EXIT_FAILURE;
    }

    freeaddrinfo(res0);

    if ((listen(sockfd, 32)) == -1) {
        die("listen()");
    }

    if ((fcntl(sockfd, F_SETFD, O_NONBLOCK)) == -1) {
        die("fcntl()");
    }

    FD_ZERO(&master);
    FD_ZERO(&readfds);

    FD_SET(sockfd, &master);

    maxfd = sockfd;

    while (true) {
        memcpy(&readfds, &master, sizeof(master));

        printf("running select()\n");

        if ((nready = select(maxfd+1, &readfds, NULL, NULL, NULL)) == -1) {
            die("select()");
        }

        printf("Number of ready descriptor: %d\n", nready);

        for (int i = 0; i <= maxfd && nready > 0; i++) {
            if (FD_ISSET(i, &readfds)) {
                nready--;

                if (i == sockfd) {
                    printf("Trying to accept() new connection(s)\n");

                    if ((newval = accept(sockfd, NULL, NULL)) == -1) {
                        if (EWOULDBLOCK != errno) {
                            die("accept()");
                        }

                        break;
                    } else {

                        if ((fcntl(newval, F_SETFD, O_NONBLOCK)) == -1) {
                            die("fcntl()");
                        }

                        FD_SET(newval, &master);

                        if (maxfd < newval) {
                            maxfd = newval;
                        }
                    }
                } else {
                    printf("recv() data from one of descriptors(s)\n");

                    nbytes = recv(i, buffer, sizeof(buffer), 0);
                    if (nbytes <= 0) {
                        if (EWOULDBLOCK != errno) {
                            die("recv()");
                        }

                        break;
                    }

                    buffer[nbytes] = '\0';
                    printf("%s", buffer);

                    printf("%zi bytes received.\n", nbytes);

                    close(i);
                    FD_CLR(i, &master);

                }
            }

        }

    }
    return 0;
}
Remove ads

See also

References

Loading related searches...

Wikiwand - on

Seamless Wikipedia browsing. On steroids.

Remove ads