如何使用Delphi中的Indy Client从服务器读取所有字节?

时间:2012-12-12 11:48:53

标签: delphi delphi-xe2 indy indy10

我正在使用Indy客户端来读取服务器发送给我的消息(客户端)。它一次性向我发送512字节的数据。这512字节的数据由两种数据类型(Word和String)组成。例如,它发送2个字节的字,然后再发送2个字节的字,然后发送50个字节的字符串,依此类推。我正在尝试使用代码来解决这个问题:

var BufferArray : Array[0..512] of Byte;

 if IdTCPClient1.IOHandler.InputBufferIsEmpty then
 begin
      if IdTCPClient1.IOHandler.CheckForDataOnSource(1000) then
      begin
          Edit1.Text := idtcpclient1.IOHandler.ReadBytes(BufferArray ,512, true);
      end;
 end;

我在Edit1.Text上遇到错误:= idtcpclient1.IOHandler.ReadBytes(BufferArray,512,true);错误:实际和正式var参数的类型必须相同。

我使用的是正确的方法吗?我想在Edit1.Text上存储整个512字节,然后我将对该数据执行任何操作。请帮我从服务器获取所有512个字节。

更新:替代方法

我正在使用这种方法来读取单词和字符串值

WordArray : array[0..5] of word;

 if IdTCPClient1.IOHandler.InputBufferIsEmpty then
 begin
      if IdTCPClient1.IOHandler.CheckForDataOnSource(1000) then
      begin
        i := 0;
        while i < 6 do //Read all the words
        begin
            //Fill WORD data in array
            WordArray[i] :=  (IdTCPClient1.Socket.ReadWord(True));
        end;
      end;
end;

类似字符串的方法

WordArray [i]:=(IdTCPClient1.Socket.ReadString(50));

这很好用,但是当我读取循环中的所有数据时,我必须保持连接打开状态。如果在连接之间,我会丢失所有内容,并且必须再次从服务器请求整个包。

2 个答案:

答案 0 :(得分:1)

1:字符串的字符集是什么?它是1字节的windows-1251吗?或2字节Unicode UCS-2?或可变长度的UTF-8或UTF-16?

2:字符串的长度是多少?总是50?


阅读缓冲区:

  1. 阅读手册
    1.1 http://www.indyproject.org/docsite/html/TIdIOHandler_ReadBytes@TIdBytes@Integer@boolean.html
    1.2 http://www.indyproject.org/docsite/html/TIdIOHandler_ReadSmallInt@Boolean.html 1.3 http://docwiki.embarcadero.com/Libraries/XE2/en/System.SetString
  2. 准确地按照类型和参数说明制作代码 2.1阅读标题:这应该会产生类似

    的内容
    var  Word1, Word2: word;
    
    Word1 := IOHandler.ReadSmallInt(false);   
    Word2 := IOHandler.ReadSmallInt(false);
    
  3. 读取单字节字符串
    3.1阅读缓冲区
    3.2将缓冲区转换为字符串

    var  Word1, Word2: word;  Buffer: TIdBytes;    
    var s: RawByteString;     
     // or AnsiString; or maybe UTF8String; but probably not UnicodeString aka string
    
    Word1 := IOHandler.ReadSmallInt(false);   
    Word2 := IOHandler.ReadSmallInt(false);
    
    // You should check that you really received 50 bytes,
    // then do something like that:
    
    IOHandler.ReadBytes(Buffer, 50, false);    
    Assert(Length(Buffer)=50);    
    SetString (s, pointer(@Buffer[0]), 50);    
    
  4. 继续阅读其余内容 - 您只读取50 + 2 + 2 = 54字节的512字节数据包 - 应该有更多数据。

  5. 512 = 54 * 9 + 26 - 所以它可能看起来像一个循环 - 并丢弃26个字节的尾部。

        var Word1, Word2: word;  Buffer: TIdBytes;    
        var s: RawByteString;     
    
        for i := 1 to 9 do begin    
          Word1 := IOHandler.ReadSmallInt(false);     
          Word2 := IOHandler.ReadSmallInt(false);  
    
          IOHandler.ReadBytes(Buffer, 50, false);        
          Assert(Length(Buffer)=50);      
          SetString (s, pointer(@Buffer[0]), 50);    
    
          SomeOutputCollection.AppendNewElement(Word1, Word2, s);   
        end;   
        IOHandler.ReadBytes(Buffer, 512 - 9*(50+2+2), false); // discard the tail
    

答案 1 :(得分:1)

除非您准确描述您所拥有的文档中所写的内容,否则很难回答您。到目前为止,我们知道您的512B数据包由6个字和10x50B字符串组成。所以,以此为出发点,直到你告诉我们更多:

procedure TForm1.Button1Click(Sender: TObject);
var
  I: Integer;
  Buffer: TBytes;
  WordArray: array[0..5] of Word;
  StringArray: array[0..9] of AnsiString;
begin
  if IdTCPClient1.IOHandler.InputBufferIsEmpty then
  begin
    if IdTCPClient1.IOHandler.CheckForDataOnSource(1000) then
      IdTCPClient1.IOHandler.ReadBytes(Buffer, 512, False);

    for I := 0 to High(WordArray) do
    begin
      WordRec(WordArray[I]).Hi := Buffer[I * 2];
      WordRec(WordArray[I]).Lo := Buffer[I * 2 + 1];
    end;
    for I := 0 to High(StringArray) do
      SetString(StringArray[I], PAnsiChar(@Buffer[I * 50 + 12]), 50);

    // here you have the arrays prepared to be processed
  end;
end;