Date: Tue, 10 Dec 2002 16:15:22 +0500
From: Maksym Shevchenko <r0land@r0land.kiev.ua>
Newsgroups: ftn.ru.unix.prog
Subject: Реализация multithreaded сервера на C++
Вот реализовал один алгоритм и решил поделится с уважаемым All.
Постановка задачи: Требуется принимать входящие соединения и асинхронно
обрабатывать принимаемые данные и посылать что-то в ответ. Язык - С++,
target platform = Linux RH 7.x.
Что я сделал:
Первое - врапперы для POSIX mutex & pthread (на самом деле остались от
старого проекта):
Скажем, мне такая реализация показалась удобной, но обсуждаемой. ;-)
Далее реализовано несколько классов:
СListener - собствеено говоря он принимает входящие соединения;
СSocket - класс отвечающий за интерфейс с открытым сокетом;
СManager - управляет жзненым циклом CListener и хранит список СSocket.
for (int i=0 ; i < size; i++)
{
if ((pfd[i].fd) > 0)
{
if (pfd[i].revents & POLLHUP || pfd[i].revents & POLLERR)
/* Socket hung-up */
{
p_debug(LOG_DEBUG, "Loop() got POLLHUP||POLLERR on fds=[%d]",(FDS)pfd[i].fd);
OnKillSocket((FDS)pfd[i].fd);
KillSocket((FDS)pfd[i].fd);
}
if (pfd[i].revents & POLLIN &&
(m_mapSocket.find((FDS)pfd[i].fd) != m_mapSocket.end()))
/* Got data & CSocket exist*/
{
p_debug(LOG_DEBUG, "Loop() got POLLIN on fds=[%d]",(FDS)pfd[i].fd);
OnReceiveData((FDS)pfd[i].fd);
}
}
}
free(pfd);
}
else
{
sleep(1); /* we have no opened sockets... what about using mutex here? */
}
}
}
return NULL;
}
Ранее был реализован вариант с ожиданием изменения состояния сокета через
sigwaitinfo(...) после того как с полученым сокетом (в CSocket::CSocket)
проводились следующие манипуляции:
но к превеликому сожалению этот вариант имеет несколько недостатков. Во
первых этот вариант работает только тогда, когда pthreads реализованы как в
виде отдельных процессов. Во вторых fcntl(..,F_SETOWN,..) можно сделать
только от root'а. И в третьих, как не прискорбно, тестирование на 10000 и
более входящих соединениях показало что сигнал все таки облодает свойством
терятся.
Теперь смотрите как это используется:
class CServer : public CManager
{
void OnNewSocket (const FDS& id, const CSocket* socketX)
{
cout << "incomming fds=" << id << endl;
}
Почему я не рализовал listen в том же poll? Очень просто - представьте что
CManager'ов несколько, а CListener делает round-robin between them. T.е.
CManager::m_pListener становится статик и в CManager добовляется static
set<CManager *> m_setManager. Из конструктора CManager добовляем this в
m_setManger, из деструктора его соответсвенно убиваем. А в CListener::Loop
добавляется set<CManager*>::iterator который говорит куда мы добавляем вновь
созданый сокет.
454 Прочтений • [Реализация multithreaded сервера на C++ (threads linux mutex)] [08.05.2012] [Комментариев: 0]