Jump to content

выбрать (Unix)

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);
}

См. также

[ редактировать ]
  1. ^ Группа исследования компьютерных систем (1994). «select, pselect — синхронное мультиплексирование ввода-вывода» . Перекрестная ссылка BSD . НетБСД .
  2. ^ «Методы обработки соединений» . nginx.org .
[ редактировать ]
Arc.Ask3.Ru: конец переведенного документа.
Arc.Ask3.Ru
Номер скриншота №: 6a9125de388a7e01f1b0e9d2d95f773b__1655727420
URL1:https://arc.ask3.ru/arc/aa/6a/3b/6a9125de388a7e01f1b0e9d2d95f773b.html
Заголовок, (Title) документа по адресу, URL1:
select (Unix) - Wikipedia
Данный printscreen веб страницы (снимок веб страницы, скриншот веб страницы), визуально-программная копия документа расположенного по адресу URL1 и сохраненная в файл, имеет: квалифицированную, усовершенствованную (подтверждены: метки времени, валидность сертификата), открепленную ЭЦП (приложена к данному файлу), что может быть использовано для подтверждения содержания и факта существования документа в этот момент времени. Права на данный скриншот принадлежат администрации Ask3.ru, использование в качестве доказательства только с письменного разрешения правообладателя скриншота. Администрация Ask3.ru не несет ответственности за информацию размещенную на данном скриншоте. Права на прочие зарегистрированные элементы любого права, изображенные на снимках принадлежат их владельцам. Качество перевода предоставляется как есть. Любые претензии, иски не могут быть предъявлены. Если вы не согласны с любым пунктом перечисленным выше, вы не можете использовать данный сайт и информация размещенную на нем (сайте/странице), немедленно покиньте данный сайт. В случае нарушения любого пункта перечисленного выше, штраф 55! (Пятьдесят пять факториал, Денежную единицу (имеющую самостоятельную стоимость) можете выбрать самостоятельно, выплаичвается товарами в течение 7 дней с момента нарушения.)