我使用Indy与C++ Builder XE3。这是一个完美的系统,但我有一些问题。IdTCPServer运行得很好,但是当我在他身上有一些连接,并且我想要停止服务器时,我的应用程序就会冻结。我试着一步一步地讲述我是如何做到的: 1)启动应用程序(和服务器侦听) 2)等待新连接(或模拟它,没有区别) 3)当我们有10-15个连接时,然后尝试停止服务器侦听。4)当代码到达IdTCPServer1 1->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;
}
谢谢你的建议!
发布于 2013-02-08 12:48:17
除了最后一行之外,您需要删除所有的StopServer()
代码。当TIdTCPServer
被停用时,它会为您执行所有必要的清理。不要自己做(特别是因为你做错了)。
void TForm1::StopServer()
{
IdTCPServer1->Active = false;
}
现在,只要有了这些代码,如果你的应用程序还在冻结,那就意味着你的主线程是死锁的。如果在主线程的上下文中调用StopServer()
,并且服务器代码中有两种情况之一,则会发生这种情况:
TIdTCPServer
事件处理程序之一对主线程执行同步操作(通过TIdSync
或TThread::Synchronize()
)。TIdTCPServer
事件处理程序之一吞噬了Indy异常,并且不允许TIdTCPServer
在需要时正确终止一个或多个客户端线程。在内部,TIdTCPServer::Active
属性设置程序关闭所有活动的套接字并等待它们各自的线程完全终止,阻塞调用线程直到属性集退出。如果yoou在主线程中使服务器失活,而其中一个服务器线程执行主线程不能处理的同步,或者在应该时不正确终止同步,则将阻止服务器失活,从而导致主线程死锁。
所以要确保:
EIdException
块中吞咽任何Indy -derived异常。如果你捕捉到这样的异常,当你发现使用它时,重新抛出它。让TIdTCPServer
处理任何Indy异常,这样它就可以根据需要执行内部清理。最后,附带说明,您不需要手动跟踪连接。TIdTCPServer
已经在Contexts
属性中为您执行了此操作。如果您需要知道当前有多少客户机在任何时候连接,只需Lock()
Contexts
列表,读取其Count
属性(或对客户端执行其他需要做的任何事情),然后对列表进行Unlock()
。
https://stackoverflow.com/questions/14780792
复制相似问题