Delphi 从ClientSocket(移动)向ServerSocket(服务器)发送数据时丢失数据
我在Delphi10.1 Berlin中使用FireMonkey开发Android移动客户端应用程序,在Delphi10.1 Berlin中使用VCL开发Windows服务器应用程序 在移动应用程序中,我使用Delphi 从ClientSocket(移动)向ServerSocket(服务器)发送数据时丢失数据,delphi,firemonkey,vcl,delphi-10.1-berlin,delphi-10.2-tokyo,Delphi,Firemonkey,Vcl,Delphi 10.1 Berlin,Delphi 10.2 Tokyo,我在Delphi10.1 Berlin中使用FireMonkey开发Android移动客户端应用程序,在Delphi10.1 Berlin中使用VCL开发Windows服务器应用程序 在移动应用程序中,我使用TIdTCPClient发送以下记录: PSampleReq = ^TSampleReq ; TSampleReq = packed record Value1: array [0..10] of Char; Value2: array [0..59] of Char; Valu
TIdTCPClient
发送以下记录:
PSampleReq = ^TSampleReq ;
TSampleReq = packed record
Value1: array [0..10] of Char;
Value2: array [0..59] of Char;
Value3: array [0..40] of Char;
Value4: Int64;
Value5: array [0..9] of Char;
Value6: array [0..9] of Char;
Value7: Integer;
end;
我已用数据填充数据包,并使用以下代码发送数据包:
FIdTCPClient.IOHandler.Write(RawToBytes(TSampleReq,SizeOf(TSampleReq)));
在读取服务器应用程序中的数据时,我无法读取Value5
、Value6
和Value7
字段。下面是读取数据的代码:
Move(tyTIDBytes[0], SampleReq, SizeOf(TSampleReq));
为了接收从客户端套接字发送的数据,我使用了TIDTcpServer,并在Execute方法中处理了以下代码:
TServerRecord = packed record
PointerMessage : TIndyBytes;
ClientSocket : TIdTCPConnection;
end;
Var
ReceivedIDBytes: TServerRecord;
begin
if not AContext.Connection.IOHandler.InputBufferIsEmpty then
begin
AContext.Connection.IOHandler.InputBuffer.ExtractToBytes(ReceivedIDBytes.PointerMessage.tyTIDBytes) ;
ReceivedIDBytes.ClientSocket := AContext.Connection;
MessageProcessorThread.ProcessMessageQueue.Enqueue(ReceivedIDBytes);
end;
在此之后,我将处理队列中的数据,以及我在下面提到的处理方法:
var
InputRec: TServerRecord;
begin
InputRec := DBWorkerThread.DBWorkerQueue.Dequeue;
MessageHeaderPtr := @InputRec.PointerMessage.tyTIDBytes[0];
iHMMessageCode := StrToIntDef( Trim(MessageHeaderPtr^.MessageCode), UNKNOWN_MESSAGE_CODE);
case iHMMessageCode of
1001:
begin
Move(InputRec.PointerMessage.tyTIDBytes[0], SampleReq, SizeOf(TSampleReq));
end;
end;
在这里,我无法读取Value5、Value6和Value7字段
通过下面的链接,我找到了一些优化技术,以及如何正确处理数据包而不丢失任何数据包。请帮我解决这个问题
您使用的
提取字节()
是完全错误的。该方法返回在特定时刻存储在InputBuffer
中的任意字节,该字节可能小于或大于您实际期望的字节数
如果您的客户端每次发送一个固定大小的记录,您应该准确地读取这么多字节,不多也不少:
var
ReceivedIDBytes: TServerRecord;
begin
AContext.Connection.IOHandler.ReadBytes(ReceivedIDBytes.PointerMessage.tyTIDBytes, SizeOf(TSampleReq)); // <-- HERE!!!
ReceivedIDBytes.ClientSocket := AContext.Connection;
MessageProcessorThread.ProcessMessageQueue.Enqueue(ReceivedIDBytes);
end;
然后服务器可以在读取字节之前读取字节计数:
var
ReceivedIDBytes: TServerRecord;
begin
AContext.Connection.IOHandler.ReadBytes(ReceivedIDBytes.PointerMessage.tyTIDBytes, AContext.Connection.IOHandler.ReadInt32); // <-- HERE!!!
ReceivedIDBytes.ClientSocket := AContext.Connection;
MessageProcessorThread.ProcessMessageQueue.Enqueue(ReceivedIDBytes);
end;
var
ReceivedIDBytes:TServerRecord;
开始
AContext.Connection.IOHandler.ReadBytes(ReceivedIDBytes.PointerMessage.tyTIDBytes,AContext.Connection.IOHandler.ReadInt32);//您是否验证了两个应用程序中的sizeof(TSampleReq)
正好是276字节?在调用Move()
之前,您没有显示正在填充tyTIDBytes
的实际读取代码。代码应该是这样的:var tyTIDBytes:TIdBytes。。。AContext.Connection.IOHandler.ReadBytes(tyTIDBytes,SizeOf(TSampleReq),False)代码>仅供参考,Indy有一个BytesToRaw()
函数作为RawToBytes()
:BytesToRaw(tyTIDBytes,sampleeq,SizeOf(TSampleReq))代码>和仅供参考,您没有使用其中描述的“优化技术”。这种技术在发送实际数据之前先发送数据大小。Indy的等价物看起来是这样的:tyTIDBytes:=RawToBytes(sampleeq,SizeOf(tsampleq);FIdTCPClient.IOHandler.Write(Int32(Length(tyTIDBytes));FIdTCPClient.IOHandler.Write(tyTIDBytes);
…AContext.Connection.IOHandler.ReadBytes(tyTIDBytes,AContext.Connection.IOHandler.ReadInt32,False);BytesToRaw(tyTIDBytes,SampleReq,SizeOf(TSampleReq));
请您的问题显示您在连接两端使用的实际代码。发送代码和读取代码之间显然不匹配。您没有回答我之前的问题:“您验证了SizeOf(TSampleReq)吗?”
两个应用程序中的字节数都是276吗?”。我在问题中添加了额外的信息,从服务器接收的部分应该针对不同的记录进行处理,我也尝试了你的方法,但仍然面临相同的问题。你没有使用我描述的技术,甚至没有关闭。你使用的ExtractToBytes()
完全错了,这是您的问题的根源。我现在发布了一个答案。谢谢。当客户端应用程序在桌面上运行时,它可以正常工作,并且没有数据包丢失。但是当我尝试在Android mobile上运行时,没有收到value6。Android firemonkey移动应用程序有任何限制吗?@Work2Enjoy-Enjoy2Work th我展示的e代码在所有平台上都同样有效。如果它不适用于你,那么你的代码中一定还有不匹配的地方。你需要调试你的代码。你仍然没有回答我之前的问题。这是我最后一次问:“你的所有应用程序中的sizeof(TSampleReq)
正好是276字节吗?”您是否验证了TIdIOHandler.ReadInt32()
是否每次都返回预期值?如果不是,请确保您使用的是最新版本的Indy.IIRC,Android上有一个endian错误,我不久前修复了该错误。谢谢@Remy。现在我在服务器端收到了正确的数据。需要发送的特定数据包是否有大小限制?@Work2Enjoy-EnjOY2工作限制为2GB,即Int32
的最大值。
var
ReceivedIDBytes: TServerRecord;
begin
AContext.Connection.IOHandler.ReadBytes(ReceivedIDBytes.PointerMessage.tyTIDBytes, AContext.Connection.IOHandler.ReadInt32); // <-- HERE!!!
ReceivedIDBytes.ClientSocket := AContext.Connection;
MessageProcessorThread.ProcessMessageQueue.Enqueue(ReceivedIDBytes);
end;