2010-03-21 104 views
0

我會嘗試用最短的單詞來解釋問題。我使用C++ Builder的,我使用TIdTCPServer 2010異常斷開的TCP套接字和寫入超時

和發送語音包連接的客戶端列表。一切正常,直到任何客戶端異常斷開,例如電源故障等。我可以通過切斷連接的客戶端的以太網連接來重現類似的斷開連接。

所以現在我們有一個斷開插座但你知道它尚未在服務器端檢測到這樣的服務器將繼續嘗試將數據發送到客戶端了。

但是,當服務器嘗試寫入數據到該斷開連接的客戶端...... Write()或WriteLn()HANGS在嘗試寫入時,它就像是爲某種Write超時寫入數據。這會掛起分組分發過程,從而導致向所有其他客戶端的數據傳輸發生滯後。幾秒鐘後「套接字連接關閉」引發異常並繼續數據流。

下面是代碼

try 
{ 
EnterCriticalSection(&SlotListenersCriticalSection); 
for(int i=0;i<SlotListeners->Count;i++) 
{ 
    try 
    { 

     //Here the process will HANG for several seconds on a disconnected socket 
     ((TIdContext*) SlotListeners->Objects[i])->Connection->IOHandler->WriteLn("Some DATA"); 

    }catch(Exception &e) 
    { 
    SlotListeners->Delete(i); 
    } 
} 
}__finally 
{ 
LeaveCriticalSection(&SlotListenersCriticalSection); 
} 

好吧,我已經有一個保持其閒置n秒後斷開插座活動的機制。但是,正如你可以想象的那樣,這個機制仍然無法與這個braodcasting循環完全同步,因爲這個braodcasting循環幾乎總是在運行。

那麼,有沒有寫超時我可以指定可能通過iohandler什麼?我見過很多關於「檢測斷開的TCP套接字」的線程,但我的問題有點不同,我需要在寫入嘗試期間避免幾秒鐘的掛斷。

那麼有沒有解決方案?

或者我應該考慮使用這樣的數據廣播例如一些不同的機制廣播循環把數據包在某種FIFO緩衝器和客戶端線程的連續檢查可用的數據並挑選並將其交付給自己?這樣,如果一個線程掛起,它不會停止/延遲整個分發線程。

有什麼想法嗎?感謝您的時間和幫助。

問候

卡紙

回答

0

有在印地實現沒有寫超時。爲此,您將不得不使用TIdSocketHandle.SetSockOpt()方法直接設置套接字級超時。

FIFO緩衝器是一個更好的選擇(和一般的一個更好的設計)。例如:

void __fastcall TForm1::IdTCPServer1Connect(TIdContext *AContext) 
{ 
    ... 
    AContext->Data = new TIdThreadSafeStringList; 
    ... 
} 

void __fastcall TForm1::IdTCPServer1Disconnect(TIdContext *AContext) 
{ 
    ... 
    delete AContext->Data; 
    AContext->Data = NULL; 
    ... 
} 

void __fastcall TForm1::IdTCPServer1Execute(TIdContext *AContext) 
{ 
    TIdThreadSafeStringList *Queue = (TIdThreadSafeStringList*) AContext->Data; 
    TStringList *Outbound = NULL; 
    TStringList *List = Queue->Lock(); 
    try 
    { 
     if(List->Count > 0) 
     { 
      Outbound = new TStringList; 
      Outbound->Assign(List); 
      List->Clear(); 
     } 
    } 
    __finally 
    { 
     Queue->Unlock(); 
    } 

    if(Outbound) 
    { 
     try 
     { 
      AContext->Connection->IOHandler->Write(Outbound); 
     } 
     __finally 
     { 
      delete Outbound; 
     } 
    } 

    ... 
} 

... 

try 
{ 
    EnterCriticalSection(&SlotListenersCriticalSection); 
    int i = 0; 
    while(i < SlotListeners->Count) 
    { 
     try 
     { 
      TIdContext *Ctx = (TIdContext*) SlotListeners->Objects[i]; 
      TIdThreadSafeStringList *Queue = (TIdThreadSafeStringList*) Ctx->Data; 
      Queue->Add("Some DATA"); 
      ++i; 
     } 
     catch(const Exception &e) 
     { 
      SlotListeners->Delete(i); 
     } 
    } 
} 
__finally 
{ 
    LeaveCriticalSection(&SlotListenersCriticalSection); 
}