Select (Unix)
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);
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 <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;
}
See alsoReferences
External links
|