Delphi IOHandler读取未知的字节数

时间:2014-02-21 20:05:46

标签: delphi

我是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)没有被评估,并且不知道为什么。

2 个答案:

答案 0 :(得分:4)

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()来填充{{} 1}}然后从中提取):

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;

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

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);

或者:

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

答案 1 :(得分:0)

谢谢。我不明白为什么如果输入缓冲区中有数据不能评估ExtractBytes?这是我试图实现的逻辑。我正在通过TCP与串行设备进行通信。我发送一个打开通信的字符,它会回复一些大小不一的信息。

// Stay in loop until a certain amount of time has passed with no data
// I understand I can use the timeout as well
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
            // If there is data in the buffer get it
            // But why is ExtractToBytes not evaluated
            Client.IOHandler.InputBuffer.ExtractToBytes(rxBuf);
            // I break the loop because I am assuming ExtractToBytes has been evaluated
            break;
          end;
      end
    else
      begin
      Client.IOHandler.InputBuffer.ExtractToBytes(rxBuf);
      break;
  end;

端;

我显然误解的是,由于输入缓冲区中存在数据,因此不一定会评估ExtractToBytes。感谢您的投入,我将继续使用它。