使用 MemoryStream.CopyFrom 时的访问冲突



嗯,这会很长!

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

数据包存储

TDataBuffer = record
PacketID : WORD;
Packet   : TMemoryStream;
end;
PDataBuffer = ^TDataBuffer;

相关数据模块类成员

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;

数据包:输出变量。

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

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

1) 在调用CopyFrom()之前,传递给GetPacketFromTxDataPacketList()的输入Packet可能实际上尚未实例化。这将解释AV。

2)由于Packet参数被声明为var,这对我来说表明它是GetPacketFromTxDataPacketList()应该创建和返回的输出参数,而不是让调用者创建TMemoryStream并将其传递到GetPacketFromTxDataPacketList()中以填充数据。 这也将在#1中发挥作用,因为GetPacketFromTxDataPacketList()没有创建新的TMemoryStream对象,而是假设该对象已经事先创建。

相关内容

  • 没有找到相关文章

最新更新