C SELECT: синтаксис и примеры использования
С select в языке программирования C можно реализовать многопоточность и выполнение одновременно нескольких задач без блокировки других потоков исполнения.
Функция select позволяет проверять состояние одного или нескольких файловых дескрипторов на предмет готовности к чтению, записи или ошибке. Она блокирует выполнение программы до тех пор, пока не произойдет событие, ожидаемое в функции select или не выйдет таймаут.
Пример использования select для чтения из нескольких сокетов:
#include
#include
#include
#include
#define MAX_LINE 1024
int main(int argc, char **argv) {
int sockfd[3];
struct sockaddr_in servaddr[3];
socklen_t len = sizeof(servaddr[0]);
char buf[MAX_LINE];
int maxfd, nready, n;
// создание трех сокетов и подключение к серверам
sockfd[0] = socket(AF_INET, SOCK_STREAM, 0);
sockfd[1] = socket(AF_INET, SOCK_STREAM, 0);
sockfd[2] = socket(AF_INET, SOCK_STREAM, 0);
// установка параметров серверов
bzero(&servaddr[0], len);
servaddr[0].sin_family = AF_INET;
servaddr[0].sin_port = htons(10000);
inet_pton(AF_INET, "127.0.0.1", &servaddr[0].sin_addr);
bzero(&servaddr[1], len);
servaddr[1].sin_family = AF_INET;
servaddr[1].sin_port = htons(20000);
inet_pton(AF_INET, "127.0.0.1", &servaddr[1].sin_addr);
bzero(&servaddr[2], len);
servaddr[2].sin_family = AF_INET;
servaddr[2].sin_port = htons(30000);
inet_pton(AF_INET, "127.0.0.1", &servaddr[2].sin_addr);
// подключение к серверам
connect(sockfd[0], (struct sockaddr *) &servaddr[0], len);
connect(sockfd[1], (struct sockaddr *) &servaddr[1], len);
connect(sockfd[2], (struct sockaddr *) &servaddr[2], len);
// определение максимального дескриптора для вызова select
maxfd = sockfd[2];
// цикл приема сообщений от серверов
while(1) {
fd_set rset;
FD_ZERO(&rset);
// добавление сокетов в множество наблюдения
FD_SET(sockfd[0], &rset);
FD_SET(sockfd[1], &rset);
FD_SET(sockfd[2], &rset);
// вызов select и ожидание наступления готовности к чтению
nready = select(maxfd + 1, &rset, NULL, NULL, NULL);
if (FD_ISSET(sockfd[0], &rset)) {
if ((n = read(sockfd[0], buf, MAX_LINE)) == 0) {
printf("server[0] закрыл соединение\n");
close(sockfd[0]);
FD_CLR(sockfd[0], &rset);
} else {
buf[n] = '\0';
printf("server[0]: %s\n", buf);
}
}
if (FD_ISSET(sockfd[1], &rset)) {
if ((n = read(sockfd[1], buf, MAX_LINE)) == 0) {
printf("server[1] закрыл соединение\n");
close(sockfd[1]);
FD_CLR(sockfd[1], &rset);
} else {
buf[n] = '\0';
printf("server[1]: %s\n", buf);
}
}
if (FD_ISSET(sockfd[2], &rset)) {
if ((n = read(sockfd[2], buf, MAX_LINE)) == 0) {
printf("server[2] закрыл соединение\n");
close(sockfd[2]);
FD_CLR(sockfd[2], &rset);
} else {
buf[n] = '\0';
printf("server[2]: %s\n", buf);
}
}
}
return 0;
}
В этом примере программа создает три сокета и подключается к серверам с адресами 127.0.0.1 и портами 10000, 20000 и 30000. Затем в цикле она вызывает функцию select и ожидает наступления готовности сокетов к чтению. Если сокет готов к чтению, программа читает из него данные и выводит на экран. Если сервер закрыл сокет, программа закрывает соединение и удаляет дескриптор из множества наблюдения.