我有一个使用 Indy 的客户端和服务器套接字应用程序,用 Delphi 10.2 编译。
应用程序有一个工作线程,用于处理来自不同端口的请求,并使用如下调用在同一线程内写入响应:
procedure TMyCommManager.WriteResponse(AHandler: TIdIOHandler; SomeData: SomeType);
var
idBytes: TidBytes;
PacketSize: Integer;
begin
SomeData.GetBytes(idBytes, PacketSize);
AHandler.Write(DataBuffer, PacketSize);
end;
几乎所有时间一切都按预期工作,但我们注意到工作线程在生产中不时卡住。经过各种迭代后,我们最终发现所有这些都发生在对 TidIOHandler.Write()
的调用中,我很确定它正在发生,因为单个端口的另一端是不读取套接字的响应。
从另一端重置端口后,工作线程解冻并继续按预期工作。
我找到了this answer来自 Remy Lebeau 的问题 Delphi (Indy) Server Freezing on Write ,他在评论中提到(强调我的):
Indy uses blocking sockets, so if the client is not reading inbound data on its end, eventually the socket's internal send buffer will fill up and the socket will become blocked on the server side waiting for the client to empty the buffer. The only way to avoid a deadlock in that scenario would be to set a socket-level send timeout using the socket API directly. Indy does not implement send timeouts in its logic.
我正在寻找设置超时的正确方法,通过 INDY 或通过 Windows 中的直接 API 调用,但我陷入困境,所以我来这里寻求帮助。
如果这是不可能的,我可以在辅助线程上实现超时机制,但我不确定重置我这边辅助线程的连接以让工作线程继续工作。
最佳答案
I'm looking for the correct way to set that timeout, via INDY or via a direct API call in Windows
在我的previous comment ,当我说“直接使用套接字 API 设置套接字级发送超时”时,我指的是通过 setsockopt()
的 SO_SNDTIMEO
套接字选项。功能。
对于Indy来说,可以通过TIdSocketHandle.SetSockOpt()
方法来调用setsockopt()
,例如:
// Windows
SomeConnection.Socket.Binding.SetSockOpt(Id_SOL_SOCKET, Id_SO_SNDTIMEO, TimeoutInMS);
// 'Nix
var tv: timeval;
...
SomeConnection.Socket.Binding.SetSockOpt(Id_SOL_SOCKET, Id_SO_SNDTIMEO, Integer(@timeval));
or:
GBSDStack.SetSocketOption(SomeConnection.Socket.Binding.Handle, Id_SOL_SOCKET, Id_SO_SNDTIMEO, timeval, sizeof(timeval));
(TIdTCPConnection.Socket
属性是当为 TIdTCPConnection.IOHandler
分配了 TIdIOHandlerSocket< 时访问
或后代)。TIdIOHandlerSocket
的简写
只要知道,如果确实发生超时,您就无法确切知道哪些数据实际传输到了对等方,因此在大多数协议(protocol)中恢复通常是不可能的。您真正能做的就是关闭连接并重新连接。
关于delphi - 如果另一端没有从套接字读取数据,如何避免在 Indy 中写入套接字时卡住,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56124201/