выбрать (Unix)
Эта статья нуждается в дополнительных цитатах для проверки . ( март 2020 г. ) |
select — это интерфейс системного вызова и прикладного программирования (API) в Unix-подобных и POSIX -совместимых операционных системах для проверки состояния файловых дескрипторов открытых каналов ввода-вывода. [1] Системный вызов select аналогичен вызову Функция опроса , представленная в UNIX System V и более поздних операционных системах. Однако из-за проблемы c10k и select, и poll были заменены такими, как kqueue , epoll , /dev/poll и порты завершения ввода-вывода . [2]
Одним из распространенных вариантов использования select, помимо заявленного использования ожидания дескрипторов файлов, является реализация переносимого режима ожидания менее секунды . Этого можно добиться, передав NULL для всех трех аргументов fd_set и продолжительность желаемого сна в качестве аргумента тайм-аута.
В языке программирования C системный вызов select объявлен в заголовочном файле sys/select.h или unistd.h и имеет следующий синтаксис:
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *timeout);
аргумент | описание |
---|---|
нфдс | Это целое число, на единицу превышающее максимальное значение любого файлового дескриптора в любом из наборов. Другими словами, добавляя файловые дескрипторы в каждый из наборов, вы должны вычислить максимальное целое значение всех из них, затем увеличить это значение на единицу и затем передать его как nfds. |
чтение файлов | Тип fd_set, содержащий дескрипторы файлов, которые необходимо проверить на готовность к чтению, и на выходе указывает, какие дескрипторы файлов готовы к чтению. Может быть НУЛЕВОЙ . |
записьfds | Тип fd_set, содержащий дескрипторы файлов, которые необходимо проверить на готовность к записи, и на выходе указывает, какие дескрипторы файлов готовы к записи. Может быть НУЛЕВОЙ . |
errorfds | Тип fd_set, содержащий файловые дескрипторы, которые необходимо проверить на наличие ожидающих ошибок, а на выходе указывает, какие файловые дескрипторы имеют ожидающие ошибки. Может быть НУЛЕВОЙ . |
тайм-аут | структура типа struct timeval, указывающая максимальный интервал ожидания завершения выбора. Если аргумент timeout указывает на объект типа struct timeval, члены которого равны 0, select() не блокируется. Если аргумент тайм-аута равен NULL, select() блокируется до тех пор, пока событие не приведет к возврату одной из масок с допустимым (ненулевым) значением. Linux обновит тайм-аут, чтобы указать, сколько времени прошло, хотя такое поведение не характерно для большинства других систем Unix. |
fd_set type
Аргументами можно манипулировать с помощью четырех служебных макросов: FD_SET(), FD_CLR(), FD_ZERO() и ФД_ИССЕТ() .
Select возвращает общее количество бит, установленных в чтения, записи и errorfds или ноль, если тайм-аут истек, и -1 в случае ошибки.
Наборы файловых дескрипторов, используемые при выборе, имеют конечный размер в зависимости от операционной системы. Новый системный вызов опрос предлагает более гибкое решение.
Пример
[ редактировать ]#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 <err.h>
#include <errno.h>
#define PORT "9421"
/* function prototypes */
void die(const char*);
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;
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 (0 != (error = getaddrinfo(NULL, PORT, &hints, &res0)))
errx(EXIT_FAILURE, "%s", gai_strerror(error));
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 == sockfd)
exit(EXIT_FAILURE);
freeaddrinfo(res0);
if (-1 == (listen(sockfd, 32)))
die("listen()");
if (-1 == (fcntl(sockfd, F_SETFD, O_NONBLOCK)))
die("fcntl()");
FD_ZERO(&master);
FD_ZERO(&readfds);
FD_SET(sockfd, &master);
maxfd = sockfd;
while (1)
{
memcpy(&readfds, &master, sizeof(master));
(void)printf("running select()\n");
if (-1 == (nready = select(maxfd+1, &readfds, NULL, NULL, NULL)))
die("select()");
(void)printf("Number of ready descriptor: %d\n", nready);
for (i=0; i<=maxfd && nready>0; i++)
{
if (FD_ISSET(i, &readfds))
{
nready--;
if (i == sockfd)
{
(void)printf("Trying to accept() new connection(s)\n");
if (-1 == (new = accept(sockfd, NULL, NULL)))
{
if (EWOULDBLOCK != errno)
die("accept()");
break;
}
else
{
if (-1 == (fcntl(new, F_SETFD, O_NONBLOCK)))
die("fcntl()");
FD_SET(new, &master);
if (maxfd < new)
maxfd = new;
}
}
else
{
(void)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);
(void)printf("%zi bytes received.\n", nbytes);
close(i);
FD_CLR(i, &master);
}
}
}
}
return 0;
}
void die(const char *msg)
{
perror(msg);
exit(EXIT_FAILURE);
}
См. также
[ редактировать ]Ссылки
[ редактировать ]- ^ Группа исследования компьютерных систем (1994). «select, pselect — синхронное мультиплексирование ввода-вывода» . Перекрестная ссылка BSD . НетБСД .
- ^ «Методы обработки соединений» . nginx.org .
Внешние ссылки
[ редактировать ]- Единая спецификация UNIX , версия 4 от Открытой группы. – Справочник по системным интерфейсам,
- man-страницы для
select(2)
во FreeBSD, NetBSD, OpenBSD и DragonFly BSD