gpt4 book ai didi

delphi - 如何使用 Indy TCP 服务器/客户端传输数据?

转载 作者:行者123 更新时间:2023-12-02 03:43:31 24 4
gpt4 key购买 nike

我想将数据从 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:我想以这种方式发送文件,而不是使用流或其他任何东西。

最佳答案

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

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

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

要解决此问题,您需要:

  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,尽管您说您不想这样做。它将极大地简化代码和内存管理,而不会破坏您选择使用的通信协议(protocol):

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;

关于delphi - 如何使用 Indy TCP 服务器/客户端传输数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45255470/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com