Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Сети > Неблокирующий сервер


Автор: Sphinx 19.1.2007, 21:28
Написал стандартную функцию сервера, но она, если нет соединения, останавливается на accept. Мне же нужно периодически проверять состояние одной глобальной переменной. Как я понял подобное можно сделать с помощью select. Но ничего не получается. Дайте простейший пример сервера с использованием select.

Автор: Anikmar 19.1.2007, 21:49
Я ничего не понял, если честно...

Что такое стандартная функция сервера?

Нужно периодически просматривать появилось ли соединение?

Автор: Sphinx 19.1.2007, 22:12
Я имел ввиду, что использовал стандартний пример сервера, которые есть во многих учебниках.
А проверять надо состояние переменной совершенно не имеющей отношение к сети. В общем надо чтобы сервер не зависал на accept, а организовать перед ним цикл, в котором делать проверку на появление соединения ну и попутно просматривать эту переменную.

Автор: W4FhLF 19.1.2007, 22:43
Создай функцию с accept в отдельном потоке или используй WSAAccept 

Автор: ptr 22.1.2007, 07:35
Есть много способов: использовать select с установленным timeout, использовать неблокирующие сокеты, использовать многопоточность, или установить таймер. Выбирай любой.

Автор: Sphinx 23.1.2007, 08:53
Поясню, более конкретно, чего я хочу. Может будут другие варианты, как это реализовать. Сервер запускается в отдельном потоке, который создает загружаемый плагин. При выгрузке плагина, хочется, чтобы сервер корректно завершал свою работу. В блокирующем режиме сервер вызывает accept и управление к нему не возвращается (пока кто-то не создаст соединение). Была идея перед вызовом accept сделать цыкл в котором с помощью select определять попытку соединения, но ничего не получилось. Потом попробовал использовать неблокирующий сокет. Вот код сервера:
Код

void DoServer()
{
SOCKET lSck,cSck;
SOCKADDR_IN sin;
int nlen;
    if((lSck=socket(AF_INET,SOCK_STREAM,0))==INVALID_SOCKET){
        Error("ERROR: Failed to create listening socket %d");
        return;
    }
    nlen=1;
    if(ioctlsocket(lSck,FIONBIO,&nlen)==SOCKET_ERROR)AddLog("Error switch in nonblock mode");
    else AddLog("Socket in nonblock mode");
    sin.sin_family=AF_INET;
    sin.sin_port=htons(Port);
    sin.S_addr=INADDR_ANY;
    if(bind(lSck,&sin,sizeof(sockaddr))!=0){
        Error("ERROR: Failed to bind() listening socket %d");
        return;
    }
    if(listen(lSck,5)!=0){
        Error("ERROR: Failed to listen() socket %d");
        return;
    }
    do{
        nlen=sizeof(sockaddr);
        while((cSck=accept(lSck,&sin,&nlen))==-1){
            if(WSAGetLastError()!=10035){
                Error("ERROR - accept() failed %d");
                return;
            }
            Sleep(0);
            if(processtread==FALSE)return;
        }
        nlen=sizeof(sockaddr);
        getpeername(cSck,&sin,&nlen);
        InputMsg(cSck);
        closesocket(cSck);
    }while(processtread);
}

Все отрабатывает как надо, кроме завершения работы - зависает на вызова WSACleanup(). Вот код главного потока:
Код

void MainThread(dword i)
{
WSADATA WSAData;
    runthread=TRUE;
    AddLog("Start Server Thread");
    if(WSAStartup(0x202,#WSAData)!=0)Error("WSAStartup() failed with error code %d");
    else DoServer();
    WSACleanup();
    AddLog("Close Server Thread");
    runthread=FALSE;
}


Автор: Enelar 26.3.2011, 18:37
Цитата(Sphinx @  23.1.2007,  08:53 Найти цитируемый пост)
Была идея перед вызовом accept сделать цыкл в котором с помощью select определять попытку соединения, но ничего не получилось. 

Что именно у вас не получилось?
Код

readfds:

    * If listen has been called and a connection is pending, accept will succeed.
    * Data is available for reading (includes OOB data if SO_OOBINLINE is enabled).
    * Connection has been closed/reset/terminated.

Собственно на сокете, находящемся в состоянии прослушки, функция оставит его в массиве согласно пункту один - если есть входящее соединение, и следующий вызов функции accept не заблокирует приложение. Есть небольшая особенность с функцией select - она не расчитанна на вызов в массиве, нужно делать хотя бы Sleep(1) а лучше 10.

А вообще для подобных целей есть только 2 норм варианта
1) Слушающий поток, отдельный. Блокируется в функции accept, при ее успехе завершается с кодом - входящий сокет, или 0 если ошибка. В основном потоке проверяется не завершился ли дополнительный. Возможны модификации.
2) Использование неблокирующих сокетов(что по моему личному мнению намного лучше).

Автор: Олег2005 27.3.2011, 10:16

M
Олег2005
Enelar, внимательно следите за датами опубликования темы и ответов - последний ответ в тему был 4 года назад.....

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)