【问题标题】:How to transfer data using Indy TCP Server/Client?如何使用 Indy TCP 服务器/客户端传输数据?
【发布时间】:2017-12-28 13:21:45
【问题描述】:

我想将数据从 TIdTCPServer 传输到 TIdTCPClient。

在服务器端我有:

procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
var x:Integer;
    Received:String;
    SendBuff:TBytes;
    hFile:THandle;
    fSize:Int64;
begin
 fSize:=0;
 if MOpenFileForRead(hFile,MGetExePath+'\test.jpg') then begin
  fSize:=MFileSize(hFile);
  SetLength(SendBuff,fSize);
  MReadFile(hFile,SendBuff[0],fSize);
  MCloseFile(hFile);
 end;

 // ... here the SendBuff contains valid data, I checked. 

 repeat
  Received:=AContext.Connection.Socket.ReadLn;
  if not AContext.Connection.Connected then Exit;
  if Received=CMD_TEST_FILE then begin
   AContext.Connection.Socket.Write(fSize);
   AContext.Connection.Socket.WriteBufferOpen;
   AContext.Connection.Socket.Write(SendBuff);
   AContext.Connection.Socket.WriteBufferClose;
  end;
 until False;
end;

和客户端:

procedure TForm1.Button2Click(Sender: TObject);
var fSize:Int64;
    RecvBuff:TBytes;
    hFile:THandle;
begin
  IdTCPClient1.Socket.WriteLn(CMD_TEST_FILE);
  fSize:=IdTCPClient1.Socket.ReadInt64;
  SetLength(RecvBuff,fSize);
  IdTCPClient1.Socket.ReadBytes(RecvBuff,fSize);
  if MCreateFile(hFile, MGetExePath+'\new.jpg') then begin
   MWriteFile(hFile,RecvBuff[0],fSize);
   MCloseFile(hFile);
  end;
  Memo1.Lines.Add('ok');
end;

...但它不起作用。我检查了使用的读取和写入数据功能,它们没问题。在服务器端缓冲区设置正常,文件大小到达客户端正常,但客户端缓冲区的内容只有零。

P.S:我想以这种方式发送文件,而不是流或其他任何东西。

【问题讨论】:

    标签: delphi indy transfer


    【解决方案1】:

    如果您查看ReadBytes() 的签名,它有一个可选的AAppend 参数,默认为True:

    procedure ReadBytes(var VBuffer: TIdBytes; AByteCount: Integer; AAppend: Boolean = True); virtual;
    

    当为真时,它从套接字读取字节并将它们附加到现有字节数组的末尾。由于您正在预分配数组,因此初始字节未定义,文件字节在未定义字节之后。

    要解决此问题,您需要:

    1. 停止预分配字节数组,让ReadBytes()为你分配。

      procedure TForm1.Button2Click(Sender: TObject);
      var
        fSize: Int64;
        RecvBuff: TBytes;
        hFile: THandle;
      begin
        IdTCPClient1.Socket.WriteLn(CMD_TEST_FILE);
        fSize := IdTCPClient1.Socket.ReadInt64;
        // SetLength(RecvBuff,fSize); // <-- remove this line
        IdTCPClient1.Socket.ReadBytes(RecvBuffer, fSize);
        if MCreateFile(hFile, MGetExePath+'\new.jpg') then
        begin
          MWriteFile(haile, RecvBuff[0], fSize);
          MCloseFile(hFile);
        end;
        Memo1.Lines.Add('ok');
      end;
      
    2. 预分配数组,但将 AAppend 设置为 False,以便字节填充现有数组而不是附加到它。

      procedure TForm1.Button2Click(Sender: TObject);
      var
        fSize: Int64;
        RecvBuff: TBytes;
        hFile: THandle;
      begin
        IdTCPClient1.Socket.WriteLn(CMD_TEST_FILE);
        fSize := IdTCPClient1.Socket.ReadInt64;
        SetLength(RecvBuff, fSize);
        IdTCPClient1.Socket.ReadBytes(RecvBuff, fSize, False);
        if MCreateFile(hFile, MGetExePath+'\new.jpg') then
        begin
          MWriteFile(haile, RecvBuff[0], fSize);
          MCloseFile(hFile);
        end;
        Memo1.Lines.Add('ok');
      end;
      

    更新:话虽如此,我强烈建议你改用TStream,尽管你说你不想这样做。它将大大简化代码和内存管理,而不会破坏您选择使用的通信协议:

    procedure TForm1.IdTCPServer1Connect(AContext: TIdContext);
    begin
      AContext.Data := TFileStream.Create(MGetExePath+'\test.jpg', fmOpenRead or fmShareDenyWrite);
      AContext.Connection.IOHandler.LargeStream := True;
    end;
    
    TForm1.IdTCPServer1Execute(AContext: TIdContext);
    var
      Received: String;
    begin
      Received := AContext.Connection.IOHandler.ReadLn;
      if Received = CMD_TEST_FILE then
      begin
        AContext.Connection.IOHandler.Write(TStream(AContext.Data), 0, True);
      end;
    end;
    

    procedure TForm1.Button2Click(Sender: TObject);
    var
      FileName: string;
      Strm: TStream;
    begin
      FileName := MGetExePath+'\new.jpg';
      Strm := TFileStream.Create(FileName, fmCreate);
      try
        try
          IdTCPClient1.IOHandler.WriteLn
    (CMD_TEST_FILE);
          IdTCPClient1.IOHandler.ReadStream(Strm, -1, False);
        finally
          Strm.Free;
        end;
      except
        DeleteFile(FileName);
        raise;
      end;
      Memo1.Lines.Add('ok');
    end;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-01-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多