2013-02-08 2 views
0

Я использую Indy с C++ Builder XE3. Это идеальная система, но у меня есть некоторые проблемы. IdTCPServer работает очень хорошо, но когда у меня есть некоторые подключения к нему, и я хочу остановить сервер, тогда мое приложение застыло. Я пытаюсь сказать, как это делается шаг за шагом: 1) Запуск приложения (и прослушивания сервера) 2) дождитесь новых подключений (или имитируйте его, без разницы) 3) когда у нас 10-15 соединений - затем попробуйте чтобы остановить прослушивание сервера. 4) когда код пришел в IdTCPServer1-> Active = false - приложение будет замороженоIndy10 TCP Server Freezing

Я сделал небольшое видео. Возможно, это объясняет ситуацию намного лучше. 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; 
} 

Спасибо за посоветуйте!

ответ

1

Вам необходимо избавиться от всего вашего кода StopServer(), за исключением последней строки. Когда TIdTCPServer деактивирован, он выполняет все необходимые очистки для вас. НЕ ДЕЛАЙТЕ СВОЮ СЕБЯ (тем более, что вы все равно ошибаетесь).

void TForm1::StopServer() 
{ 
    IdTCPServer1->Active = false; 
} 

Теперь, только с этим кодом, если ваше приложение еще замораживанием, то это означает, что вы запирание основного потока. Это происходит, если вы звоните StopServer() в контексте главного потока и одна из двух вещей происходят в вашем коде сервера:

  1. один из ваших TIdTCPServer обработчиков событий выполняет синхронную работу в основной поток (через TIdSync или TThread::Synchronize()).

  2. один из ваших обработчиков событий TIdTCPServer проглатывает исключения Indy и не позволяет TIdTCPServer прекратить один или несколько потоков клиентов правильно, когда это необходимо.

Внутри TIdTCPServer::Active свойство сеттера закрывает все активные сокетов и ожидает их соответствующие потоки, чтобы полностью прекратить, не блокируют вызывающий поток до выходов свойства инкубационных. Если вы деактивируете сервер в основном потоке, а один из потоков сервера выполняет синхронизацию, которую основной поток не может обработать, или, иначе, не будет корректно завершен, когда это произойдет, что заблокирует деактивацию сервера от выхода и, таким образом, блокирует основной нить.

Поэтому убедитесь, что:

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

  2. Ваши обработчики событий не проглатывают ни один Indy EIdException -определенные исключения в try/catch блоки. Если вы поймаете такое исключение, повторно бросьте его, когда вы его используете. Пусть TIdTCPServer обрабатывает любые исключения Indy, поэтому при необходимости может выполнять внутреннюю очистку.

Наконец, на боковой ноте вам не нужно отслеживать соединения вручную. TIdTCPServer уже делает это для вас в Contexts. Если вам нужно знать, сколько клиентов в данный момент подключено, просто Lock() список Contexts, ознакомьтесь с его Count (или сделайте что-нибудь еще, что вам нужно сделать с клиентами), а затем Unlock() списка.