【问题标题】:Delphi 2009, Indy 10, TIdTCPServer.OnExecute, how to grab all the bytes in the InputBufferDelphi 2009,Indy 10,TIdTCPServer.OnExecute,如何抓取InputBuffer中的所有字节
【发布时间】:2010-10-07 08:24:08
【问题描述】:

我正在搞乱 Delphi 2009 提供的 Indy 10,并且在 OnExecute 触发时无法从 IOHandler 获取所有数据...

procedure TFormMain.IdTCPServerExecute(AContext: TIdContext);
var
  RxBufStr: UTF8String;
  RxBufSize: Integer;
begin

  if AContext.Connection.IOHandler.Readable then
  begin
    RxBufSize := AContext.Connection.IOHandler.InputBuffer.Size;
    if RxBufSize > 0 then
    begin
      SetLength(RxBufStr, RxBufSize);
      AContext.Connection.IOHandler.ReadBytes(TBytes(RxBufStr), RxBufSize, False);
    end;
  end;

end;

AContext.Connection.IOHandler.InputBuffer.Size 似乎不可靠并且经常返回 0,但在下次通过 OnExecute 运行时,它会获取正确数量的字节,但为时已晚。

基本上我希望能够抓取所有数据,将其填充到 UTF8String(不是 Unicode 字符串)中,然后解析特殊标记。所以我没有标题,消息是可变长度的。似乎 Indy 10 IOHandlers 没有为此设置,或者我只是用错了。

最好做一些事情,比如传递一个特定大小的缓冲区,尽可能多地填充它,然后返回实际填充的字节数,如果还有更多,就继续。

顺便说一句,TIdSchedulerOfFiber 的状态如何,这看起来很有趣,它有效吗?有人在用吗?我注意到它不在 Delphi 2009 的标准安装中。

更新: 我找到了 Msg := AContext.Connection.IOHandler.ReadLn(#0, enUTF8);哪个可行,但我仍然想知道上述问题的答案,是因为它是基于阻塞IO的吗?这使得 TIdSchedulerOfFiber 更加热衷。

【问题讨论】:

    标签: delphi delphi-2009 indy


    【解决方案1】:

    您不应该那样使用 Readable()。请尝试以下方法:

    procedure TFormMain.IdTCPServerExecute(AContext: TIdContext);
    var
      RxBuf: TIdBytes;
    begin
      RxBuf := nil;
      with AContext.Connection.IOHandler do
      begin
        CheckForDataOnSource(10);
        if not InputBufferIsEmpty then
        begin
          InputBuffer.ExtractToBytes(RxBuf);
          // process RxBuf as needed...
        end;
      end;
    end;
    

    或者:

    procedure TFormMain.IdTCPServerExecute(AContext: TIdContext);
    var
      RxBufStr: String; // not UTF8String
    begin
      with AContext.Connection.IOHandler do
      begin
        CheckForDataOnSource(10);
        if not InputBufferIsEmpty then
        begin
          RxBufStr := InputBuffer.Extract(-1, enUtf8);
    
          // Alternatively to above, you can set the
          // InputBuffer.Encoding property to enUtf8
          // beforehand, and then call TIdBuffer.Extract()
          // without any parameters.
          //
          // Or, set the IOHandler.DefStringEncoding
          // property to enUtf8 beforehand, and then
          // call TIdIOHandler.InputBufferAsString()
    
          // process RxBufStr as needed...
        end;
      end;
    end;
    

    至于 TIdSchedulerOfFiber - SuperCore 包此时实际上已失效。它已经很长时间没有工作了,并且没有与最新的 Indy 10 架构保持同步。我们可能会尝试在以后恢复它,但这不在我们近期的计划中。

    【讨论】:

    • 上面的代码似乎一直在运行 OnExecute 循环,我认为这是设计使然,通常用户会想要一个阻塞的 Readln;或类似的?还有一个遗憾的是 TIdSchedulerOfFiber 没有在开发中,是否有关于它的开发的阻碍?
    • 是的,按设计,OnExecute 事件由 TIdTCPServer 自动循环。 CheckForDataOnSource() 的超时参数有助于防止调用线程在没有数据可用的空闲期间耗尽所有 CPU 周期。
    • CheckForDataOnSource() 不会查看 InputBuffer 中是否已经有数据。它直接进入插座。如果它返回 False,则套接字中没有待处理的数据。
    • 使用 CheckForDataOnSource() 的最佳方法是仅在 InputBuffer 为空时调用它,而不是无条件地在每个循环迭代器上调用它。
    • @BenjaminWeiss:RxBuf 是编译器管理的动态数组,超出范围会自动释放。
    【解决方案2】:
    procedure TFormMain.IdTCPServerExecute(AContext: TIdContext); 
    var
      RxBufStr: UTF8String;
      RxBufSize: Integer;
    begin    
      if AContext.Connection.IOHandler.Readable then
      begin     
        AContext.Connection.IOHandler.ReadBytes(TBytes(RxBufStr),-1, False);
      end;
    end; 
    

    【讨论】:

    • 不要只发布一段代码,请解释为什么这段代码可以解决所提出的问题。没有解释,这不是答案。
    猜你喜欢
    • 2011-03-13
    • 2012-03-24
    • 1970-01-01
    • 2012-11-30
    • 1970-01-01
    • 2010-10-30
    • 1970-01-01
    • 1970-01-01
    • 2015-09-14
    相关资源
    最近更新 更多