2

できるだけ短い言葉で問題を説明しようと思います。C++ ビルダー 2010 を使用しています。

TIdTCPServer を使用して、接続されているクライアントのリストに音声パケットを送信しています。クライアントが異常に切断されるまで、すべて正常に機能します。たとえば、電源障害などです。接続されているクライアントのイーサネット接続を切断することで、同様の切断を再現できます。

これでソケットが切断されましたが、サーバー側ではまだ検出されていないため、サーバーは引き続きそのクライアントにもデータを送信しようとします。

しかし、サーバーがその切断されたクライアントにデータを書き込もうとすると...... Write() または WriteLn() は、書き込みを試みる際にそこにハングアップし、ある種の書き込みタイムアウトを待っているようです。これにより、ホール パケットの配布プロセスが停止し、その結果、他のすべてのクライアントへのデータ送信に遅延が生じます。数秒後、「Socket Connection Closed」例外が発生し、データ フローが続行されます。

ここにコードがあります

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秒間非アクティブの後にソケットを切断するキープアライブメカニズムを持っています。しかし、ご想像のとおり、このブロードキャスト ループはほぼ常に実行されているため、このメカニズムはこのブロードキャスト ループと正確に同期できません。

それで、iohandlerなどを介して指定できる書き込みタイムアウトはありますか?「切断された tcp ソケットの検出」に関する多くのスレッドを見てきましたが、私の問題は少し異なります。書き込み試行中に数秒間そのハングアップを回避する必要があります。

解決策はありますか?

または、そのようなデータブロードキャストに別のメカニズムを使用することを検討する必要がありますか?たとえば、ブロードキャストループはデータパケットをある種の FIFO バッファーに入れ、クライアントスレッドは利用可能なデータを継続的にチェックし、それを選択して自分自身に配信しますか? このようにして、1 つのスレッドがハングしても、分散スレッド全体を停止/遅延させることはありません。

アイデアはありますか?お時間をいただきありがとうございます。

よろしく

ジャム

4

1 に答える 1

1

Indyには書き込みタイムアウトは実装されていません。そのためには、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); 
} 
于 2010-04-14T20:24:51.020 に答える