gpt4 book ai didi

delphi - Delphi 使用 TIdTCPServer/TIdTCPClient 组件丢失数据

转载 作者:行者123 更新时间:2023-12-01 16:23:14 24 4
gpt4 key购买 nike

我正在 Delphi 中使用 TIdTCPClient/TIdTcpServer indy 组件编写客户端-服务器应用程序。

数据传输通常工作正常,但我经常从服务器读取错误的数据;我得到了以前请求的答案,而不是当前的答案。

在调试期间,两个应用程序都在本地工作,因此传输过程中数据不会丢失。

超时为 1000-3000 毫秒,这足以避免在收到第一个请求的答复之前发送第二个请求。

我使用简单的数据格式:前4个字节是数据包长度,其余是该长度的二进制数据。

服务器端代码是(简化为仅发送字符串;我也以同样的方式使用二进制缓冲区,但此代码更易于理解和检查):

Var
lng: LongInt;
ib: TIdBytes;
begin
// Prepare data to send:
lng:=length(s);// s is an AnsiString to be sent
SetLength(ib,lng+4);
Move(lng,ib[0],4);
Move(s[1],ib[4],length(s));
// Send:
AContext.Connection.IOHandler.WriteDirect(ib);
end;

发送请求的客户端代码是相同的(在最后一行调用 TIdTcpClient.IOHandler.WriteDirect())。读取服务器答案的客户端代码是:

Var 
ib: TIdBytes;
size,done,lng: LongInt;
begin
Result:=false;
// answer length:
try
SetLength(ib,0);
tcp.IOHandler.ReadBytes(ib,4,false);
Move(ib[0],size,4);
if length(ib)<0 then Exit;// wrong data
except
on E: Exception do;// code skipped
end;
// read answer body:
done:=0;
b.Clear;// b is my buffer, TStream descendant
while done<size do
begin
lng:=Min(size-done,MaxBlockSize);
// read:
SetLength(ib,0);// to be sure
tcp.IOHandler.ReadBytes(ib,lng,false);
if length(ib)=0 then Exit;// error reading
// append my buffer:
b.Wr(ib[0],length(ib));
// progress:
Inc(done,length(ib));
end;
end;

数据交换顺序为:

  1. 客户端向服务器发送请求,

  2. 服务器读取请求并将答案发送回客户端,

  3. 客户读取答案。

第 3 步出现错误数据。

也许我做的事情总体上是错误的?

在向服务器发送请求以清除传入缓冲区之前,我尝试过 ReadBytes(),但这也没有帮助,就像我尝试过的许多其他操作一样......

现在我没有主意了:(

最佳答案

您的 I/O 逻辑比需要的复杂得多,尤其是在客户端。您正在手动执行 Indy 可以自动为您执行的操作。

在客户端,由于您将数据保存到 TStream 中,因此您可以让 Indy 直接将数据读取到 TStream 中:

begin
...
b.Clear;// b is my buffer, TStream descendant
// ReadStream() can read a '<length><bytes>' formatted
// message. When its ASize parameter is -1 and its
// AReadUntilDisconnect parameter is False, it reads
// the first 4 or 8 bytes (depending on the LargeStream
// property) and interprets them as the byte count,
// in network byte order...
tcp.IOHandler.RecvBufferSize := MaxBlockSize;
tcp.IOHandler.LargeStream := False; // read 4-byte length
// read answer:
try
tcp.IOHandler.ReadStream(b, -1, false);
except
on E: Exception do begin
// the socket is now in an indeterminate state.
// You do not know where the reading left off.
// The only sensible thing to do is disconnect
// and reconnect...
tcp.Disconnect;
...
end;
end;
...
end;

在服务器端,您可以通过两种不同的方式发送与上述代码兼容的消息:

var
lng: LongInt;
ib: TIdBytes;
begin
// Prepare data to send:
// s is an AnsiString to be sent
lng := Length(s);
SetLength(ib, lng);
Move(PAnsiChar(s)^, PByte(ib)^, lng);
// Send:
AContext.Connection.IOHandler.Write(lng); // send 4-byte length, in network byte order
AContext.Connection.IOHandler.Write(ib); // send bytes
end;

或者:

var
strm: TIdMemoryBufferStream;
begin
// Prepare data to send:
// s is an AnsiString to be sent
strm := TIdMemoryBufferStream.Create(PAnsiChar(s), Length(s));
try
// Send:
// Write(TStream) can send a '<length><bytes>' formatted
// message. When its ASize parameter is 0, it sends the
// entire stream, and when its AWriteByteCount parameter
// is True, it first sends the byte count as 4 or 8 bytes
// (depending on the LargeStream property), in network
// byte order...
AContext.Connection.IOHandler.LargeStream := False; // send 4-byte lengtb
AContext.Connection.IOHandler.Write(strm, 0, True);
finally
strm.Free;
end;
end;

如您所见,此代码发送的消息类型与您最初发送的消息类型相同,更改的是管理消息的代码。此外,它还强制消息字节计数以网络字节顺序发送,而您是以主机字节顺序发送消息。多字节整数应尽可能以网络字节顺序发送,以实现一致性和多平台兼容性。

关于delphi - Delphi 使用 TIdTCPServer/TIdTCPClient 组件丢失数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27984142/

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