向各位DELPHI高手求教.很急,谢谢了!(100分)

  • 主题发起人 主题发起人 guanweiw
  • 开始时间 开始时间
G

guanweiw

Unregistered / Unconfirmed
GUEST, unregistred user!
有N个设备通过UDP向上发数据,我要存储每个设备的数据以及共有多少条数据,并检查缺失的数据.
我使用UDP接收数据,在UDPServer的DoUDPRead事件中,每接收到一条数据,就启动一个处理数据线程,这个线程是自释放的.当收到某一设备的传输结束的指令时,启动一个处理结束数据的线程,这个线程也是自释放的.
建立一个记录体指针,在TThreadList中add记录体指针.
我的这个程序运行起来后,总是在收到几次数据后,当我使用MyUDPServer.RtuProtoList时,就提示有类型转化的错误,Rtu_ID是个长整形变量,可是提示说无法把***转换为长整形变量.我认为可能是指针什么的出错了,但怎么也找不到问题在哪里.
PS:我第一次写跟线程有关的东西,总觉得我这么写好像有问题,希望各位大侠帮我看看这段程序.谢谢了...
注:MyUDPServer.RtuProtoList是我在调用线程的类中,定义的一个TThreadList
TProtoList = record
ClientIP: String[50];
ClientPort: Integer;
Rtu_ID: Longint;
Group_ID: Integer;
FrameCount: Integer;
ArrFrame: Array [0..1024] of Word;
end;
TPProtoList = ^TProtoList;
处理数据线程:
TProtocol = class(TThread)
private
fRecCount: Integer;
fReceStr: String;
AdoCmd: TADOCommand;
fServerBinding: TIdSocketHandle;
ReceiveBuff: Array of Byte;
PNewProto: TPProtoList;
unFrame_Num, unRtu_ID: Integer;
Function ProtoEnd: Boolean;
Procedure SaveData;
Function AddProtoToList: Boolean;
protected
procedure Execute;
override;
public
property RecCount: Integer read fRecCount write fRecCount;//启动线程时传入的从UDP接收到的数据长度
property ReceStr: String read fReceStr write fReceStr;//启动线程时传入的从UDP接收到的数据
property ServerBinding: TIdSocketHandle read fServerBinding write fServerBinding;//启动线程时传入的SocketHandle
destructor Destroy;
override;
end;

procedure TProtocol.Execute;
var
lnI: Integer;
begin
inherited;
FreeOnTerminate := True;
CoInitialize(nil);
SetLength(ReceiveBuff, fRecCount);
for lnI := 0 to (fRecCount)-1do
ReceiveBuff[lnI] := StrToInt('$' + Copy(fReceStr, (lnI*2)+1, 2));
AdoCmd:=TADOCommand.Create(nil);
//检查收到的是否是结束包
//if ProtoEnd then
Destroy;
if not ProtoEnd then
begin
//维护协议包TList
if AddProtoToList then
//保存这包数据.
SaveData(True);
end;

end;

//维护协议TList
Function TProtocol.AddProtoToList: Boolean;
var
lnI: Integer;
lsTemp: String;
lnYear, lnMonth, lnDay: Word;
lnHour, lnMin, lnSec, lnMSec: Word;
lbFlag: Boolean;
begin
Result := False;
//将设备编号解出
lsTemp := '';
For lnI := 1 to ReceiveBuff[7]do
lsTemp := lsTemp + Chr(ReceiveBuff[7+lnI]);
unRtu_ID := StrToInt(lsTemp);
//帧号
unFrame_Num := ReceiveBuff[7+ReceiveBuff[7]+1]*256 + ReceiveBuff[7+ReceiveBuff[7]+2];
MyUDPServer.RtuProtoList.LockList;
try
lbFlag := False;
for lnI := 0 to MyUDPServer.RtuProtoList.LockList.Count-1do
begin
PNewProto:=TPProtoList(MyUDPServer.RtuProtoList.LockList.Items[lnI]);
If PNewProto^.ClientIP = ServerBinding.PeerIP then
if PNewProto^.ClientPort = ServerBinding.PeerPort then
if PNewProto^.Rtu_ID = unRtu_ID then
begin
PNewProto^.FrameCount := unFrame_Num;
PNewProto^.ArrFrame[unFrame_Num] := unFrame_Num;
lbFlag := True;
MyUDPServer.RtuProtoList.UnlockList;
Break;
end;
end;

if not lbFlag then
begin
New(PNewProto);
With PNewProto^do
begin
ClientIP := ServerBinding.PeerIP;
ClientPort := ServerBinding.PeerPort;
RTU_ID := unRtu_ID;
DecodeDate(Now, lnYear, lnMonth, lnDay);
DecodeTime(Now, lnHour, lnMin, lnSec, lnMSec);
Group_ID := StrToInt(Copy(IntToStr(lnYear), 3, 2) + IntToStr(lnMonth) + IntToStr(lnDay) +
IntToStr(lnHour) + IntToStr(lnMin));
FillChar(ArrFrame, SizeOF(ArrFrame), 0);
FrameCount := unFrame_Num;
ArrFrame[unFrame_Num] := unFrame_Num;
end;

try
MyUDPServer.RtuProtoList.LockList.Add(PNewProto);
finally
MyUDPServer.RtuProtoList.UnlockList;
end;
end;
except
on E: EConvertErrordo
begin
Protocol.Terminate;
Exit;
end;
end;

Result := True;
end;

//保存这包数据
procedure TProtocol.SaveData;
const
InsertPackage = 'Insert into Package_Rec (Team_Num, Package_ID, Rtu_ID, '+
'Origin_Mac, Package_Rec, Receive_Time, Deal_flag) values (%d, ' +
'%d, %d, 1, ''%s'', ''%s'', 0)';
begin
//创建数据集并检查数据库连接
with AdoCmddo
begin
Connection := FrmUDPCtrl.ADOConnection;
ExecuteOptions := [eoExecuteNoRecords];
CommandText := Format(InsertPackage, [PNewProto^.Group_ID, unFrame_Num,
unRtu_ID, ReceStr, DateTimeToStr(Now)])
try
Execute;
Except
Exit;
end;
end;
end;

//检查收到的数据是否是结束包
function TProtocol.ProtoEnd: Boolean;
var
Rtuid, lnI: Integer;
lsTemp: String;
FrameConst: Integer;
begin
Result := False;
if ReceiveBuff[1]<>$AD then
Exit;
lsTemp := '';
for lnI :=1 to ReceiveBuff[7]do
lsTemp:=lsTemp + Chr(ReceiveBuff[7+lnI]);
Rtuid := StrToInt(lsTemp);
FrameConst := ReceiveBuff[7 + ReceiveBuff[7] + 1]*256 + ReceiveBuff[7 + ReceiveBuff[7] + 2];
if FrameConst=0 then
Exit;
//启动结束处理线程
ReceEnd := TReceend.
Create(True);
Receend.
EndRtuId := Rtuid;
//设备编号
Receend.
FrameConst := FrameConst;
//总帧数
Receend.
EndServerBinding := ServerBinding;
//Socket句柄
SleepEx(2000, False);
Receend.
Resume;
Result := True;
end;

destructor TProtocol.Destroy;
begin
if Assigned(AdoCmd) then
AdoCmd.Free;
SetLength(ReceiveBuff, 0);
if PNewProto <> nil then
Dispose(PNewProto);
CoUninitialize;
inherited;
end;

处理结束数据线程:
TReceEnd = class(TThread)
private
fRtuId: Integer;
fFrameConst: Integer;
fServerBinding: TIdSocketHandle;
unCount: Integer;
ReSendFrameNo: Array [0..1024] of Byte;
PAllProto: TPProtoList;
AdoCmd: TADOCommand;
Function CheckReSendFrame: Boolean;
Procedure SendCommand;
Procedure UpdataDataBase;
protected
procedure Execute;
override;
public
property EndRtuId: Integer read fRtuId write fRtuId;
property FrameConst: Integer read fFrameConst write fFrameConst;
property EndServerBinding: TIdSocketHandle read fServerBinding write fServerBinding;
destructor Destroy;
override;
end;

Procedure TReceend.
Execute;
begin
inherited;
FreeOnTerminate := True;
CoInitialize(nil);
AdoCmd:=TADOCommand.Create(nil);
//检查是否有需要补抄的帧
if not CheckReSendFrame then
Destroy;
//如果有需要补抄的数据,发送补抄命令
if unCount<>0 then
SendCommand;
//更新数据库
UpdataDataBase;
end;

//检查是否有需要补抄的帧
Function TReceend.
CheckReSendFrame: Boolean;
var
lbFlag: Boolean;
lnI, lnJ: Integer;
begin
Result := False;
if MyUDPServer.RtuProtoList = nil then
Exit;
unCount := 0;
FillChar(ReSendFrameNo, Sizeof(ReSendFrameNo), 0);
MyUDPServer.RtuProtoList.LockList;
try
for lnI := 0 to MyUDPServer.RtuProtoList.LockList.Count-1do
begin
PAllProto:=TPProtoList(MyUDPServer.RtuProtoList.LockList.Items[lnI]);
//找到LIST中本次要处理的那个单元
If PAllProto.ClientIP = EndServerBinding.PeerIP then
if PAllProto.ClientPort = EndServerBinding.PeerPort then
if PAllProto.Rtu_ID = EndRtuId then
begin
PAllProto.FrameCount := FrameConst;
//根据总帧数判断是否每帧都收到了
for lnJ := 1 to FrameConstdo
begin
//Flag=true代表某帧收到了
lbFlag := False;
if PAllProto.ArrFrame[lnJ]<>0 then
begin
lbFlag := True;
Break;
end;
//如果Flag=False,则认为某帧没有收到,要补抄,
//将lnCount+1并且将要补抄的帧号给ReSendFrameNo
if not lbFlag then
begin
Inc(unCount);
ReSendFrameNo[unCount-1] := lnJ;
Break;
end;
end;
end;
end;
except
on E: EConvertErrordo
begin
Receend.
Terminate;
Exit;
end;
end;

MyUDPServer.RtuProtoList.UnlockList;
Result := True;
end;

Procedure TReceend.
UpdataDataBase;
const
UpdataPackage = 'Update Package_Rec set PackageCount=%d where (Package_ID=%d) and (RTU_ID=%d)';
begin
if not (PAllProto=nil) then
begin
AdoCmd := TADOCommand.Create(nil);
with AdoCmddo
begin
Connection := FrmUDPCtrl.ADOConnection;
ExecuteOptions := [eoExecuteNoRecords];
CommandText := Format(UpdataPackage, [PAllProto^.FrameCount,
PAllProto^.Group_ID, EndRtuId]);
try
Execute;
Except
Exit;
end;
end;
end;
MyUDPServer.RtuProtoList.Remove(PAllProto);
end;

destructor TReceend.
Destroy;
begin
if Assigned(AdoCmd) then
AdoCmd.Free;
if Assigned(PAllProto) then
Dispose(PAllProto);
CoUninitialize;
inherited;
end;
 
下班了.先做个标记.下午有空再帮你看看
 
我的天啊,真是无心看完
 
on E: EConvertErrordo
begin
Protocol.Terminate;//这句话应该有问题 为何在此停止一个全局的线程?
Exit;
end;
 
多线程的调试很麻烦,大看一下你的代码,很难细细去体会其中的每个过程,我以前调试这样的代码,都会做一个输出日志类,不断监视到了哪一个步骤,监视关键变量,然后出错了至少知道是哪个地方错的,相关的变量是多少,楼主可以试试,没有设备很难看你的代码的
 
问题我已经找到了.我在一个非主线程中调用另一个线程时,没有等待被调用线程的结束,资源已经被释放掉了,所以在这种情况下,就会出现未知的问题.
谢谢各位了.
PS:就像诸葛白痴说的,调试线程很麻烦,虽然你能跟到线程中去,但依然无法真正找到问题出在什么地方,所以我也建议大家做个输出日志,并且对所有异常都TRY住,在报出异常的时候写日志,就能相对容易一些的找到真正的问题.
 
嘻嘻,找到就好
 
多人接受答案了。
 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
I
回复
0
查看
720
import
I
I
回复
0
查看
1K
import
I
后退
顶部