我有一台服务器每0.1秒发送一次状态。我使用此代码访问UI并在客户端程序上显示结果。
procedure TModules.TCPServerExecute(AContext: TIdContext);
begin
Buffer:= AContext.Connection.IOHandler.ReadLn();
TIdNotify.NotifyMethod( ServerExecute );
end;
但ServerExecute
未收到某些数据包。我更改了代码并使用了TIdSync.SynchronizeMethod
。问题解决了:
procedure TModules.TCPServerExecute(AContext: TIdContext);
begin
Buffer:= AContext.Connection.IOHandler.ReadLn();
TIdSync.SynchronizeMethod( ServerExecute );
end;
我在这个网站上看到TIdSync.SynchronizeMethod可能会产生死锁。
所以我想知道TIdNotify.NotifyMethod
的问题是什么。另外,我看到一个答案建议使用Timer
同步UI,不使用Notify()和Synchronize()方法。
另外,我必须提到该程序在ServerExecute
内完成其余的工作。
如您所见,我正在将代码缩小到以下内容。我必须提一下,我使用以下代码执行该程序,它已经存在问题并且没有得到预期的结果:
procedure TModules.ServerExecute;
var
I: Word;
tmp, Packet, Cmd:string;
CheckSum: Boolean;
begin
//try
frmDiag.DataLog.Lines.Add(Buffer);
{ExplodeStr(Buffer, Cmd, Packet);
if Cmd='status' then
begin
//ExplodeStr(Packet, Cmd, Packet);
if trim(Packet)='' then
raise Exception.Create('Empty packet received.');
//Prepare for log
{tmp:='';
for I := 1 to Length(Packet) do
begin
if (Ord(Packet[I])>=48) and (Ord(Packet[I])<=122) then
tmp:=tmp+Packet[I]+''
else
tmp:=tmp+IntToStr(Ord(Packet[I]))+'';
end;
//frmITCAMain.Memo1.Lines.Add(Packet);
CheckSum:=ParsePackets(Packet);
IntersectionsList.Int.CallNotifier; //Call the notifier to execute assigned proc
if frmLoader.Visible=true then
with frmLoader do
begin
if
//(Packet[1]='X') or //Server responce
(Packet[1]<>'l') and (Packet[1]<>'s') and (Packet[1]<>'e')and //ignore general packet
(
(Req[1]<>'f') //Only receive ACK
or
((Req[1]='f')and( (Req[2]='m')or(Req[2]='a')or(Req[2]='b') ))
or
( //Receive Data+ACK
(Req[1]='f')and( (Req[2]='g')or(Req[2]='h')or(Req[2]='p')or(Req[2]='j') )
and
(Packet[1]<>'k') //Ignore ACK
)
)
then
begin
if CheckSum then
begin
Res:= Packet;
Confirm;
end
else
begin
if Packet='n' then //Checksum failure
Fail
else
SendPacket; //Resend.
//lblError.Visible:=true;
end;
end;
end;
if (Packet[1]='g') or (Packet[1]='h') or (Packet[1]='p') or
(Packet[1]='j') or (Packet[1]='k') then
frmIntDetails.memReceived.Lines.Text:=tmp;
end
else if Cmd='server' then
begin
with frmLoader do
begin
if Visible=false then exit;
Res:= Packet;
if Copy(Res, 1, 2)='ok' then
Confirm
else
Cancel;
end;
end
else
ClientLog.Add(Buffer);
except on E: Exception do
begin
if E.Message='Connection Closed Gracefully.' then
ClientLog.Add('X:Connection closed(Gracefully)')
else
ClientLog.Add(E.Message+' Buffer="'+Buffer+'"');
end;
end;
//Memo2.Lines.Add( FloatToStr(TimeStampToMSecs(DateTimeToTimeStamp(Now))));
}
end;
frmDiag.DataLog
是TMemo
个组件。
在frmDiag.DataLog
内部,例如,以下列表是我期望的结果(以下字符串是从带有TIdSync.SynchronizeMethod
解决方案的Datalog组件中提取的):
status:l77770000140000
status:eFFFF20000140
status:s0000
status:s0000
status:s0000
status:s0000
status:l00005555140000
status:eFFFF20000140
status:s0000
status:s0000
status:s0000
status:s0000
status:l77770000140000
status:eFFFF20000140
但我得到了这个结果:
status:eFFFF20000140
status:eFFFF20000140
status:s0000
status:s0000
status:s0000
status:s0000
status:s0000
status:s0000
status:s0000
status:s0000
status:s0000
status:l00005555140000
status:l77770000140000
如您所见订单不符合。
我必须获得一个status:l77770000140000
类似的数据包,然后是status:eFFFF20000140
,然后是4 status:s0000
,依此类推。
@Remy我已经改变了你的代码:
TMyNotify = class(TIdNotify)
protected
FBuffer: String;
FMethod: TThreadMethod;
procedure DoNotify; override;
public
constructor Create(const ABuffer: String; AMethod: TThreadMethod);
end;
///......
{ TMyNotify }
constructor TMyNotify.Create(const ABuffer: String; AMethod: TThreadMethod);
begin
inherited Create;
FBuffer := ABuffer;
FMethod := AMethod;
end;
procedure TMyNotify.DoNotify;
begin
inherited;
FMethod;
//Destroy;
end;
这就是我现在调用ServerExcecute的方式:
procedure TModules.TCPServerExecute(AContext: TIdContext);
begin
Buffer:= AContext.Connection.IOHandler.ReadLn();
TMyNotify.Create(Buffer, ServerExecute).Notify;
// ServerExecute;
// TIdNotify.NotifyMethod( ServerExecute );
// TIdSync.SynchronizeMethod( ServerExecute );
end;
答案 0 :(得分:4)
TIdNotify
是异步的。如果您收到新行并在上一行有机会被处理之前覆盖您的Buffer
变量,则前一行将丢失。更改代码以传递TIdNotify
本身内的行值,例如:
type
TMyDataProc = procedure(const ABuffer: String) of object;
TMyNotify = class(TIdNotify)
protected
fBuffer: String;
fProc: TMyDataProc;
procedure DoNotify; override;
public
constructor Create(const ABuffer: String; AProc: TMyDataProc);
end;
constructor TMyNotify.Create(const ABuffer: String; AProc: TMyDataProc);
begin
inherited Create;
fBuffer := ABuffer;
fProc := AProc;
end;
procedure TMyNotify.DoNotify;
begin
fProc(fBuffer);
end;
procedure TModules.TCPServerExecute(AContext: TIdContext);
var
LBuffer: String;
begin
LBuffer := AContext.Connection.IOHandler.ReadLn();
TMyNotify.Create(LBuffer, ServerExecute).Notify();
end;
procedure TModules.ServerExecute(const ABuffer: String);
begin
// use ABuffer as needed...
end;