![]() |
|
Модераторы: Daevaorn |
![]()
|
|
| REZiaMIX |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 346 Регистрация: 3.11.2007 Репутация: нет Всего: 4 |
Во многих моих задачах мне приходиться сталкиваться с сетевой частью, а где сетевая часть - там и сервер.
Все время в своих проектах дорабатывал , иногда переписывал и все время улучшал "велосипед". Впринципе все отлично работает: * в плане стабильности - все ок, ошибки уже отсеяны * в плане производительности - все ок, потому что высокая не требуется(но ведь если можно, почему нет???) * в тоже время чувство незаконченности - всегда есть какието архитектурные, не функциональные косяки. И решился я написать для себя идельную либу TCP асинхронного сервера. На данный момент поставил для себя такие требования: 1) Кроссплатформенность 2) Используем лучшую стратегию(epoll,iocp и тп) на каждой платформе для пущей производительности 3) Законченный вид класса, чтобы не плеваться на код - самое для меня главное Итак, за основу выбрал boost::asio - либа сразу отметает пункты 1 и 2 почти во всех ситуациях(конечено же если остальная часть выполненна правильно). К кросплатформенности вопросов нет(все что нужно есть в boost) Остается 3. Для меня очень удобным кажется такой вид этой "системы": * Класс соединение(или клиент) в приватике держит все нужные внутри сервера данные - хендлы сокетов и другое.(можно наследоваться, чтобы связать некие нужные данные с соединением) * Класс список соединений, чтото наподобие контейнера с особой синхронизацией. * Класс обработчик - имеет вирутальные колбеки onRead, onWrite(сервер получает ссылку на него при констракте) * Класс сервер, для работы нужны: ссылка на обработчик и на используемый список клиентов Имеет вирутальные onConnect,onDisconnect. * При том, для себя очень удобным считаю, что во все вирутальные функции(такие как onRecv,onWrite,onDisconnect) приходит указатель на класс "соединение", и во все управляющие(sendBufferTo, disconnectClient). * Можно самому инициировать подключение(connectTo) * сервер знает всех своих клиентов, т.е. должны присутствовать методы сразу для всех соединений: disconnectAll, sendBufferAll. * Есть огромное желание по максимуму использовать boost, НО только внутри. Снаружи должны быть чистые, легкие нешаблонные "лица". ^^^^^ хочу услышать любые мнения по этому поводу: почему коллбеки плохо? чем предложенная мной архитектура плоха, как лучше? Что же я хочу узнать? 1) Как вы себе представляете идеальные интерфейсы: сервера, списка клиентов, клиента. 2) Каким образом синхронизировать доступ к списку клиентов? Я вижу такие проблемы: некий клиент (указатель на класс лежит в списке std::vector) отключился, надо заблокировать вектор. Новый подключается - вектор заблокирован, ждем разблокировки... И т.п. комбинации подключений/отключений. Будет много лишнего простаивания/ожидания. + разные проблемы с владением: Хочу отправить пакет Васе, забираю из списка клиентов указатель на класс "соединение", в это время другой поток решает кикнуть этого клиента. В некотором месте получаем невалидный указатель на класс "соединение". Вот наброски, чтобы примерно поняли мои задумки:
Что думаю по синхронизации: 1)Чтобы не блокировать весь список целиком, можем синхронизировать блоками по 4-128 соединений: но при удалении и при новом соединении(используем std::vector erase, push_back) все равно надо блокировать весь вектор! Может быть нужно выбрать альтернативный контейнер, тогда какой? 2)Проблемы с владением - слишком много мыслей, хотелось бы чтолибо изящного типа boost::shared_ptr посоветуйте ? Очень рад был бы увидеть наброски интерфейсов, с описанием приемуществ. В общем то , хочу Вашего мнения, и много критики!!! Когда кто-то вас в чем-нибудь упрекает, он показывает то, что могло бы стать вашим преимуществом.Бернард Вербер))) Заранее спасибо за ответ, сразу прошу прощения за сонные ошибки. Кто дочитал нудный сей нудный пост, тому большой респект -------------------- ![]() |
|||
|
||||
| borisbn |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 4875 Регистрация: 6.2.2010 Где: Ростов-на-Дону Репутация: 22 Всего: 135 |
Начал хорошо: выработка требований, разбиение на классы... а вот дальше...
1. Разработку интерфейсов стОит начинать не с private-членов, а с public-функций 2. Использовать vector в качестве контейнера, в который будут постоянно добавлять/убирать элементы, да ещё и не в конце, - не есть гуд айдеа 3. Почему у RequestHandler'а не чисто абстрактный интерфейс ? Да ещё и в private... Как ты собираешься вызывать его функции ? 4. Почему у ServerBase конструктор в private-секции ? 5. У разных классов разный code-style -------------------- Женщины отличаются от программистов тем, что у них чары состоят из стрингов |
|||
|
||||
| REZiaMIX |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 346 Регистрация: 3.11.2007 Репутация: нет Всего: 4 |
Вот немного подправленный по некоторым вопросам код:
1) Впринципе есть представления о том, что должно быть в паблике (сонный забывал писать public, в коде что выше поправил) 2) Это был один из моих вопросов: "Может быть нужно выбрать альтернативный контейнер, тогда какой?" 3) Чем же RequestHandler не абстрактный ? Добавил Base к названию чтобы было очевидней. А должны ли быть его сейчашние функции в private, или лучше protected? 4) Немного скосил, все по одной и тойже причине, извиняюсь. Перенес в паблик + start stop тудаже! 5) Так весь фокус в том, что в списке лежат именно указатели на базовые классы. Можно унаследоваться, и добавить нужную связную информацию на каждое соединение. Например для веб-сервера это могут быть хедеры запроса, наподобие "User-Agent" А в данном случае , SOCKET (и функция getter для него) это та часть, которой пользуется сам сервер - дескриптор сокета. Соответсвенно, т.к. за основу взят буст, там будет другой класс(boost::asio::tcp::socket скорее всего) -------------------- ![]() |
|||
|
||||
| Alca |
|
|||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3993 Регистрация: 14.6.2006 Репутация: 7 Всего: 50 |
std::list |
|||
|
||||
| borisbn |
|
||||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 4875 Регистрация: 6.2.2010 Где: Ростов-на-Дону Репутация: 22 Всего: 135 |
чтобы класс стал абстрактным его функции должны быть абстрактными ( в конце объявления ставится = 0; )
В данном случае исключительно public Попробуй написать код, который использует твою библиотеку, как будто она уже полностью готова, и сразу увидишь все плюсы-минусы, а чтобы всё компилировалось в функциях поставь "заглушки" типа return true; -------------------- Женщины отличаются от программистов тем, что у них чары состоят из стрингов |
||||||
|
|||||||
| Alca |
|
|||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3993 Регистрация: 14.6.2006 Репутация: 7 Всего: 50 |
тесты рулят |
|||
|
||||
| borisbn |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 4875 Регистрация: 6.2.2010 Где: Ростов-на-Дону Репутация: 22 Всего: 135 |
REZiaMIX, когда-то делал такую же. см. аттач
Присоединённый файл ( Кол-во скачиваний: 16 )
Bagira.zip 4,68 Kb-------------------- Женщины отличаются от программистов тем, что у них чары состоят из стрингов |
|||
|
||||
| boostcoder |
|
|||
![]() pattern`щик ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 5458 Регистрация: 1.4.2010 Репутация: 49 Всего: 110 |
а почему асинхронный сервер вообще должен быть классом? Оо
при использовании asio, запросто можно обойтись без единого класса. структура контекста соединения, и всё. |
|||
|
||||
| REZiaMIX |
|
||||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 346 Регистрация: 3.11.2007 Репутация: нет Всего: 4 |
Мое мнение, что даже для общей картины и понимания, необходимы некие сущности: это сервер, он принимает подключения, установим ему обработчик для данных, подключился клиент. это не касаясь темы ООП. Alca Хотелось бы услышать почему именно std::list(приемущества оного, и минусы вектора)? И как лучше синхронизировать доступ к нему. borisbn Спасибо - то, чего действительно не хватало. Добавлено через 4 минуты и 27 секунд
Удивляюсь над собой, не вижу очевидностей Топик буду пополнять новыми вопросами по мере продвижения разработки(только по теме). Всем респект за ответы, в репу скину позже -------------------- ![]() |
||||
|
|||||
| Alca |
|
||||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3993 Регистрация: 14.6.2006 Репутация: 7 Всего: 50 |
Вот:
Вообще есть книги по STL Добавлено @ 11:25 Ну или там очередь заюзать Это сообщение отредактировал(а) Alca - 8.2.2011, 11:25 |
||||
|
|||||
| borisbn |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 4875 Регистрация: 6.2.2010 Где: Ростов-на-Дону Репутация: 22 Всего: 135 |
например: Скотт Мейерс. Эффективное использование STL там неплохо описано в каких случаях какие контейнеры лучше использовать, а в каких - противопоказано Это сообщение отредактировал(а) borisbn - 8.2.2011, 11:45 -------------------- Женщины отличаются от программистов тем, что у них чары состоят из стрингов |
|||
|
||||
| REZiaMIX |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 346 Регистрация: 3.11.2007 Репутация: нет Всего: 4 |
Отличия то знаю, но не в данном контексте. Какие по Вашему отличия критичны для моего случая?
-------------------- ![]() |
|||
|
||||
| borisbn |
|
||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 4875 Регистрация: 6.2.2010 Где: Ростов-на-Дону Репутация: 22 Всего: 135 |
Как я уже говорил, ты собираешься динамически добавлять/удалять элементы из контейнера, причём не обязательно в конце. Теперь подумай, как в этом случае будет работать вектор (читай просто массив), а как список ? Подсказка... вектор как-то так:
а в листе как-то так:
это ОЧЕНЬ примерно, но по сути как-то вот так. хотя... именно в твоём случае... количество подключений будет небольшое (ну не тысячи), да и частота вызова erase/push_back невысока, поэтому, как советует Мейерс, не знаешь какой контейнер использовать - используй vector Это сообщение отредактировал(а) borisbn - 10.2.2011, 17:53 -------------------- Женщины отличаются от программистов тем, что у них чары состоят из стрингов |
||||
|
|||||
| mabrarov |
|
|||
|
Шустрый ![]() Профиль Группа: Участник Сообщений: 100 Регистрация: 12.1.2011 Где: Казань Репутация: 8 Всего: 9 |
Могу предложить посмотреть на то, как реализован проект echo_server (asio samples: http://sourceforge.net/projects/asio-samples) - он создавался как раз с такой целью.
Вкратце: 1) все работает параллельно и асинхронно, с поддержкой многопоточности; 2) каждая сессия на сервере (привязанная к определенному TCP-сокету) - это активный объект, имеющий еще и внутренние циклы исполнения; 3) управление сессиями (добавление новой, удаление остановленной, останов всех сессий при останове сервера) осуществляется менеджером сессий (ma::echo::server::session_manager); 4) циклы активности (event loop) всех сессий исполняются одним пулом потоков (его размер по умолчанию связан с кол-вом логических процессоров в ОС); 5) логика менеджера сессий (как логика иного типа) исполняется другим пулом потоков (1-2 потока) - это сделано для ослабления взаимного влияния с пунктом 4 (при пиковых нагрузках); 6) вся синхронизация основана на очередях (boost::asio::io_service::strand) - это связано с необходимостью уменьшения ненужного простоя рабочих потоков и ведет (благодаря отличной реализации boost::asio::io_service::strand) к уменьшению частоты переключения потоков и увеличению вероятности использования "прогретого" кеша (кэша потока/ядра); 7) для "удержания" активных сессий в памяти менеджер сессий использует особый intrusive-container, основанный на связке boost::shared_ptr/weak_ptr - это позволяет добавлять и удалять сессии в данный контейнер со сложностью o = const и без дополнительного выделения памяти; 8) для экономии на выделении памяти остановленные сессии не освобождаются а резервируются для повторного использования; 9) предусмотрена возможность ограничения максимального количества одновременно активных сессий; 10) предусмотрен штатный останов сервера; 11) предусмотрен аварийный останов сервера и максимально быстрое прерывание работы всего сервера; 12) все параметры настраиваются а-ля CLI. Комментариев пока ноль. Но если есть хорошие знания в Boost.Asio, то можно разобраться и без них. Еще есть qt_echo_server - все то же самое но с GUI (и связкой с Qt). P.S. Забыл "похвастать" использованием C++0x (когда компилятор его поддерживает) - а именно move semantic/rvalue reference (а это очень важно для boost::shared_ptr/weak_ptr). Плюс, некоторые плюшки-workaround-ы, сделанные специально для asio (автор asio признал их правильными и оправданными). А комментарии будут (и мнооого) - просто хочу их сделать максимально "в стиле Boost". Это сообщение отредактировал(а) mabrarov - 13.4.2011, 02:24 |
|||
|
||||
![]()
|
| Правила форума "С++:Общие вопросы" | |
|
|
Добро пожаловать!
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn |
| 0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
| 0 Пользователей: | |
| « Предыдущая тема | C/C++: Общие вопросы | Следующая тема » |
|
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |