我是Delphi XE5的新手,主要使用VB.Net和某些Java。我正在尝试从传入的TCP连接中读取未知数量的字节,并且没有运气来研究如何确定要读取的输入缓冲区中有多少个字节。似乎我尝试的每种方法(即ReadBytes,ReadStream等)都要求我明确告诉他们要读取或阻止多少字节。我只需要一种方法来确定输入缓冲区中有多少个字节,以便可以使用ReadBytes例如读取它们。

begin
  Client.IOHandler.CheckForDataOnSource(300);
  if Not Client.IOHandler.InputBufferIsEmpty then
    Client.IOHandler.ReadBytes(rxBuf);
end;


为了避免这种情况发生,我需要提供输入缓冲区中的字节数,但是我无法确定如何执行此操作。我尝试了InputBuffer.Size,但是返回的数字比可能存在的大得多。

我现在尝试了以下方法:

begin
  if Client.IOHandler.InputBufferIsEmpty then
  begin
    Client.IOHandler.CheckForDataOnSource(1000);
    if Not Client.IOHandler.InputBufferIsEmpty then
    begin
      Client.IOHandler.InputBuffer.ExtractToBytes(rxBuf);
    end;
  end
  else
    Client.IOHandler.InputBuffer.ExtractToBytes(rxBuf);
end;


当我放置一个断点并逐步执行代码时,即使输入缓冲区中有数据,代码也会跳过ExtractToBytes并且rxBuf仍然为零。为什么?

我之前遗漏了一些代码。这就是全部。

while stop-start <MainForm.Timeout do
begin
  if Client.IOHandler.InputBufferIsEmpty then
  begin
    Client.IOHandler.CheckForDataOnSource(1000);
    stop := Ticks;
    if Not Client.IOHandler.InputBufferIsEmpty then
    begin
      Client.IOHandler.InputBuffer.ExtractToBytes(rxBuf);
      break;
    end;
  end
  else
    Client.IOHandler.InputBuffer.ExtractToBytes(rxBuf);
  break;
end;


我知道缓冲区中有数据,因为单步执行代码会中断。但是没有评估ExtractToBytes(rxBuf),也不知道为什么。

最佳答案

InputBuffer.SizeInputBuffer内存中物理上的实际字节数。它不能大于实际存储的大小。 InputBufferIsEmpty()只是返回是否为InputBuffer.Size > 0

begin
  if Client.IOHandler.InputBufferIsEmpty then
  begin
    Client.IOHandler.CheckForDataOnSource(1000);
    Client.IOHandler.CheckForDisconnect;
    if Client.IOHandler.InputBufferIsEmpty then Exit;
  end;
  Client.IOHandler.ReadBytes(rxBuf, Client.IOHandler.InputBuffer.Size);
end;


或者,无条件使用InputBuffer.ExtractToBytes()提取InputBuffer中当前存在的任何内容,即使它恰好为空:

begin
  if Client.IOHandler.InputBufferIsEmpty then
  begin
    Client.IOHandler.CheckForDataOnSource(1000);
    Client.IOHandler.CheckForDisconnect;
    if Client.IOHandler.InputBufferIsEmpty then Exit;
  end;
  Client.IOHandler.InputBuffer.ExtractToBytes(rxBuf);
end;


或者,您可以将-1传递给ReadBytes(),这告诉它返回InputBuffer中当前存在的内容(它将首先调用IOHandler.ReadFromSource()填充InputBuffer,然后再从中提取):

begin
  Client.IOHandler.ReadBytes(rxBuf, -1, False);
end;


更新:无论是否读取任何内容,循环都会调用break。那是你真正想要的吗?如果不是,那么您需要将最后一个break移到begin/end块中,以便仅在调用ExtractToBytes()时对其进行评估:

while GetTickDiff(start, Ticks) < MainForm.Timeout do
begin
  if Client.IOHandler.InputBufferIsEmpty then
  begin
    Client.IOHandler.CheckForDataOnSource(1000);
    if Not Client.IOHandler.InputBufferIsEmpty then
    begin
      Client.IOHandler.InputBuffer.ExtractToBytes(rxBuf);
      break;
    end;
  end
  else
  begin
    Client.IOHandler.InputBuffer.ExtractToBytes(rxBuf);
    break;
  end;
end;


在这种情况下,您可以稍微简化循环:

start := Ticks;
while Client.IOHandler.InputBufferIsEmpty do
begin
  if GetTickDiff(start, Ticks) >= MainForm.Timeout then Break;
  Client.IOHandler.CheckForDataOnSource(1000);
end;
Client.IOHandler.InputBuffer.ExtractToBytes(rxBuf);


在这种情况下,您可以完全摆脱循环,而只使用Indy自己的超时:

Client.IOHandler.CheckForDataOnSource(MainForm.Timeout);
Client.IOHandler.InputBuffer.ExtractToBytes(rxBuf);


要么:

Client.IOHandler.ReadTimeout := MainForm.Timeout;
Client.IOHandler.ReadBytes(rxBuf, -1, False);

关于delphi - Delphi IOHandler读取的未知字节数,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/21944160/

10-10 02:20