Я использовал Indy с C ++ Builder XE3. Это идеальная система, но у меня есть некоторые проблемы. IdTCPServer работает очень хорошо, но когда у меня есть несколько подключений к нему, и я хочу остановить сервер, мое приложение зависло. Я пытаюсь рассказать, как я делаю это шаг за шагом:
1) Запуск приложения (и прослушивание сервера)
2) дождаться новых подключений (или смоделировать, без разницы)
3) когда у нас 10-15 подключений — попробуйте остановить прослушивание сервера.
4) когда код пришел к IdTCPServer1-> Active = false — приложение будет заморожено
Я сделал небольшое видео. Может быть, это объясняет ситуацию намного лучше. http://www.youtube.com/watch?v=BNgTxYbLx8g
И вот мой код:
OnConnect:
EnterCriticalSection(&CritLock);
++ActiveConnections;
SetActiveConnections(ActiveConnections);
LeaveCriticalSection(&CritLock);
OnDisconnect:
EnterCriticalSection(&CritLock);
--ActiveConnections;
SetActiveConnections(ActiveConnections);
LeaveCriticalSection(&CritLock);
Код StopServer:
void TForm1::StopServer()
{
TList *list = IdTCPServer1->Contexts->LockList();
try
{
for(int i = 0; i < list->Count; ++i)
{
TIdContext *AContext = reinterpret_cast<TIdContext*>(list->Items[i]);
try
{
if (AContext->Connection->Connected())
{
AContext->Connection->IOHandler->InputBuffer->Clear();
AContext->Connection->IOHandler->WriteBufferCancel();
AContext->Connection->IOHandler->WriteBufferClear();
AContext->Connection->IOHandler->WriteBufferClose();
AContext->Connection->IOHandler->CloseGracefully();
AContext->Connection->Disconnect();
}
}
catch (const Exception &e)
{
}
}
}
__finally
{
IdTCPServer1->Contexts->UnlockList();
}
IdTCPServer1->Contexts->Clear();
//IdTCPServer1->StopListening();
IdTCPServer1->Active = false;
}
Спасибо за совет!
Вам нужно избавиться от всех ваших StopServer()
код, за исключением самой последней строки. когда TIdTCPServer
деактивирован, он выполняет все необходимые очистки для вас. НЕ ДЕЛАЙТЕ ЭТОГО СЕБЯ (тем более, что ты все равно делаешь неправильно).
void TForm1::StopServer()
{
IdTCPServer1->Active = false;
}
Теперь, имея только этот код, если ваше приложение все еще зависает, это означает, что вы блокируете основной поток. Это произойдет, если вы позвоните StopServer()
в контексте основного потока и одна из двух вещей происходит в коде вашего сервера:
один из ваших TIdTCPServer
Обработчики событий выполняют синхронизированную операцию с основным потоком (либо через TIdSync
или же TThread::Synchronize()
).
один из ваших TIdTCPServer
обработчики событий проглатывает Indy исключения и не позволяет TIdTCPServer
правильно завершить один или несколько клиентских потоков при необходимости.
Внутренне TIdTCPServer::Active
установщик свойств закрывает все активные сокеты и ожидает полного завершения их соответствующих потоков, блокируя вызывающий поток до выхода из установщика свойства. Если вы деактивируете сервер в главном потоке, и один из потоков сервера выполняет синхронизацию, которую основной поток не может обработать, или иначе не завершается корректно, когда это должно быть, это заблокирует деактивацию сервера от выхода и, таким образом, заблокирует основной нить.
Поэтому убедитесь, что:
Вы не выполняете операции синхронизации с основным потоком, пока сервер отключается основным потоком. Если вам необходимо выполнить синхронизацию, то деактивируйте сервер в рабочем потоке, чтобы основной поток больше не блокировался.
ваши обработчики событий не глотают инди EIdException
исключения в try/catch
блоки. Если вы поймали такое исключение, перебросьте его, когда вы закончите, используя его. Позволять TIdTCPServer
обрабатывать любые исключения Indy, чтобы он мог выполнять внутреннюю очистку по мере необходимости.
Наконец, отметим, что вам не нужно отслеживать соединения вручную. TIdTCPServer
уже делает это для вас в Contexts
имущество. Если вам нужно знать, сколько клиентов в данный момент подключено, просто Lock()
Contexts
список, прочитайте его Count
собственности (или делать что-либо еще, что вам нужно сделать с клиентами), а затем Unlock()
список.
Других решений пока нет …