今天我遇到了一个奇怪的行为,使用Indy 10(随Delphi 2010一起发布)。这里的问题是:当客户端连接到Indy的服务器时,为什么IOHandler.ReadStream会阻塞线程?
假设我们有我们的客户端IdTcpClient,并在我们的服务器应用程序一个IdTcpServer,而这些代码OnExecute事件处理程序为我们IdTcpServer:
procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
var
AStream: TStringStream;
S: string;
begin
AStream := TStringStream.Create;
try
AContext.Connection.IOHandler.ReadStream(AStream);
S := AStream.DataString;
finally
AStream.Free;
end;
end;
现在,客户端时尝试使用TIdTcpClient.Connect连接到服务器;在服务器上,调用TIdTcpServer.OnExecute,并在执行达到AContext.Connection.IOHandler.ReadStream(AStream)行时阻塞在OnExecute事件处理程序内运行的线程!
当我跟踪代码时,在ReadStream中调用ReadLongInt以获取字节数时会导致问题。 ReadLongInt调用ReadBytes。在ReadBytes内部,FInputBuffer.Size为零。在那里,在一个循环中调用ReadFromSource,并最终执行到达TIdSocketListWindows.FDSelect,它从WinSock2中调用“select”函数,并在此停止执行,并且不会从该客户端连接收到任何内容。我试着给AByteCount和AReadUntilDisconnect参数赋予值,但它没有改变行为。
如果我将ReadStream替换为ReadLn,则连接到服务器不会阻止代码执行,并且客户端发送的数据被服务器读取。
代码有问题吗?或者这是一个错误?
问候
感谢您的描述。在Indy文档中提到,如果AByteCount为-1且AReadUntilDisconnect为False,则字节数将从IOHandler读取为整数,但我不知道它将从接收数据的前4个或8个字节中读取。我认为当AReadUntilDisconnect为False且AByteCount为-1时,只要输入缓冲区中存在某些内容,ReadStream就会读取。无论如何,再次感谢您的帮助。 – vcldeveloper 2010-07-27 13:58:36
所有的IOHandler的读取方法只从InputBuffer获取数据。其他方法在内部调用的ReadBytes()方法确保InputBuffer对每个读操作都有足够的可用字节。如果InputBuffer已经有4个字节,那么ReadStream()会按原样接收它们。如果InputBuffer还没有4个字节,ReadBytes()可以确保它的确如此,然后ReadStream()从InputBuffer接收它们。无论哪种方式,所有数据都会根据需要从套接字进入InputBuffer到每个读取方法。 – 2010-07-27 20:31:08