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;
我使用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;