Jump to content

select (Unix)

From Wikipedia, the free encyclopedia
This is an old revision of this page, as edited by Mazandar (talk | contribs) at 17:12, 15 October 2013. The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.

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. The select system call is similar to the poll facility introduced in UNIX System V and later operating systems.

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);
argument description
nfds the maximum file descriptor across all the sets, plus 1
readfds fd_set type holding the file descriptors to be checked for being ready to read, and on output indicates which file descriptors are ready to read. Can be NULL.
writefds fd_set type holding the file descriptors to be checked for being ready to write, and on output indicates which file descriptors are ready to write. Can be NULL.
errorfds fd_set type holding the file descriptors to be checked for error conditions pending, and on output indicates which file descriptors have error conditions pending. Can be NULL.
timeout structure of type struct timeval that specifies a maximum interval to wait for the selection to complete. If the timeout argument points to an object of type struct timeval whose members are 0, select() does not block. If the timeout argument is NULL, select() blocks until an event causes one of the masks to be returned with a valid (non-zero) value.

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.

Example

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>

#include <sys/select.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>

#define PORT "9421"

int main(int argc, char **argv)
{
	int sockfd, new, maxfd, on = 1, nready, i;

	struct addrinfo *res0, *res, hints;

	char buffer[BUFSIZ];

	fd_set master, readfds;

	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(-1 == (getaddrinfo(NULL, PORT, &hints, &res0)))
	{
		perror("getaddrinfo()");
		exit(EXIT_FAILURE);
	}

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

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

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

		break;

	}

	if(-1 == (listen(sockfd, 32)))
	{
		perror("listen()");
		exit(EXIT_FAILURE);
	}

	if(-1 == (fcntl(sockfd, F_SETFD, O_NONBLOCK)))
	{
		perror("fcntl()");
		exit(EXIT_FAILURE);
	}

	FD_ZERO(&master);
	FD_ZERO(&readfds);
	
	FD_SET(sockfd, &master);

	maxfd = sockfd;

	for(;;)
	{
		memcpy(&readfds, &master, sizeof(master));

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

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

				if(i == sockfd)
				{

					if(-1 == (new = accept(sockfd, NULL, NULL)))
					{
						if(EWOULDBLOCK != errno)
						{
							perror("accept()");
							exit(EXIT_FAILURE);
						}

						break;
					}
					
					else
					{

						if(-1 == (fcntl(new, F_SETFD, O_NONBLOCK)))
						{
							perror("fcntl()");
							exit(EXIT_FAILURE);
						}

						FD_SET(new, &master);

						if(maxfd < new)
							maxfd = new;
					}
				}

				else
				{

					nbytes = recv(i, buffer, sizeof(buffer), 0);
					{
						buffer[nbytes] = '\0';
						printf("%s", buffer);
					}

					if(nbytes <= 0)
					{
						if(EWOULDBLOCK != errno)
						{
							perror("recv()");
							exit(EXIT_FAILURE);
						}

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

				}
			}

		}


	}


	return 0;
}

See also