c ++ выберите проблему - PullRequest
       6

c ++ выберите проблему

1 голос
/ 12 апреля 2011

Итак, я пытаюсь построить асинхронный сервер ... Вот краткое изложение того, что у меня есть:

int sockfd;
int max;
fd_set socks;
set<int> conns;

bind();
listen(sockfd);

while(1){
    FD_ZERO(&socks);
    max = sockfd;
    FD_SET(sockfd, &socks);
    for(set<int>::iterator it=conns.begin(); it!=conns.end(); it++){
        FD_SET(*it, &socks);
        if(max < *it){
            max = *it;
        }
    }

    int res = select(max+1, &socks, NULL, NULL, NULL);

    if(res < 0){
        cerr << "ERROR with select" << endl;
        break;
    }else if(res){
        if(FD_ISSET(sockfd, &socks)){
            //new connection
            int new_sockfd = accept();
            conns.insert(new_sockfd);
        }else{
            for(set<int>::iterator it=conns.begin(); it!=conns.end(); it++){
                if(FD_ISSET(*it, &socks){
                    char buffer[256];
                    read(buffer, 256, *it);
                    cout << buffer << endl;
                    close(*it);
                    conns.erase(*it);
                }
            }
        }
    }
}

Что в итоге происходит ... Если я подключу клиента-1, а затем клиента-2. А потом я пытаюсь отправить данные, используя Client-2, а затем Client-1 ... это работает ...

Однако, если я подключаю клиент-1, а затем подключаю клиент-2 ... и затем пытаюсь отправить данные, используя клиент-1. Select () возвращает -1 ...

Помощь

Ответы [ 2 ]

2 голосов
/ 12 апреля 2011

Просмотрите справочные страницы для выбора . Важная часть:

При следующих условиях pselect () и select () должны завершиться ошибкой и установить errno на:
EBADF
Один или несколько наборов дескрипторов файлов указали дескриптор файла, который не является допустимым дескриптором открытого файла.
EINTR
Функция была прервана до того, как произошло какое-либо из выбранных событий, и до истечения времени ожидания.

Если SA_RESTART был установлен для сигнала прерывания, то определяется реализацией, перезапускается ли функция или возвращается с помощью [EINTR].
EINVAL
Указан неверный интервал ожидания.
EINVAL
Аргумент nfds меньше 0 или больше, чем FD_SETSIZE.
EINVAL
Один из указанных файловых дескрипторов относится к STREAM или мультиплексору, который связан (прямо или косвенно) ниже по потоку от мультиплексора.

errno должен сказать вам, что не так.

Это просто вопрос, но когда вы закрываете соединение, ваш файловый дескриптор становится недействительным. Я предполагаю, что ошибка выбора должна быть EBADF

0 голосов
/ 13 апреля 2011

Я думаю, ваш код, удаленный из набора, является подозрительным. как только вы вызываете conns.erase(*it), ваш итератор становится недействительным (и его увеличение приводит к неопределенному поведению).

Изменение цикла на что-то вроде следующего должно решить проблему:

for(set<int>::iterator it=conns.begin(); it!=conns.end();)
{
    set<int>::iterator cur = it++;
    if(FD_ISSET(*cur, &socks)){
        char buffer[256];
        read(buffer, 256, *cur);
        cout << buffer << endl;
        close(*cur);
        conns.erase(*cur);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...