delphi 本地主机客户端和服务器之间的TCP通信已损坏数据

ufj5ltwl  于 2023-01-17  发布在  其他
关注(0)|答案(1)|浏览(139)

我试图从(IcsOverbyte)服务器(TWSocketServer)到客户端(TWSocket)传输原始h264视频数据包,但是我在尝试正确组装消息时遇到了一些麻烦。
在进入我的问题之前,我只想说我已经确认了.h264数据是有效的,在我序列化我的消息之后,我将它反序列化,并将视频包数据部分保存到一个文件中,然后用VLC播放它,这个文件可以播放,没有任何问题。这样我也确认了我的Serialize/Deserialize例程是正确的(服务器和客户端都有相同的类型和ser/des例程源)。
我的留言是这样的-〉

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;

在客户端,我有一个如下所示的消息组装例程...

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;

仅供参考,从未发生过例外情况。
这就是SetHandleMessage过程

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;

我一直在追自己的尾巴有一段时间了,现在我似乎不能确定是什么问题。
我也尝试过将原始的.h264流传输到客户端并将其保存到文件,效果也很好...
看起来唯一可能出错的是消息组装例程。
编辑:.决定添加序列化函数。
一个一个三个一个一个一个一个一个四个一个一个一个一个一个五个一个

bogh5gae

bogh5gae1#

我想通了...我必须在第一个else语句中将vRcvdCount设置为0。
现在看起来像这样-〉

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;

相关问题