Home > database >  TCP communication between localhost client and server has corrupted data
TCP communication between localhost client and server has corrupted data

Time:01-16

I am trying to stream raw h264 video packets from a (IcsOverbyte) Server (TWSocketServer) to a Client(TWSocket) however I've been having some trouble trying to properly assemble the messages.

Before going into my question I just wanted to say that I've confirmed that the .h264 data is valid, after I serialize my message I deserialize it and save the video-packet data part into a file and play it with VLC, the file is playable with no issues. That way I also confirmed that my Serialize/Deserialize routine is correct (both server and client have the same source for the types and ser/des routine).

My message is like so ->

  TMessageHeader = packed record
    MessageID: UInt32;
    TotalSize: UInt32; {Meaning HeaderSize   Payload}
  end;

  TMediaDataMessage = record
    Header: TMessageHeader;
    Channel: UInt32;
    Stream: UInt32;
    MediaType: Byte; {0 - Video, 1 - Audio}
    Data: TArray<Byte>;
    function FromBytes(pBytes: TArray<Byte>): Boolean;
    function ToBytes: TArray<Byte>;
    function GetSize: UInt32;
  end;

On the client-side I have a message assembly routine like this...

procedure TfrmMain.HandleDataAvailable(pSender: TObject; ErrCode: Word);
var
  vRcvdCount: Integer;
  vBytes: TBytes;
  vMessageTotalSize: UInt32;
  vOffset: UInt32;
begin
  {$POINTERMATH ON}
  if ErrCode <> 0 then
    Exit;

  if pSender = nil then
    Exit;

  SetLength(vBytes, 65536);
  vRcvdCount := fTCPClient.Receive(@vBytes[0], 65536);
  vOffset := 0;

  try
    if fRemainingDataSize > 0 then
    begin
      if vRcvdCount >= fRemainingDataSize then
      begin
        fCurrentBuf.Write(vBytes[vOffset], fRemainingDataSize);
        Inc(vOffset, fRemainingDataSize);
        Dec(vRcvdCount, fRemainingDataSize);
        fRemainingDataSize := 0;
        SetHandleMessage(fIdx.ToString   'Sync');
      end
      else
      begin
        fCurrentBuf.Write(vBytes[vOffset], vRcvdCount);
        Dec(fRemainingDataSize, vRcvdCount);
      end;
    end;
  except
    reLog.Lines.Add('Error sync');
  end;

  try
    while (vRcvdCount > 0) do
    begin
      vMessageTotalSize := PUInt32(@vBytes[vOffset   4])^;

      if vRcvdCount >= vMessageTotalSize then
      begin
        fCurrentBuf.Write(vBytes[vOffset], vMessageTotalSize);
        Inc(vOffset, vMessageTotalSize);
        Dec(vRcvdCount, vMessageTotalSize);
        SetHandleMessage('Loop');
      end
      else
      begin
        fCurrentBuf.Write(vBytes[vOffset], vRcvdCount);
        fRemainingDataSize := vMessageTotalSize - vRcvdCount;
        vRcvdCount := 0;
      end;
    end;
  except
    reLog.Lines.Add('Loop');
  end;

  //fTcpClient.Flush;
end;

FYI the exceptions never occur.

And this is the SetHandleMessage procedure

procedure TfrmMain.SetHandleMessage(pSort: string);
var
  vMsgBytes: TArray<Byte>;
  vMessageID: UInt32;
begin
  fCurrentBuf.Position := 0;
  SetLength(vMsgBytes, fCurrentBuf.Size);
  fCurrentBuf.Read(vMsgBytes[0], fCurrentBuf.Size);
  fCurrentBuf.Clear;
  vMessageID := PUInt32(@vMsgBytes[0])^;
  HandleMessage(vMessageID, vMsgBytes, pSort);
end;

I've been chasing my own tail for a while now I can't seem to pinpoint what is the issue.

I've also tried just streaming the raw .h264 to the client and save it to file and it works as well...

It seems the only thing that could be wrong is the message assembly routine.

Edit:. Decided to add the serialization functions.

function TMediaDataMessage.FromBytes(pBytes: TArray<Byte>): Boolean;
var
  vLen: Integer;
  vOffset: Integer;
  vArrSize: UInt32;
begin
  vOffset := 0;

  Move(pBytes[vOffset], PByte(@Header.MessageId)[0], Sizeof(Header.MessageID));
  Inc(vOffset, Sizeof(Header.MessageID));
  Move(pBytes[vOffset], PByte(@Header.TotalSize)[0], Sizeof(Header.TotalSize));
  Inc(vOffset, Sizeof(Header.TotalSize));
  Move(pBytes[vOffset], PByte(@Channel)[0], Sizeof(Channel));
  Inc(vOffset, Sizeof(Channel));
  Move(pBytes[vOffset], PByte(@Stream)[0], Sizeof(Stream));
  Inc(vOffset, Sizeof(Stream));
  Move(pBytes[vOffset], PByte(@MediaType)[0], Sizeof(MediaType));
  Inc(vOffset, Sizeof(MediaType));

  Move(pBytes[vOffset], PByte(@vArrSize)[0], Sizeof(vArrSize));
  Inc(vOffset, Sizeof(vArrSize));

  if vArrSize <> 0 then
  begin
    SetLength(Data, vArrSize);
    Move(pBytes[vOffset], Data[0], vArrSize);
  end;

  Exit(True);
end;
function TMediaDataMessage.GetSize: UInt32;
begin
  Result := (Sizeof(uInt32) *2)   Sizeof(Channel)   Sizeof(Stream)  
    Sizeof(MediaType)   Sizeof(UInt32)   Length(Data);
end;
function TMediaDataMessage.ToBytes: TArray<Byte>;
var
  vSize: UInt32;
  vOffset: UInt32;
  vLen: UInt32;
begin
  vSize := Self.GetSize;

  SetLength(Result, vSize);
  vOffset := 0;

  Move(Self.Header.MessageID, Result[vOffset], Sizeof(Self.Header.MessageID));
  Inc(vOffset, Sizeof(Self.Header.MessageID));
  Move(Self.Header.TotalSize, Result[vOffset], Sizeof(Self.Header.TotalSize));
  Inc(vOffset, Sizeof(Self.Header.TotalSize));

  Move(Self.Channel, Result[vOffset], Sizeof(Self.Channel));
  Inc(vOffset, Sizeof(Self.Channel));
  Move(Self.Stream, Result[vOffset], Sizeof(Self.Stream));
  Inc(vOffset, Sizeof(Self.Stream));

  Move(Self.MediaType, Result[vOffset], Sizeof(Self.MediaType));
  Inc(vOffset, Sizeof(Self.MediaType));

  vLen := Length(Self.Data);
  Move(vLen, Result[vOffset], Sizeof(UInt32));
  Inc(vOffset, Sizeof(UInt32));
  if vLen > 0 then
    Move(Self.Data[0], Result[vOffset], vLen);
end;

CodePudding user response:

I figured it out... I had to set vRcvdCount to 0 in the first else statement.

Looks like this now ->

procedure TfrmMain.HandleDataAvailable(pSender: TObject; ErrCode: Word);
var
  vRcvdCount: Integer;
  vBytes: TBytes;
  vMessageTotalSize: UInt32;
  vOffset: UInt32;
begin
  {$POINTERMATH ON}
  if ErrCode <> 0 then
    Exit;

  if pSender = nil then
    Exit;

  SetLength(vBytes, 65536);
  vRcvdCount := fTCPClient.Receive(@vBytes[0], 65536);
  vOffset := 0;

  try
    if fRemainingDataSize > 0 then
    begin
      if vRcvdCount >= fRemainingDataSize then
      begin
        fCurrentBuf.Write(vBytes[vOffset], fRemainingDataSize);
        Inc(vOffset, fRemainingDataSize);
        Dec(vRcvdCount, fRemainingDataSize);
        fRemainingDataSize := 0;
        SetHandleMessage(fIdx.ToString   'Sync');
      end
      else
      begin
        fCurrentBuf.Write(vBytes[vOffset], vRcvdCount);
        Dec(fRemainingDataSize, vRcvdCount);
        vRcvdCount := 0; \\ Add this here!!!
      end;
    end;
  except
    reLog.Lines.Add('Error sync');
  end;

  try
    while (vRcvdCount > 0) do
    begin
      vMessageTotalSize := PUInt32(@vBytes[vOffset   4])^;

      if vRcvdCount >= vMessageTotalSize then
      begin
        fCurrentBuf.Write(vBytes[vOffset], vMessageTotalSize);
        Inc(vOffset, vMessageTotalSize);
        Dec(vRcvdCount, vMessageTotalSize);
        SetHandleMessage('Loop');
      end
      else
      begin
        fCurrentBuf.Write(vBytes[vOffset], vRcvdCount);
        fRemainingDataSize := vMessageTotalSize - vRcvdCount;
        vRcvdCount := 0;
      end;
    end;
  except
    reLog.Lines.Add('Loop');
  end;

  //fTcpClient.Flush;
end;
  • Related