这会很长!
我正在制作一个用于管理丢弃的UDP数据包的重传方案,用于我正在进行的LAN仿真协议。
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;
数据包:输出变量。
请帮助我,我知道由于代码量的原因,它可能是一个很难推断的东西。
答案 0 :(得分:2)
基于这个有限的代码,我正在做一些猜测:
1)在调用Packet
之前,传递给GetPacketFromTxDataPacketList()
的输入CopyFrom()
可能尚未实际实例化。这将解释AV。
2)因为Packet
参数被声明为var
,这告诉我它是GetPacketFromTxDataPacketList()
应该创建并返回的输出参数,而不是调用者创建TMemoryStream
并将其传递到GetPacketFromTxDataPacketList()
以填充数据。这也会成为#1,因为GetPacketFromTxDataPacketList()
没有创建新的TMemoryStream
对象,它假设事先已经创建了对象。