0

好吧,这会很长!

我为我正在研究的 LAN 模拟协议制定了一个用于管理丢弃的 UDP 数据包的重传方案。

数据包存储

TDataBuffer = record

  PacketID : WORD;
  Packet   : TMemoryStream;

end;
PDataBuffer = ^TDataBuffer;

相关 DataModule 类成员

fRxDataPacketList  : TThreadList20;
fTxDataPacketList  : TThreadList20;

procedure CreateDataBuffer
          (PacketID : WORD; Packet : TMemoryStream;
           var DataBuffer : PDataBuffer);

procedure DestroyDataBuffer
          (var DataBuffer : PDataBuffer);

procedure AddPacketToPacketList
          (PacketID : WORD; Packet : TMemoryStream;
           RecievedPacket : Boolean);

function  GetPacketFromTxDataPacketList
          (PacketID : WORD; var Packet : TMemoryStream): Boolean;

TThreadList20:它是我自己的线程友好、加密和压缩支持的 TList 包装类。

还有另一个处理 Rx 端的过程与我的问题无关,所以我跳过它。

创建

procedure TDataModuleClient.CreateDataBuffer
          (PacketID : WORD; Packet : TMemoryStream; 
           var DataBuffer : PDataBuffer);

begin

  New (DataBuffer);
  DataBuffer.PacketID := PacketID;
  DataBuffer.Packet   := TMemoryStream.Create;

  if Assigned (Packet) then 
  begin

    DataBuffer.Packet.CopyFrom (Packet,Packet.Size); // NO AV HERE
    DataBuffer.Packet.Position := 0;

  end;

end;

破坏

procedure TDataModuleClient.DestroyDataBuffer
          (var DataBuffer : PDataBuffer);
begin

  DataBuffer.Packet.Free;
  Dispose (DataBuffer);

end;

添加到列表

procedure TDataModuleClient.AddPacketToDataPacketList
          (PacketID : WORD; Packet : TMemoryStream; RecievedPacket : Boolean);
var
  DataBuffer : PDataBuffer;

begin

  CreateDataBuffer (PacketID,Packet,DataBuffer);

  if RecievedPacket then
    fRxDataPacketList.Add (TObject (DataBuffer))

  else
  begin

    fTxDataPacketList.Lock;

    try

      fTxDataPacketList.Add (TObject (DataBuffer));

      if fRxDataPacketList.Count = 21 then
      begin

        DataBuffer := PDataBuffer (fTxDataPacketList [0]);

        DestroyDataBuffer (DataBuffer);
        fTxDataPacketList.Delete (0);

      end;

    finally fTxDataPacketList.Unlock;
    end;

  end;

end;

从列表中提取

function  TDataModuleClient.GetPacketFromTxDataPacketList
          (PacketID : WORD; var Packet : TMemoryStream): Boolean;
var
  DataBuffer : PDataBuffer;
  I          : Integer;

begin

  Result := False;
  fTxDataPacketList.Lock;

  try

    for I := fTxDataPacketList.Count - 1 downto 0 do
    begin

      DataBuffer := PDataBuffer (fTxDataPacketList [I]);

      if DataBuffer.PacketID < PacketID then
      begin

        DestroyDataBuffer (DataBuffer);
        fTxDataPacketList.Delete (I);

      end
      else if DataBuffer.PacketID = PacketID then
      begin

        Result := True;

        Packet := TMemoryStream.Create;

        Packet.CopyFrom
        (DataBuffer.Packet,DataBuffer.Packet.Size); // AV HERE
        Packet.Position := 0;

        DestroyDataBuffer (DataBuffer);
        fTxDataPacketList.Delete (I);

        break;

      end;

    end;

  finally fTxDataPacketList.Unlock;
  end;

end;

数据包:输出变量。

请帮帮我,我知道由于代码量很大,推断出一些东西看起来是一项艰巨的任务。

4

1 回答 1

2

基于这个有限的代码,我做了一些猜测:

1)在您Packet调用. 这将解释 AV。GetPacketFromTxDataPacketList()CopyFrom()

2)由于Packet参数被声明为 a var,这向我表明它是一个GetPacketFromTxDataPacketList()应该创建和返回的输出参数,而不是让调用者创建TMemoryStream并传递它GetPacketFromTxDataPacketList()以填充数据。这也适用于#1,因为GetPacketFromTxDataPacketList()不是创建新TMemoryStream对象,而是假设对象已经事先创建。

于 2012-11-08T18:56:35.160 回答