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


Автор: null56 2.12.2008, 10:01
Задача: создание сервера, который будет ожидать соединения по SSL, аутентифицировать клиента, проверять его права доступа, читая их из базы (mysql, postgresql).
ОС: linux

Почитав на форуме различные способы создания, так и не понял общего эффективного решения. Но, как видно, все ссылаются на использование select для слежения за сокетами и создание второго потока, а то и к совокупности между ними.

Хочу привезти алгоритм моего понимания на основе прочитанного (работа только серверной):
1) Сервер висит в ожидании запроса на соединение
2) При запросе на соединение сервер в случае успешной аутентификации добавляет сокет в массив SELECT и в цикле начинает следить за состоянием каждого из сокетов и это в каком - то дочернем потоке, потому что в основном потоке приложение будет висеть в ожидании подключений accept
3) При запросе со стороны клиента (передача условной команды, допустим чтение данных из базы), это событие регистрируется через SELECT и создается ЕЩЕ один поток для этого сокета, в котором осуществляется какое - либо действие с базой???!!!
4) По завершению работы потока сокет продолжает отслеживаться через select и при необоходимости закрыт, уже в основном потоке

Вопрос: Как совместно реализовать взаимодействие select и accept для работы сервера и правильно ли я это понимаю?

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

Если в описании моего алгоритма работы сервера есть недочеты, пожалуйста опишите их здесь
Заранее благодарен за помощь

Автор: MAKCim 2.12.2008, 11:39
null56, 
во-первых, если ОС Linux, то не select нужно использовать, а epoll
во-вторых, общий принцип следующий
1 поток - аккептор (вызывает accept), остальные N - рабочие (1 <= N <= K * CPU), CPU - количество процессоров, K - произвольный множитель (зависит от того, как эффективно реализован шедулинг в ОС)
каждый рабочий поток работает со своей матрицей определенного размера (зависит от производительности процессора)
каждый элемент матрицы инкапсулирует все необходимое для взаимодействия с клиентом
принцип работы рабочего потока: проходит по всем элементам матрицы и вызывает функции, которые соответствуют состояниям элементов
(конечный автомат)
после этого вызывает epoll_wait для всех сокетов клиентов, которые соответствуют этому потоку
epoll_wait возвращает набор событий, он их обрабатывает и заного повторяет весь цикл
задача потока аккептора - дергать accept, находить свободный элемент в какой-либо матрице (желательно это делать с умом, чтобы равномерно нагрузить систему), устанавливать состояние элемента в INIT
рабочий поток, проходя по матрице, видит, что элемент находится в состоянии INIT, добавляет его в свой epoll
для работы с SSL настоятельно рекомендую использовать либу openSSL

что касается взаимоодействия с мускулом, то наилучшее решение, имхо, отдельным тредом поддерживать кэш соединений к базе, чтобы по возможности избежать блокирования на коннекте к базе
а еще лучше, использовать неблокирующий I/O для взаимодействия с mysql
сейчас точно не скажу, поддерживается ли он нативно в libmysql
если нет, надо пропатчить либу

да, забыл сказать, весь I/O на стороне сервера, естественно, неблокирующий 

как-то так

Автор: null56 2.12.2008, 12:23
MAKCim, 

Уточнюсь, как я понял это....

1) Сразу при запуске приложения я создаю 1 серверный поток и какое - то количество дочерних...
2) Дочерние потоки хранят матрицы с моими структурами, в которых я храню какую - то нужную мне информацию. Вызов epoll_wait остановит цикл проверки всей матрицы до происхождения определенного события с одним из сокетов данного потока.

Или же по матрице нужно бегать постоянно????

И второе, как  лучше организовать межпроцессное взаимодействие аккептора и рабочих потоков, чтобы иметь доступ к каждой матрице каждого потока?

Автор: MAKCim 2.12.2008, 14:01
Цитата(null56 @  2.12.2008,  12:23 Найти цитируемый пост)
1) Сразу при запуске приложения я создаю 1 серверный поток и какое - то количество дочерних...

да, +поток для БД

Цитата(null56 @  2.12.2008,  12:23 Найти цитируемый пост)
2) Дочерние потоки хранят матрицы с моими структурами, в которых я храню какую - то нужную мне информацию. Вызов epoll_wait остановит цикл проверки всей матрицы до происхождения определенного события с одним из сокетов данного потока.

матрица одна глобальная
доступ к ней имеют все

сначала обрабатываем состояния всех элементов (в цикле)
потом дергаем epoll
потом таймаут
потом все повторяем сначала

Цитата(null56 @  2.12.2008,  12:23 Найти цитируемый пост)
Или же по матрице нужно бегать постоянно????

постоянно, но через определенный таймаут


Цитата(null56 @  2.12.2008,  12:23 Найти цитируемый пост)
И второе, как  лучше организовать межпроцессное взаимодействие аккептора и рабочих потоков, чтобы иметь доступ к каждой матрице каждого потока? 

никак  smile 
серьезно
тут можно воспользовать принципом делегирования состояний
т. е, например, элементы в состоянии FREE игнорируются рабочим потоком, но используются аккептором
аккептор же в свою очередь игнорит все состояния кроме FREE
рабочий поток переводит элемент в состояние FREE, а аккептор - в INIT
для x86, x86-64 здесь даже не нужна синхронизация
делаем состояние 32-х разрядной переменной, инкапсулируем ее в элемент и изменяем только через =
в таком случае атомарность гарантируется, если адрес переменной выровнен по границе размера 4-х байт
а это по-умолчанию гарантируется компилятором

Автор: null56 2.12.2008, 15:32
Суть ясна... спасибо...

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