Как мне сделать неблокирующее поведение сервера в C, когда я хочу получить только одно соединение?

В C предположим, что у меня есть серверное приложение. Сокет настроен правильно и привязан к локальному порту, а функция listen() вызывается без ошибок.

Код такой:

    //obtain a connection.
    int connection;
    struct sockaddr_storage sender;
    socklen_t addr_size = sizeof(sender);
    if((connection=accept(sockfd, (struct sockaddr*)&sender, &addr_size))==-1)
            {close(sockfd); return -1; }
    if(close(sockfd)==-1){
            close(connection);
            return -1;
    }
    else
            return connection;

Успешно получает дескриптор файла подключения, через который данные могут быть прочитаны клиентом.

Мое приложение требует, чтобы сервер ждал определенное время, а затем отключался и выполнял другие действия, если соединение не установлено. Далее будет принято не более одного соединения. Accept() — блокирующий системный вызов, но я хотел бы избежать блокировки.

Кажется, есть много разных способов решить эту проблему:

  • вопрос SE предлагает использовать select для решения этой проблемы, но выберите предназначен для одновременного мониторинга многих файловых дескрипторов и здесь кажется излишним.

  • Другой вопрос предлагает изменить сокет, чтобы он был неблокирующим, а затем проверить в цикле, действительно ли соединение было установлено. Это тоже сработает, но кажется не очень хорошим, потому что я хочу заблокировать - но не навсегда.

  • В других языках люди используют SIGALARM и команду alarm() для предотвращения блокировки, но мое приложение имеет несколько потоков, и это похоже на решение, подверженное ошибкам.

  • В некоторых других языках (Java?) Я думаю, что есть аргумент тайм-аута, который можно передать, чтобы принять, который выполняет это. Это было бы идеально здесь, но я не могу найти подобную функцию для сокетов в C.

Есть ли более приятный способ решить эту проблему? Кажется, что кто-то другой уже понял бы это. Если нет лучшего способа, какое из упомянутых выше решений является наиболее подходящим? Я склоняюсь к тому, чтобы сделать сокет неблокирующим, но, похоже, это вносит много лишнего мусора.


person John Doucette    schedule 15.11.2012    source источник
comment
Это именно то, для чего предназначено select()... некоторое время ожидания активности одного или нескольких файловых дескрипторов. Позвоните select() с тайм-аутом, и вы получите то, что хотите.   -  person larsks    schedule 15.11.2012
comment
select() это именно то, что вам нужно. Оберните его небольшой функцией, и это тоже не будет выглядеть излишним.   -  person moooeeeep    schedule 15.11.2012


Ответы (1)


При использовании select не забывайте всегда делать свой файловый дескриптор неблокирующим с помощью fcntl(), иначе клиент может инициировать соединение, select вернется, клиент может завершить работу, и ваш сервер будет навсегда заблокирован в accept().

После успешного принятия вы можете снова перевести файловый дескриптор в режим блокировки, если ваша программа работает таким образом.

person LtWorf    schedule 15.11.2012