線上訂房服務-台灣趴趴狗聯合訂房中心
發文 回覆 瀏覽次數:4251
推到 Plurk!
推到 Facebook!

使用TCPCLIENT與偵錯模式時,離開程式會出現錯誤視窗

答題得分者是:careychen
lkkplayer
一般會員


發表:26
回覆:59
積分:17
註冊:2006-11-22

發送簡訊給我
#1 引用回覆 回覆 發表時間:2008-07-19 10:32:50 IP:220.129.xxx.xxx 訂閱
請教各位,我是用Delphi7
我有使用TCPCLIENT
但是很奇怪每次程式執行後,要離開時都會錯誤,
我要離開的時候會執行下面程式碼
var
Client : TIdTCPClient;
.
.
.
if Client <> nil then
if Client.Connected then Client.Disconnect;
不知道我離開時執行這段程式碼是不是斷線不完全,導致有錯誤的視窗。
錯誤視窗如附件。
請教各位有遇過這種情況嗎?
附加檔案:48815252ce926_Noname.jpg
編輯記錄
lkkplayer 重新編輯於 2008-07-21 18:28:12, 註解 無‧
careychen
尊榮會員


發表:41
回覆:580
積分:959
註冊:2004-03-03

發送簡訊給我
#2 引用回覆 回覆 發表時間:2008-07-19 22:42:00 IP:59.126.xxx.xxx 訂閱
大大的問題,小弟試的時候是不會,但我是用 indy 10 的,不知道有沒有差
或是您可以 Po 部份的程式碼來看看是不是您中間有寫了什麼造成這段訊息的出現??
------
價值的展現,來自於你用哪一個角度來看待它!!
lkkplayer
一般會員


發表:26
回覆:59
積分:17
註冊:2006-11-22

發送簡訊給我
#3 引用回覆 回覆 發表時間:2008-07-20 08:44:13 IP:218.169.xxx.xxx 訂閱
附上程式碼....

[code delphi]
procedure TfrmMain.FormClose(Sender: TObject; var Action: TCloseAction);
begin
if MessageDlg('要離開系統?',mtConfirmation,[mbYes,mbNo],0)=mrYes then
begin
LogOut;
Action := caFree
end
else
Action := caNone;
end;

procedure TfrmMain.LogOut;
begin
if adDBConn.Connected then
begin
// 更新DB.Users.loggedin (登入狀態1-->0)
adCmd.Connection := frmMain.adDBConn;
adCmd.CommandText:= 'update users set loggedin=0'
' where username=''' UserInfo.Username '''';
adCmd.Execute;
end;
//
if ClientHandleThread <> nil then ClientHandleThread.Terminate;
if Client <> nil then
if Client.Connected then Client.Disconnect;
//
tmAutoConnSvr.Enabled := False;
tmShowStatus.Enabled := False;
end;

procedure TfrmMain.tmAutoConnSvrTimer(Sender: TObject);
var
i : integer;
Temp : TComponent;
strMsg : string;
begin
strMsg := '';
//
ShowMsg('正主動重新連線到 Sever ...');
// Keep at
window
for i := 0 to Componentcount - 1 do
begin
Temp := Components[i];
if (Temp is TForm) then
begin
with TForm(FindComponent(Temp.Name)) do
begin
if (Name <> 'frmMain') and Showing then
close;
end;
end;
end;
// Set ClientHandleThread to
if (Sender AS TTimer).Tag = 0 then
begin
if ClientHandleThread.Terminated then
begin
ClientHandleThread := nil;
(Sender AS TTimer).Tag := (Sender AS TTimer).Tag 1;
end;
end;
// try to connect Server
if (Sender AS TTimer).Tag = 1 then
begin
//
try
FreeAndNil(Client);
Client := TIdTCPClient.Create(frmMain);
Client.Host := Login.SVR;
Client.Port := 24451;
Client.Connect(1000);
//
(Sender AS TTimer).Tag := (Sender AS TTimer).Tag 1;
ShowMsg('重新連線到 Server 成功。');
except
on E : exception do
begin
plCenter.Color := clRed;
strMsg := '重新連線到 Server 失敗。';
end;
end;
//
ShowMsg(strMsg); StatusBar.Panels[4].Text := strMsg;
end;
// Re-Connect DB & Re-Create ClientHandleThread
if (Sender AS TTimer).Tag = 2 then
begin
// 若 Client 至 Server 之間的網路線路有問題 (例如:突然拔掉 Client 網路線)
// adDBConn 的連線狀態雖然仍保持 "TRUE",但實際用 [netstat] 觀測已經失效
if adDBConn.Connected then
adDBConn.Close;
//
try
adDBConn.Open;
if adDBConn.Connected then ShowMsg('重新連線到本機資料庫成功。');
//
ClientHandleThread := TClientHandleThread.Create(True);
ClientHandleThread.FreeOnTerminate:=True;
ClientHandleThread.Priority := tpLower;
ClientHandleThread.Resume;
//
(Sender AS TTimer).Tag := (Sender AS TTimer).Tag 1;
except
on E: Exception do
begin
plCenter.Color := clRed;
strMsg := '重新連線到本機資料庫失敗。';
end;
end;
//
plCenter.Color := clSkyBlue;
strMsg := 'Stop Timer.';
ShowMsg(strMsg); StatusBar.Panels[4].Text := strMsg;
//
(Sender AS TTimer).Enabled := False;
(Sender AS TTimer).Interval:= 2000;
(Sender AS TTimer).Tag:=0;
end;
end;

procedure TfrmMain.tmShowStatusTimer(Sender: TObject);
var
blCheck : boolean;
strMsg : string;
begin
if ClientHandleThread = nil then
StatusBar.Panels[4].Text := 'ClientHandleThread is nil';
blCheck := False;
StatusBar.Panels[1].Text := FormatDateTime('yyyy/mm/dd HH:nn:ss', now);
// 每天固定時段->檢查資料庫 乙次
if DEFAULT_Prompt_Tm <> '' then
begin
strMsg := DEFAULT_Prompt_Tm ' <==> ' FormatDateTime('HH:nn:ss',Time);
if DEFAULT_Prompt_Tm = FormatDateTime('HH:nn:ss',Time) then
begin
blCheck := True;
strMsg := strMsg '.....BINGO!!';
end;
//test
//ShowMsg(strMsg);
end
else
if (SecondOf(now)=0) and (MinuteOf(now)=0) and (HourOf(now)=9) then
blCheck := True;
if blCheck then
begin
btnChkInformClick(Self);
end;
end;
[/code]

===================引 用 careychen 文 章===================
大大的問題,小弟試的時候是不會,但我是用 indy 10 的,不知道有沒有差
或是您可以 Po 部份的程式碼來看看是不是您中間有寫了什麼造成這段訊息的出現??
編輯記錄
lkkplayer 重新編輯於 2008-07-20 08:45:25, 註解 無‧
careychen
尊榮會員


發表:41
回覆:580
積分:959
註冊:2004-03-03

發送簡訊給我
#4 引用回覆 回覆 發表時間:2008-07-20 10:58:04 IP:59.126.xxx.xxx 訂閱
看了您的程式碼,建議你查一下 ClientHandleThread , 因為這個雖然對他下了 Terminate, 
但他如果是被用來一直讀 Server 傳來的訊息,那實際上這個 Thread 是沒有停止的哦~~!
我假設你的 ClientHandleThread 的 OnExecute 的寫法是這樣


[code delphi]
procedure TClientHandleThread.OnExecute;
begin
while Not Client.Disconnected do
begin
// Indy 10 的語法, 了解小弟的意思就行
// 那這個 Thread 其實是卡在這邊一直在等著由 Server 傳來的訊息
// 所以雖然下了 Terimate ,但【還是卡在這裡哦!!】
Data := Client.IOHandler.ReadLn;
Synchronize(HandleFunctionName);
end;
end;
[/code]

當最後你對他下了

if ClientHandleThread <> nil then ClientHandleThread.Terminate; <== 只是標記要結束,但未真正結束
if Client <> nil then
if Client.Connected then Client.Disconnect; <== 但這行一執行後,引發 Thread 內等著 ReadLn 的指令錯誤

你先查看看是不是因為如此造成的
------
價值的展現,來自於你用哪一個角度來看待它!!
lkkplayer
一般會員


發表:26
回覆:59
積分:17
註冊:2006-11-22

發送簡訊給我
#5 引用回覆 回覆 發表時間:2008-07-20 23:53:10 IP:218.169.xxx.xxx 訂閱
我的程式碼如下:這樣寫會有問題嗎?
[code delphi]
procedure TClientHandleThread.Execute;
begin
while not Terminated do
begin
if not Client.Connected then
Terminate
else
try
Client.ReadBuffer(CB, Sizeof(CB));
Synchronize(HandleInput);
except
on E:Exception do
begin
//
ShowMsg('ClientHandleThread Excute Error ::' E.Message);
if Client.Connected then Client.Disconnect;
frmMain.tmAutoConnSvr.Enabled := True;
end;
end;
end;
end;

[/code]
careychen
尊榮會員


發表:41
回覆:580
積分:959
註冊:2004-03-03

發送簡訊給我
#6 引用回覆 回覆 發表時間:2008-07-21 13:08:25 IP:218.210.xxx.xxx 訂閱
平常你可以觀察一下,程式應該是一直停在  Client.ReadBuffer(CB, Sizeof(CB));    
這一行,除非有訊息進來,否則他是不會動的,所以你下 Termiate 時,
他還是會停在那一行,但後來下了 Disconnect 時,他會觸發這一行的錯誤,
因為你現在是 Design mode 所以會看到這個訊息,
但是因為你有寫 try...except.. end 所以你在 RunTime Mode 時,
應該是看不到這行錯誤的,程式會正常的關閉,對嗎?

要測試的話,在你的 Main form 上放一個 button ,按下 Click 後,裡面寫

Client.Disconnect; 你看一下引發的訊息是不是一樣的

===================引 用 lkkplayer 文 章===================
我的程式碼如下:這樣寫會有問題嗎?
[code delphi]
procedure TClientHandleThread.Execute;
begin
while not Terminated do
begin
if not Client.Connected then
Terminate
else
try
Client.ReadBuffer(CB, Sizeof(CB)); //< == 你可以看看是不是在這邊 Waiting
Synchronize(HandleInput);
except
on E:Exception do
begin
//
ShowMsg('ClientHandleThread Excute Error ::' E.Message);
if Client.Connected then Client.Disconnect;
frmMain.tmAutoConnSvr.Enabled := True;
end;
end;
end;
end;

[/code]
------
價值的展現,來自於你用哪一個角度來看待它!!
編輯記錄
careychen 重新編輯於 2008-07-21 13:10:11, 註解 無‧
careychen 重新編輯於 2008-07-21 13:12:30, 註解 無‧
lkkplayer
一般會員


發表:26
回覆:59
積分:17
註冊:2006-11-22

發送簡訊給我
#7 引用回覆 回覆 發表時間:2008-07-22 09:36:04 IP:210.202.xxx.xxx 訂閱
careychen大大:

我依照你說的測試方法,Main form 上放一個 button ,按下 Click 後,裡面寫
Client.Disconnect; 在偵錯模式下,就會出現那個錯誤訊息,不知道是不是因為這個樣子
導致我直接執行程式檔時,然後離開,蠻常會出現那種程式發生問題,叫我關閉,
問我是否回報此問題或不回報微軟的確認視窗,這個問題有方法解決嗎?

===================引 用 careychen 文 章===================
平常你可以觀察一下,程式應該是一直停在 Client.ReadBuffer(CB, Sizeof(CB));
這一行,除非有訊息進來,否則他是不會動的,所以你下 Termiate 時,
他還是會停在那一行,但後來下了 Disconnect 時,他會觸發這一行的錯誤,
因為你現在是 Design mode 所以會看到這個訊息,
但是因為你有寫 try...except.. end 所以你在 RunTime Mode 時,
應該是看不到這行錯誤的,程式會正常的關閉,對嗎?

要測試的話,在你的 Main form 上放一個 button ,按下 Click 後,裡面寫

Client.Disconnect; 你看一下引發的訊息是不是一樣的

===================引 用 lkkplayer 文 章===================
我的程式碼如下:這樣寫會有問題嗎?
[code delphi]
procedure TClientHandleThread.Execute;
begin
while not Terminated do
begin
if not Client.Connected then
Terminate
else
try
Client.ReadBuffer(CB, Sizeof(CB)); //< == 你可以看看是不是在這邊 Waiting
Synchronize(HandleInput);
except
on E:Exception do
begin
//
ShowMsg('ClientHandleThread Excute Error ::' E.Message);
if Client.Connected then Client.Disconnect;
frmMain.tmAutoConnSvr.Enabled := True;
end;
end;
end;
end;

[/code]
careychen
尊榮會員


發表:41
回覆:580
積分:959
註冊:2004-03-03

發送簡訊給我
#8 引用回覆 回覆 發表時間:2008-07-22 23:32:03 IP:59.126.xxx.xxx 訂閱
你改像下面這樣試試,不過看你的程式碼似乎是用 Indy9 的,我現在是用 Indy 10  的
不知道會不會有差別,至少我現在是這樣用的,在 Indy 10 上沒有出現錯誤訊息


[code delphi]
procedure TClientHandleThread.Execute;
begin
try // 多加一層 Try Except
while not Terminated do
begin
if not Client.Connected then
Terminate
else
try
Client.ReadBuffer(CB, Sizeof(CB));
Synchronize(HandleInput);
except
on E:Exception do
begin
// 下面這行 Showmsg 取消
//ShowMsg('ClientHandleThread Excute Error ::' E.Message);
if Client.Connected then Client.Disconnect;
frmMain.tmAutoConnSvr.Enabled := True;
end;
end;
end;
except
Self.Terminate;
end;
end;
[/code]
------
價值的展現,來自於你用哪一個角度來看待它!!
lkkplayer
一般會員


發表:26
回覆:59
積分:17
註冊:2006-11-22

發送簡訊給我
#9 引用回覆 回覆 發表時間:2008-07-25 21:52:00 IP:218.169.xxx.xxx 訂閱
careychen大大:

試用你的方法,似乎已經不會再出現錯誤訊息了,持續觀察中。
感謝你^^"。
另外想請教你一件事,有沒有啥書或者文件網站之類的有講多執行緒與工作排程
多執行緒的控制權轉移真的非常難搞>"<


===================引 用 careychen 文 章===================
你改像下面這樣試試,不過看你的程式碼似乎是用 Indy9 的,我現在是用 Indy 10 的
不知道會不會有差別,至少我現在是這樣用的,在 Indy 10 上沒有出現錯誤訊息


[code delphi]
procedure TClientHandleThread.Execute;
begin
try // 多加一層 Try Except
while not Terminated do
begin
if not Client.Connected then
Terminate
else
try
Client.ReadBuffer(CB, Sizeof(CB));
Synchronize(HandleInput);
except
on E:Exception do
begin
// 下面這行 Showmsg 取消
//ShowMsg('ClientHandleThread Excute Error ::' E.Message);
if Client.Connected then Client.Disconnect;
frmMain.tmAutoConnSvr.Enabled := True;
end;
end;
end;
except
Self.Terminate;
end;
end;
[/code]
careychen
尊榮會員


發表:41
回覆:580
積分:959
註冊:2004-03-03

發送簡訊給我
#10 引用回覆 回覆 發表時間:2008-07-25 22:16:08 IP:59.126.xxx.xxx 訂閱
呵,不客氣能夠解決你的問題才是最重要的

另~~~ 你說的書籍和資料,我還沒買過這方面的書籍,其實我大部份都是在下面這三個地方找到答案

1、KTop
2、大陸的 CSDN
3、Google (其實大部份的解答還是指向1 和 2)

不過,你要找有 Thread 的相關東東,找找 CriticalSection 這個關鍵字
有些文章提到這個名詞時會對 Thread 有一些解釋,會增加你對 Thread 的觀念

或是 Indy 的 IdThreadComponent 他是直接實作 TThread 變成一個元件也可以參考看看

------
價值的展現,來自於你用哪一個角度來看待它!!
系統時間:2024-04-26 7:10:36
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!