【问题标题】:Delphi IOHandler Read Unknown Number of BytesDelphi IOHandler 读取未知字节数
【发布时间】:2014-02-24 23:14:10
【问题描述】:

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

【问题讨论】:

    标签: delphi


    【解决方案1】:

    InputBuffer.SizeInputBuffer 内存中物理上的实际字节数。它不能大于实际存储的值。 InputBufferIsEmpty() 只返回 InputBuffer.Size &gt; 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);
    

    【讨论】:

      【解决方案2】:

      谢谢。我不明白的是,为什么如果输入缓冲区中有数据不会评估 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 进行评估。感谢您的意见,我会再尝试一下。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-04-05
        • 1970-01-01
        • 2011-08-07
        • 2012-12-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多