Как трябва да направя неблокиращо поведение на сървъра в 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 за решаване на това, но 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