2010-03-21 4 views
0

Je vais essayer d'expliquer le problème dans les mots les plus courts possibles. J'utilise C++ builder 2010.Sockets TCP anormalement déconnectés et timeout d'écriture

J'utilise TIdTCPServer et j'envoie des paquets vocaux à une liste de clients connectés. Tout fonctionne bien jusqu'à ce que tout client soit déconnecté anormalement, par exemple panne de courant, etc. Je peux reproduire une déconnexion similaire en coupant la connexion ethernet d'un client connecté. Donc maintenant nous avons un socket déconnecté mais comme vous le savez il n'est pas encore détecté côté serveur donc le serveur continuera à essayer d'envoyer des données à ce client aussi.

Mais quand le serveur essaye d'écrire des données sur ce client déconnecté ...... Write() ou WriteLn() HANGS là en essayant d'écrire, C'est comme si ça valait pour quelque chose de Write Timeout. Cela bloque le processus de distribution des paquets de trous, ce qui crée un retard dans la transmission des données à tous les autres clients. Après quelques secondes "Socket Connection Closed" L'exception est levée et le flux de données continue.

Voici le code

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); 
} 

Ok je l'ai déjà un mécanisme de garder en vie qui débrancher la prise au bout de n secondes d'inactivité. Mais comme vous pouvez l'imaginer, ce mécanisme ne peut pas être synchronisé exactement avec cette boucle de diffusion, car cette boucle de diffusion est presque toujours active.

Alors, y a-t-il des délais d'écriture que je peux spécifier peut être par iohandler ou quelque chose? J'ai vu beaucoup de discussions sur "Détection de socket tcp déconnecté" mais mon problème est un peu différent, j'ai besoin d'éviter ce blocage pendant quelques secondes au cours de la tentative d'écriture.

Y a-t-il une solution? Ou devrais-je envisager d'utiliser un mécanisme différent pour cette diffusion de données, par exemple la boucle de diffusion place le paquet de données dans une sorte de tampon FIFO et les threads client vérifient en permanence les données disponibles et se les ramènent? De cette façon, si un thread se bloque, il n'arrêtera/retardera pas le thread de distribution.

Des idées s'il vous plaît? Merci pour votre temps et votre aide.

Cordialement

Confitures

Répondre

0

Il n'y a pas les délais d'attente d'écriture mises en œuvre dans Indy. Pour cela, vous devrez utiliser la méthode TIdSocketHandle.SetSockOpt() pour définir les délais d'attente au niveau du socket directement.

Le tampon FIFO est une meilleure option (et une meilleure conception en général). Par exemple:

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); 
}