0

私はC++BuilderXE3でIndyを使用しています。それは完璧なシステムですが、私はいくつかの問題を抱えています。IdTCPServerは非常にうまく機能しますが、彼にいくつかの接続があり、サーバーを停止したい場合、アプリケーションがフリーズしました。私はそれをどのように行うかを段階的に説明しようとしています:1)アプリケーションを起動する(そしてサーバーをリッスンする)2)新しい接続を待つ(またはシミュレートする、違いはない)3)接続が10〜15になったらサーバーを停止してみてください聞いている。4)コードがIdTCPServer1-> Active=falseに到達したとき-アプリケーションはフリーズします

私は小さなビデオを作りました。多分それは状況をはるかによく説明します。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;
}

アドバイスありがとうございます!

4

1 に答える 1

1

StopServer()最後の行を除いて、すべてのコードを削除する必要があります。がTIdTCPServer非アクティブ化されると、必要なすべてのクリーンアップが実行されます。 自分でやらないでください(特に、とにかく間違っているので)。

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

このコードだけでも、アプリがまだフリーズしている場合は、メイン スレッドがデッドロックしていることを意味します。StopServer()これは、メイン スレッドのコンテキストで呼び出し、サーバー コードで次の 2 つのいずれかが発生している場合に発生します。

  1. イベント ハンドラーの 1 つはTIdTCPServer、メイン スレッドに対して同期操作を実行します ( または を介し​​てTIdSync) TThread::Synchronize()

  2. イベント ハンドラーの 1 つがIndy 例外を飲み込み、必要なときに 1 つ以上のクライアント スレッドを正しく終了TIdTCPServerできません。TIdTCPServer

内部的には、TIdTCPServer::Activeプロパティ セッターはすべてのアクティブなソケットを閉じ、それぞれのスレッドが完全に終了するのを待って、プロパティ セッターが終了するまで呼び出し元のスレッドをブロックします。メイン スレッドでサーバーを非アクティブ化しているときに、サーバー スレッドの 1 つがメイン スレッドが処理できない同期を実行した場合、または正常に終了しない場合、サーバーの非アクティブ化の終了がブロックされ、メイン スレッドがデッドロックします。スレッド。

したがって、次のことを確認してください。

  1. サーバーがメイン スレッドによって非アクティブ化されている間は、メイン スレッドに対して同期操作を実行していません。同期する必要がある場合は、代わりにワーカー スレッドでサーバーを非アクティブ化して、メイン スレッドがブロックされないようにします。

  2. イベント ハンドラーは、ブロック内の IndyEIdException派生例外を飲み込んでいません。try/catchこのような例外をキャッチした場合は、使用が終了したときに再度スローします。IndyTIdTCPServer例外を処理して、必要に応じて内部クリーンアップを実行できるようにします。

最後に、接続を手動で追跡する必要はありません。 TIdTCPServerすでにContextsプロパティでそれを行っています。現時点で現在接続されているクライアントの数を知る必要がある場合は、単純Lock()Contextsリストを参照し、そのプロパティを読み取りCount(または、クライアントに対して必要な他の操作を行います)、次にUnlock()リストを参照します。

于 2013-02-08T20:48:17.283 に答える