我有一个使用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()
的调用中,并且我很确定它正在发生,因为单个端口的另一端没有从套接字读取响应
从另一端重置端口后,工作线程解冻,并继续按预期工作。
我从雷米·勒博(Remy Lebeau)找到this answer到问题Delphi (Indy) Server Freezing on Write,他在评论中提到了我(强调我的意思):
Indy使用阻塞套接字,因此如果客户端未从其一端读取入站数据,则最终套接字的内部发送缓冲区将被填满,套接字将在服务器端被阻塞,等待客户端清空缓冲区。 在这种情况下避免死锁的唯一方法是直接使用套接字API设置套接字级别的发送超时。 Indy并未在其逻辑中实现发送超时。
我正在寻找通过INDY或通过Windows中的直接API调用来设置超时的正确方法,但是我陷入其中,所以我来这里寻求帮助。
如果这不可能,我可以在辅助线程上实现超时机制,但是我不确定从此辅助线程进行重置连接的正确方法是什么,以便让辅助线程继续工作。
答案 0 :(得分:4)
我正在寻找通过INDY或通过Windows中的直接API调用来设置该超时的正确方法
在我的previous comment中,当我说“直接使用套接字API设置套接字级别的发送超时”时,我是通过setsockopt()
函数引用SO_SNDTIMEO
套接字选项的。
就印地语而言,您可以使用setsockopt()
方法来调用TIdSocketHandle.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
属性是在TIdIOHandlerSocket
被分配了TIdTCPConnection.IOHandler
或其后代时访问TIdIOHandlerSocket
的简写)。
仅知道如果发生超时,您将无法确切知道实际将哪些数据传输给对等方,因此在大多数协议中通常都无法恢复。您真正要做的就是关闭连接并重新连接。