I'm using FireMonkey in Delphi 10.1 Berlin for developing an Android mobile client application, and I'm using VCL in Delphi 10.1 Berlin for developing a Windows server application.
In the mobile application, I am using TIdTCPClient
for sending the following record:
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;
I have filled the packet with data and am sending the packet using the following code:
FIdTCPClient.IOHandler.Write(RawToBytes(TSampleReq,SizeOf(TSampleReq)));
While reading the data in the Server application, I am not able to read the Value5
, Value6
and Value7
fields. Below is the code that is reading the data:
Move(tyTIDBytes[0], SampleReq, SizeOf(TSampleReq));
For receiving the data which is send from the client socket, I have used the TIDTcpServer and handled the below code in Execute method:
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;
After this I'm processing the data from Queue and the processing method I have mentioned below:
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;
And in this I'm not able to read the Value5, Value6 and Value7 fields.
With the below Link, I have found some optimized technique and how I can handle the packets properly without any packet missing. Please help me out to resolve this issue.
Your use of ExtractToBytes()
is completely wrong. That method returns whatever arbitrary bytes are stored in the InputBuffer
at that particular moment, which may be less than, or more than, what you are actually expecting.
If your client is sending a fixed-sized record each time, you should be reading exactly that many bytes, no more, no less:
var
ReceivedIDBytes: TServerRecord;
begin
AContext.Connection.IOHandler.ReadBytes(ReceivedIDBytes.PointerMessage.tyTIDBytes, SizeOf(TSampleReq)); // <-- HERE!!!
ReceivedIDBytes.ClientSocket := AContext.Connection;
MessageProcessorThread.ProcessMessageQueue.Enqueue(ReceivedIDBytes);
end;
However, if the size of the record depends on the message code, then your client should send the number of bytes in a record before sending the actual record bytes:
var
tyTIDBytes: TIdBytes;
begin
tyTIDBytes := RawToBytes(TSampleReq, SizeOf(TSampleReq));
FIdTCPClient.IOHandler.Write(Int32(Length(tyTIDBytes)));
FIdTCPClient.IOHandler.Write(tyTIDBytes);
end;
And then the server can read the byte count before reading the bytes:
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;