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


Автор: chozen 26.1.2008, 21:46
Реализация архитектуры клиент-сервер c возможным количеством клиентов >> 100.
Подскажите, имеются ли какие ограничения на использование сокетов в данном случае?

Имеется компьютер с выделенным IP. На нем стоит серверная часть программы и следит, какие
клиенты в данный момент он-лайн. Поэтому, клиенты должны посылать каждую минуту (допустим)
некое сообщение - "несущую" - признак того, что клиент "еще здесь".

Есть ли какие особенности реализации такой системы? Обычные сокеты подойдут, если учесть,
что скоростью можно пренебречь и важна лишь общая работоспособность комплекса.

Автор: JackYF 26.1.2008, 22:08
Цитата(chozen @  26.1.2008,  20:46 Найти цитируемый пост)
Есть ли какие особенности реализации такой системы? Обычные сокеты подойдут, если учесть,
что скоростью можно пренебречь и важна лишь общая работоспособность комплекса. 

да, подойдут... а что, есть необычные сокеты? smile

Автор: chozen 26.1.2008, 23:16
Просто некоторый человек, который знает гораздо больше меня в это области, говорил какие-то больно мудреные вещи.

Как должен вести себя сервер на примере такой архитектуры?

Автор: JackYF 26.1.2008, 23:46
Цитата(chozen @  26.1.2008,  22:16 Найти цитируемый пост)
Как должен вести себя сервер на примере такой архитектуры? 

в чём вопрос?

Автор: Олег2005 28.1.2008, 19:47
4.4.    Выбор модели I/O для приложения
Семь моделей ввода/вывода WinSock в окружении оконных и консольных приложений и сервисов, различные требования протоколов верхнего (пользовательского) уровня, однопоточность и многопоточность, однопроцессорные хосты и многопроцессорные – весь этот набор ставит программиста перед очень непростым выбором, какую модель избрать для решения данных конкретных задач. Ниже перечислены наиболее очевидные варианты, рассмотренные нами в том или ином объеме: 
1.    "Обычные" блокирующие сокеты – "родное" состояние любого сокета – блокирующее, и вызов операции на нем не вернет управление, пока она не закончится. 
2.    "Чисто" неблокирующие сокеты – Вызов на таких сокетах возвращает управление немедленно, даже если операция еще будет продолжаться. Хотя принципиально до момента возврата программа может производить некоторые действия, этот метод требует постоянного опроса для определения момента завершения операции – обычно с помощью select(). 
3.    Мультиплексирование с помощью select(). Функция select() блокирует родительский поток до тех пор, пока на одном из сокетов не произойдет некоторое сетевое событие. Обычная практика – использование select() на неблокирующих сокетах во избежание опроса. 
4.    Асинхронные сокеты – это тоже неблокирующие сокеты (WSAAsyncSelect()), за исключением того, что не требуется производить опрос – модуль стекового протокола посылает специальное оконное сообщение, когда на сокете произойдет нечто интересующее программу. 
5.    Объекты-события – Используется WSAEventSelect(), механизм похож на метод мультиплексирование с помощью select(), но более эффективный. Кроме того, не стоит забывать, что select() работает с Беркли-сокетами, а WSAEventSelect() работает в среде WinSock. 
6.    I/O с перекрытием – Одна из наиболее примечательных особенностей WinSock 2, которая дает возможность обобщить на сокетные операции унифицированный I/O-механизм Win32 API и дает существенный выигрыш в производительности по сравнению с предыдущими моделями. 
7.    I/O Сompletion Port – наибольший эффект от применения этой модели может быть достигнут для серверных приложений на многопроцессорных аппаратных платформах.
Следует отметить, что применение любого из упомянутых методов в многопоточной среде может привести к существенным модификациям того или иного избранного механизма I/O, так как потоки существенно влияют на его природу.
Конечно же, при выборе в первую очередь следует обратить внимание на операционную систему, для которой пишется приложение, ибо все системы обладают различными сетевыми характеристиками. 
К примеру, Windows 9x не содержат в своем ядре механизма I/O с перекрытием, и если даже метод работает, то только за счет эмуляции на уровне API, и сокетная операция ReadFile() в Windows 9x будет неудачной. В UNIX механизм, аналогичный I/O с перекрытием, отсутствует. Как было уже отмечено выше, в некоторых UNIX-like системах введено понятие "чистых" асинхронных операций aio_*(), но они не соотносятся с WinSock-идеологией и не так широко распространены. 
Далее, хотя практически все современные UNIX-like системы поддерживают так называемые "потоки Posix – Posix threads", API для создания многопоточных приложений и техника программирования в UNIX и Windows различны. 
Из перечисленных методов функция select() для неблокирующих сокетов считается наименее эффективной из-за больших накладных расходов на ее исполнение, и эти расходы растут линейно при увеличении числа обслуживаемых соединений. Вместе с тем она хороша по причине портабельности кода, потому что все системы ее поддерживают.
Асинхронная модель с WSAAsyncSelect() также не принадлежит к числу очень эффективных, и она хороша для небольших объемов данных, к тому же она работает только в оконном окружении.
Модель с WSAEventSelect() обладает несколько большей эффективностью по сравнению с моделью WSAAsyncSelect(), плюс хорошая совместимость с "безоконными" приложениями. Она рекомендуется для серверов, получающих до 100 запросов на соединение и их обработку. Проблема лишь в том, что можно запустить "в дело" не более 64 объектов (в одном потоке) одновременно, и если будет создано 1024 сокета, это потребует 16–ти потоков!
Небольшой трафик – 1-100 запросов на соединение - может практически без ущерба обслуживаться любой из этих моделей.
Для высокопроизводительных и достаточно загруженных по количеству запросов серверов безусловно рекомендуется модель I/O с перекрытием – ни одна прежде рассмотренная модель не может себя с ней сравнить. Она позволяет справиться с нагрузкой десятков тысяч запросов на соединение (при условии достаточного объема быстродействующей оперативной памяти на сервере), и  еще более производительная модель порта завершения.
Следующие рекомендации могут быть отнесены к среде исполнения. Например, не рекомендуется программировать блокирующие вызовы в однопоточной среде с графическим интерфейсом (GUI), в этом случае лучше работать с асинхронными сокетами. В клиентских программах "усиленное" использование многопоточности редко оправдано, к тому же надо принимать во внимание вопросы синхронизации и отладки.
Многопоточность оправдана для FTP-серверов, для веб-броузеров, позволяющих закачку файлов в фоновом режиме, для посылки писем в email-клиенте без прерывания работы пользователя и так далее – программа должна применять многопоточность грамотно и уместно. Возможно также применение многопоточных клиентских приложений для задач тестирования серверов.

Автор: JackYF 29.1.2008, 10:25
Олег2005, где ссылка на источник?

Автор: Олег2005 29.1.2008, 11:07
Цитата(JackYF @  29.1.2008,  10:25 Найти цитируемый пост)
Олег2005, где ссылка на источник? 

Тут ссылаться не на кого - это из моего учебника по современному сетевому программированию
для моего вуза smile 

Автор: JackYF 29.1.2008, 11:22
Цитата(Олег2005 @  29.1.2008,  10:07 Найти цитируемый пост)
это из моего учебника по современному сетевому программированию
для моего вуза smile  

У учебника есть автор, у учебника есть название.
Извиняюсь, понял smile

Автор: dumb 29.1.2008, 12:38
Олег2005, яви публике своё ФИО. smile
а кстати, этот учебник издавался "в массы"?

Автор: chozen 29.1.2008, 23:48
Господа, СПАСИБО ВСЕМ БОЛЬШОЕ!!! Особенно Олегу!

Не побрезгуйте сообщить ссылочку на пример Overlapped I/O Sockets. Кроме МСДНа.

Автор: Олег2005 30.1.2008, 11:03
Цитата(dumb @  29.1.2008,  12:38 Найти цитируемый пост)
Олег2005, яви публике своё ФИО. 

Не думаю что в этом есть какая-то необходимость - если надо, то в ПМ
Цитата(dumb @  29.1.2008,  12:38 Найти цитируемый пост)
а кстати, этот учебник издавался "в массы"? 

3 года я предлагал этот учебник по всем популярным российским издательствам - Питер, БХВ, Солон - неа, им не интересно - литература для чайников приносит бОльший доход.
Поэтому он и был издан внутриинститутским вариантом в рижском вузе TCИ - (TSI)
У нашей библиотеки есть сайт, может там что есть в электронном виде.

Автор: chozen 31.1.2008, 01:39
Олег2005
Спасибо за приложенный пример. К слову, а сервер как должен работать с такой схемой? В примере только клиент...

Автор: Олег2005 31.1.2008, 11:25
Вот возможный вариант простого сервера:
Код

#define DATA_BUFSIZE        4096
void main(void)
{
    WSABUF DataBuf;
    char buffer[DATA_BUFSIZE];
    DWORD EventTotal = 0,  RecvBytes=0,   Flags=0;
    WSAEVENT EventArray[WSA_MAXIMUM_WAIT_EVENTS];
    WSAOVERLAPPED AcceptOverlapped;
    SOCKET ListenSocket, AcceptSocket;
    // Шаг 1:
    // Стартуем Винсок и и формируем слушающий сокет (socket,listen,bind) и все что надо
    ...
    // Шаг 2:
    // Принимаем запрос на вхолящее соединение
    AcceptSocket = accept(ListenSocket, NULL, NULL);
    // Шаг 3:
    // Формируем  overlapped structure
    EventArray[EventTotal] = WSACreateEvent();
    ZeroMemory(&AcceptOverlapped, sizeof(WSAOVERLAPPED));
    AcceptOverlapped.hEvent = EventArray[EventTotal];
    DataBuf.len = DATA_BUFSIZE;
    DataBuf.buf = buffer;
    EventTotal++;
    // Step 4:
    // Запускаем  WSARecv для получения запроса от клиента
    if (WSARecv(AcceptSocket, &DataBuf, 1, &RecvBytes,
        &Flags, &AcceptOverlapped, NULL) == SOCKET_ERROR)
    {
     if (WSAGetLastError() != WSA_IO_PENDING)
     {
         // Значит ошибка
     }
 }
    // Обработка перекрытого чтения на сокете
    while(TRUE)
    {
     DWORD    Index;
        // Шаг 5:
        // Ждем завершения перекрытого I/O
        Index = WSAWaitForMultipleEvents(EventTotal,
            EventArray, FALSE, WSA_INFINITE, FALSE);
        // Индекс должен быт 0 так как у нас имеется 
        // только один дескриптор события в массиве EventArray
        // Шаг 6:
        // Сбрасываем просигналенное событие
        WSAResetEvent(
            EventArray[Index - WSA_WAIT_EVENT_0]);
        // Шаг 7:
        // Определяем статус перекрытого запроса
        WSAGetOverlappedResult(AcceptSocket,
            &AcceptOverlapped, &BytesTransferred,
            FALSE, &Flags);
        // Сразу проверяем, может клиент закрыл соединение
        // и если так,  то закрываем свой сокет
        if (BytesTransferred == 0)
        {
            printf("Closing socket %d\n", AcceptSocket);
            closesocket(AcceptSocket);
            WSACloseEvent(EventArray[Index - WSA_WAIT_EVENT_0]);
            return;
        }

        // Выполняем действия с полученными данными 
        // DataBuf содержит полученные данные
        ...
        // Шаг 8:
        // Выдаем следующий WSARecv() - может быть WSASend() - в зависимости от логики
        Flags = 0;
        ZeroMemory(&AcceptOverlapped, sizeof(WSAOVERLAPPED));
        AcceptOverlapped.hEvent = EventArray[Index -  WSA_WAIT_EVENT_0];
        DataBuf.len = DATA_BUFSIZE;
        DataBuf.buf = buffer;
if (WSARecv(AcceptSocket,&DataBuf,1,&RecvBytes,&Flags, &AcceptOverlapped,
             NULL) == SOCKET_ERROR)
        {
            if (WSAGetLastError() != WSA_IO_PENDING)
            {
                // Какая-то ошибка
            }
        }
    }
}

Автор: Олег2005 31.1.2008, 11:44
Форум сглючил smile 

Автор: acral 12.2.2008, 23:28
Олег2005, А можешь дать линк на учебник, я не  могу его найти...

Автор: Олег2005 12.2.2008, 23:51
Цитата(acral @  12.2.2008,  23:28 Найти цитируемый пост)
можешь дать линк на учебник, я не  могу его найти...

Увы, линка я тоже не нашел - значит электронной версии нет
А в чем проблемы то?

Автор: quasi 13.2.2008, 17:33
А подскажите, в каких случаях лучше использовать синхронный\асинхонный? Конеша в многопоточке синхронным геморно все перебирать, поправте, если не так... От чего зависит на сколько клиентов хватит сервера, 100, 1к, 10к, итд...?

Автор: Олег2005 15.2.2008, 00:43
Цитата(quasi @  13.2.2008,  17:33 Найти цитируемый пост)
от чего зависит на сколько клиентов хватит сервера, 100, 1к, 10к, итд...?

Зависит от многого:
1 - от наличия памяти (многопоточный сервер - на каждый поток выделяется 1 мб памяти+память под сокетные буфера)
2 - от количества процессоров (ядер)
3 - от модели сетевого ввода-вывода (см.стр.1)
4 - от идеологии программирования - это тоже играет роль

Добавлено через 1 минуту и 14 секунд
Цитата(quasi @  13.2.2008,  17:33 Найти цитируемый пост)
синхронный

На загруженных серверах синхронный I/O не применяется

Автор: quasi 16.2.2008, 15:50
Цитата

На загруженных серверах синхронный I/O не применяется 

А какие тогда еще есть под юних?
Цитата

4 - от идеологии программирования - это тоже играет роль

тогда скажите или покажите как не нужно smile 
было бы очень здорово!

Автор: Олег2005 16.2.2008, 17:15
Цитата(quasi @  16.2.2008,  15:50 Найти цитируемый пост)
тогда скажите или покажите как не нужно 

Это надо прочитать вам курс лекций - форум на это не рассчитан
Посмотрите вот этот http://tangentsoft.net/wskfaq/

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