2013-02-08 116 views
0

我使用Indy與C++ Builder XE3。這是完美的系統,但我有一些問題。 IdTCPServer的工作非常好,但是當我有一些他的連接,我想停止服務器,然後我的應用程序凍結。我試着告訴我該怎麼做一步一步來: 1)啓動應用程序(和服務器偵聽) 2)等待新的連接(或模擬它,沒有區別) 3)當我們有10-15個連接 - 然後再嘗試停止服務器偵聽。 4)當代碼來到IdTCPServer1->活動=假 - 應用程序將被凍結Indy10 TCP服務器凍結

我做了小視頻。也許它更好地解釋情況。 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一個事件處理程序進行同步操作的主線程(通過TIdSyncTThread::Synchronize())。

  2. 您的TIdTCPServer事件處理程序中的一個會吞服Indy異常,並且不允許TIdTCPServer在需要時正確終止一個或多個客戶機線程。

內部,TIdTCPServer::Active屬性setter關閉所有活動插座,並等待各自的線程完全終止,阻塞調用線程,直到屬性setter退出。如果您在主線程中停用了服務器,並且其中一個服務器線程執行了主線程無法處理的同步,或者在其它情況下未正確終止,則會阻止服務器停用退出並因此導致主線。

所以要確保:

  1. ,而服務器是由主線程激活你是不是在主線程中執行同步操作。如果您必須同步,請在工作線程中取消激活服務器,以便主線程不會再被阻止。

  2. 您的事件處理程序不try/catch塊吞嚥任何印EIdException派生例外。如果你發現了這樣的例外情況,那麼在你使用它時要重新扔掉它。讓TIdTCPServer處理任何Indy異常,以便根據需要執行內部清理。

最後,在旁註中,您不需要手動跟蹤連接。 TIdTCPServer已經爲您在Contexts屬性中爲您做了這件事。如果您需要知道當前有多少客戶端正在連接,只需簡單地Lock()Contexts列表,閱讀其Count屬性(或者執行其他任何與客戶端有關的操作),然後再使用Unlock()列表。