почему выбор () всегда возвращается 0 после первого тайм-аута

У меня есть проблема об избранной функции, когда я работал над программой сокета Linux. Избранная функция хорошо работала, как в странице справочника говорится, соединил ли клиент сторону сервера во временном интервале, настроенном сервером. Если тайм-аут произошел, избранная функция возвратится 0 навсегда. В то время я отлаживаю клиент и нахожу, что клиент соединился с сервером. Но избранная функция все еще возвращается 0. Я имею поиск эта проблема, но не нашел ни один полезным. Кто-то мог знать, почему выбору действительно нравилось это? Моя версия Linux является RHEL5.4.Спасибо за помощь.

Код проиллюстрирован ниже.

static const int maxLog = 10000;

int main()
{
    int servSock;
    signal(SIGPIPE, SIG_IGN);
    if((servSock = socket(AF_INET, SOCK_STREAM, 0)) < 0 )
    {
        printf("socket create fail\n");
        exit(-1);   
    }
    int val = 1;
    if(setsockopt(servSock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val))<0)
    {
        DieWithUserMessage("setsockopt error");
    }

    struct sockaddr_in serverAddr;
    memset(&serverAddr, 0, sizeof(serverAddr));
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    serverAddr.sin_port = htons(22000);

    if(bind(servSock, (struct sockaddr *) &serverAddr, 
                sizeof(serverAddr)) < 0)
    {
        printf("socket bind  fail\n");
        exit(-1);   
    }

    if(listen(servSock, maxLog) < 0)
    {
        printf("listen failed\n");
        exit(-1);
    }   

    fd_set read_set;
    FD_ZERO(&read_set);
    FD_SET(servSock, &read_set);
    int maxfd1 = servSock + 1; 
    std::set<int> fd_readset;

    for(;;){    
        struct timeval tv;
        tv.tv_sec = 5;
        int ret = select(maxfd1, &read_set, NULL, NULL, tv);       
        if(ret == 0)
            continue;

        if(ret < 0)
            DieWithUserMessage("select error");

        if(FD_ISSET(servSock, &read_set))
        {
            struct sockaddr_in clntAddr;
            socklen_t clntAddrlen = sizeof(clntAddr);
            int clntSock = accept(servSock, (struct sockaddr *) &clntAddr, &clntAddrlen);
            if(clntSock < 0)
            {
                printf("accept failed()");
                exit(-1);
            }   

            maxfd1 = 1 +  (servSock>=clntSock? servSock:clntSock);
            FD_SET(clntSock, &read_set );
            fd_readset.insert(clntSock); 
         }

    } 
}
7
задан Jonathan Leffler 24 July 2010 в 06:43
поделиться

3 ответа

Вы должны заполнять ваш FD_SET на каждой итерации. Лучший способ сделать это - хранить где-то коллекцию ваших FD и помещать ту, которая нужна для вызова select, во временный FD_SET.

Если вам нужно обрабатывать большое количество клиентов, возможно, придется изменить макрос FD_SETSIZE (в /usr/include/sys/select.h).

Счастливого сетевого программирования :)

1
ответ дан 6 December 2019 в 06:35
поделиться

Функция 'select()' неудобна в использовании; вы должны устанавливать ее аргументы каждый раз перед вызовом, потому что она их изменяет. То, что вы видите, является демонстрацией того, что происходит, если вы не устанавливаете fd_set(s) каждый раз в цикле.

22
ответ дан 6 December 2019 в 06:35
поделиться

У вас уже есть правильный ответ - повторно инициализируйте fd_set s перед каждым звонком на выбирайте (2) .

Я хотел бы указать вам на лучшую альтернативу - Linux предоставляет возможность epoll (4) . Хотя это нестандартно, это намного удобнее, поскольку вам нужно настроить события, которых вы ждете, только один раз. Ядро управляет таблицами событий файловых дескрипторов за вас, поэтому это намного эффективнее. epoll также предоставляет запускаемые по фронту функциональные возможности, при которых сигнализируется только изменение состояния дескриптора.

Для полноты - BSD предоставляют kqueue (2) , Solaris имеет / dev / poll .

Еще одна вещь: ваш код имеет хорошо известное состояние гонки между клиентом и сервером. Взгляните на Stevens UnP: Nonblocking accept .

3
ответ дан 6 December 2019 в 06:35
поделиться
Другие вопросы по тегам:

Похожие вопросы: