我有一臺服務器每隔0.1秒發送一次狀態。我使用此代碼訪問UI並在客戶端程序中顯示結果。使用TIdNotify.NotifyMethod時丟失了一些數據包
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
液)結果:
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;
沒有工作。我也有丟包問題和'TIdSync.SynchronizeMethod'解決了這個問題。 – SAMPro
然後你沒有正確處理數據。我向你保證,我描述的技術在正確使用時工作得很好。我用過很多次。最終,'TIdNotify'和'TIdSync'通過RTL中相同的'TThread'序列化隊列,他們只是以不同的方式到達那裏。如果您遇到了我描述的方法問題,請使用您實際使用的最新代碼更新您的問題。您使用TIdSync並不安全,因爲您並未保護您的「緩衝區」變量不受併發訪問的影響,但仍會導致數據丟失。 –
感謝您的信息。這是實際的'TCPServerExecute'代碼。該程序執行'MyServerExecute'內的其餘工作。在那個函數裏面有字符串解析器,然後程序做一些與UI相關的工作來顯示結果。 – SAMPro