0

我将 Indy 与 C++ Builder XE3 一起使用。这是完美的系统,但我有一些问题。IdTCPServer 工作得非常好,但是当我与他有一些连接并且我想停止服务器时,我的应用程序就冻结了。我试着一步一步告诉我是怎么做的:1)启动应用程序(和服务器监听)2)等待新连接(或模拟它,没有区别)3)当我们有10-15个连接时 - 然后尝试停止服务器听。4) 当代码到达 IdTCPServer1->Active = false - 应用程序将被冻结

我做了小视频。也许它更好地解释了情况。http://www.youtube.com/watch?v=BNgTxYbLx8g

这里是我的代码:

连接:

EnterCriticalSection(&CritLock);
++ActiveConnections;
SetActiveConnections(ActiveConnections);
LeaveCriticalSection(&CritLock);

断开连接:

EnterCriticalSection(&CritLock);
--ActiveConnections;
SetActiveConnections(ActiveConnections);
LeaveCriticalSection(&CritLock);

停止服务器代码:

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()在主线程的上下文中调用并且在您的服务器代码中发生以下两种情况之一,则会发生这种情况:

  1. 您的TIdTCPServer事件处理程序之一对主线程执行同步操作(通过TIdSyncTThread::Synchronize())。

  2. 您的TIdTCPServer事件处理程序之一会吞下 Indy 异常,并且不允许TIdTCPServer在需要时正确终止一个或多个客户端线程。

在内部,TIdTCPServer::Active属性设置器关闭所有活动套接字并等待它们各自的线程完全终止,阻塞调用线程直到属性设置器退出。如果您在主线程中停用服务器,并且其中一个服务器线程执行了主线程无法处理的同步,或者在应该停止时没有正确终止,这将阻止服务器停用退出并因此死锁主线程线。

因此,请确保:

  1. 当服务器被主线程停用时,您没有对主线程执行同步操作。如果您必须同步,则改为在工作线程中停用服务器,以便不再阻塞主线程。

  2. 您的事件处理程序不会在块中吞下任何 IndyEIdException派生的异常。try/catch如果你捕捉到这样的异常,当你用完它时重新抛出它。让我们TIdTCPServer处理任何 Indy 异常,以便它可以根据需要执行内部清理。

最后,附带说明一下,您不需要手动跟踪连接。 TIdTCPServer已经在Contexts酒店内为您做到了。如果您需要知道当前连接了多少客户端,只需Lock()列出Contexts列表,读取其Count属性(或对客户端执行任何其他操作),然后Unlock()查看列表。

于 2013-02-08T20:48:17.283 回答