在 Indy TIdTCPServer 和 TIdTCPClient 中管理异常

Managing Exceptions in Indy TIdTCPServer and TIdTCPClient

在 Indy TIdTCPServer 和 TIdTCPClient 中管理异常

我在本论坛的其他 post 和其他地方读到,在 Indy 组件中,异常(来自 EIdException 的后代)是内部管理的。 因此,在 TCPServer Execute 方法中不需要使用 try - catch 块。 但是,如果在 TCPServer Execute 方法中出现另一种异常会怎样?

在我的服务器应用程序中,我在主窗体上放置了一个 TIdTCPServer 组件,如果在其 Execute 方法中发生错误并且我不管理它,服务器将停止。 显然我需要服务器 运行 所以我使用 try - catch 块,如果有异常(任何类型的异常),我重新启动服务器。 我不知道这是否是最好的做法。

有时,在 IDE 中使用服务器应用程序 运行,我得到错误

Project CallMonitor.exe raised exception class EIdSocketError with message 'Socket Error # 10054 - Connection reset by peer.'.

可能是由同一台计算机上的客户端 运行 引起的(不在 IDE 中)。 应用程序执行被阻止,如果我中断,代码将在 IdStack 文件中停止,那里有大的 READ ME!!!关于异常 10038。 我按 F9,应用程序继续 运行。

我不太清楚发生了什么。我的 try - catch 块在这种情况下有效吗?还是无用或有害? 我必须过滤 Indy 异常和其他异常?

在客户端,在我的应用程序中,主窗体中有一个 TIdTCPClient 对象,与服务器的连接在主线程中进行管理。然后还有另一个线程来管理与服务器的通信。在通信线程 Execute 方法中,我有一个 try - catch 块和一个循环,在该循环中,我每 2 秒或当用户请求数据时向服务器发送一个请求,然后我解码服务器答案。 如果出现 EIdReadTimeout 异常,我将终止线程并重新启动它。对于其他异常,我终止线程,disconnect/connect TIdTCPClient 并重新启动线程。

我认为这是一种不同的情况,因为在服务器中,异常是在 TIdTCPServer 线程中管理的,而在客户端中,异常是在仅使用 TCPClient->Socket 与服务器通信的线程中管理的,对吗?

任何 answer/comment/suggestion 不胜感激。

in the TCPServer Execute method there is no need to use a try - catch block. But what happens if in the TCPServer Execute method another kind of exception occurs?

允许从 OnConnectOnExecute 事件逃逸回 TIdTCPServer 的任何 未捕获异常将导致调用 TIdContext 线程停止 运行。它将在清理期间关闭其关联的客户端 Connection,触发 OnDisconnect 事件。然后 OnException 事件将在之后触发。

In my server application, I have put a TIdTCPServer component on the main form, if something bad happens inside its Execute method and I don't manage it, the server stops.

服务器整体不停机。只有调用 TIdContext 线程被停止。

Obviously I need the server running so I use a try - catch block and if there is an exception (any kind of exception), I restart the server.

没有必要在任何异常时重新启动整个服务器。仅在 invalidate/corrupt 您的应用正常运行所需的例外情况下。

Sometimes, with the server application running in the IDE, I got the error

Project CallMonitor.exe raised exception class EIdSocketError with message 'Socket Error # 10054 - Connection reset by peer.'.

这是一个完全正常的套接字错误。那不会杀死你的整个服务器。

如果您进入 IDE 的调试器设置,可以选择忽略 Indy“静默”异常(源自 EIdSilentException,例如 EIdConnClosedGracefully)。或者,您也可以告诉调试器忽略特定的异常类型,例如 EIdSocketError.

The application execution is blocked ... I press F9 and the application continues running.

没错。不是致命错误。阻塞仅在调试器中,它让您检查异常并决定如何处理它。

For me it is not very clear what happens. My try - catch block is effective in this situation?

IDE 调试器会先于您的代码捕获异常。当你按F9继续执行时,异常会传回你的代码,相应的catch会正常处理。

Or is it useless or harmful?

没有

I have to filter Indy exceptions and other exceptions?

IF 你捕获异常,处理你需要的异常,然后你应该 重新抛出任何特定于 Indy 的异常你捕获了(所有 Indy 异常都来自 EIdException 以便于识别),让服务器处理它们。如果不这样做,那么您 应该 自己断开调用 Connection 并优雅地退出事件处理程序。无论哪种方式,服务器都会根据需要清理其余部分。

On the client side, in my application there is a TIdTCPClient object in the main form and the connection to the server is managed in the main thread. Then there is another thread to manage communication with the server.

我也会将连接管理移到工作线程中。连接、通信、断开连接、必要时重复,都应该在一个线程中。

In the communication thread Execute method I have a try - catch block and a loop in which I send a request to the server every 2 seconds or when the user asks for data and I decode the server answer. If there is a EIdReadTimeout exception, i terminate the thread and I restart it.

如果实际读取操作超时,则通信状态未知且可能无法恢复,因为您不知道超时的是哪个字节。所以你应该断开并重新连接,而不仅仅是重新启动线程。唯一不需要完全重新连接的情况是,如果您正在处理消息之间的超时等待,并且 知道 通信没有被破坏。在这种情况下,简单地重新启动线程而不完全重新连接不太可能解决超时情况。重新尝试等待操作会更简单。

For other exception, I terminate the thread, I disconnect/connect the TIdTCPClient and I restart the thread.

如果将connect/disconnect逻辑移到线程中,它们可以在循环中完成,那么就不需要重新启动线程本身。线程对 create/destroy 来说很昂贵(从 OS 的角度来看),因此请尽可能重用线程。

I think this is a different situation because in the server the exception was managed inside the TIdTCPServer thread while in the client the exception is managed in a thread that just uses the TCPClient->Socket to communicate with the server, is it right?

是的。