0

我在 Delphi 10.1 Berlin 中使用 FireMonkey 开发 Android 移动客户端应用程序,我在 Delphi 10.1 Berlin 中使用 VCL 开发 Windows 服务器应用程序。

在移动应用程序中,我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)));

在服务器应用程序中读取数据时,我无法读取Value5Value6Value7字段。下面是读取数据的代码:

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;

在此之后,我正在处理来自 Queue 的数据以及我在下面提到的处理方法:

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 字段。

通过下面的链接,我发现了一些优化的技术以及如何正确处理数据包而不会丢失任何数据包。请帮我解决这个问题。

通过套接字发送正确的记录大小

4

1 回答 1

1

你的使用ExtractToBytes()是完全错误的。该方法返回在特定时刻存储在 中的任意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
  tyTIDBytes: TIdBytes;
begin
  tyTIDBytes := RawToBytes(TSampleReq, SizeOf(TSampleReq));
  FIdTCPClient.IOHandler.Write(Int32(Length(tyTIDBytes)));
  FIdTCPClient.IOHandler.Write(tyTIDBytes);
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;
于 2017-05-22T17:32:50.557 回答