关于Indy10中IdTcpServer与IdTcpClient断开连接的问题 |
答題得分者是:Hero
|
zhweizw
一般會員 發表:7 回覆:16 積分:9 註冊:2008-01-12 發送簡訊給我 |
各位大大,小弟在使用Indy10中遇到了问题,此问题困扰我许久,寻遍互联网不得其解,请大大在百忙之中指点一下小弟,感激涕零!
IdTcpClient与IdTcpServer建立连接后,如果在Server端选择一条已连接的Client,执行DisConnect方法后,Client端不会触发OnDisConnected事件(但此时Client端的Connected属性是False,说明连接确实已经断开,但却没有触发OnDisconnected事件)。 例如: [code delphi] procedure TForm1.Btn1Click(Sender:TObject); var i:integer; List:TList; begin List:=IdTcpServer1.Contexts.LockList; try for i:=0 to List.Count -1 do begin if TIdServerContext(List.items[i]).binding.Peerip = '192.168.1.6' then begin TIdServerContext(List.items[i]).Connection.Disconnect; end; end; finally IdTcpServer1.Contexts.UnLockList; end; end; [/code] 执行上面的代码后,客户端'192.168.1.6' 链接断开(connected属性为FALSE),但没有触发OndisConnected事件。 相反,如果在Client端主动执行DisConnect方法,Server与Client端都能触发OnDisconnected事件。 由于IdTcpClient继承自TIdTcpConnection类,所以小弟查看了IdTcpConnection.pas单元的源码发现:Client端的OnDisconnected事件只在自己的DisConnect方法中触发,其他位置没发现有触发此事件的代码。所以造成了Server端断开连接而Client端不触发OnDisconnected事件的现象。 那么,如果在Server执行DisConnect 方法后,如何在Client端触发Ondisconnected事件呢,小弟想到2个方法: 1、在Client端用timer定时检测; 2、在Server端执行Disconnect方法前先通知Client。 但是上面2种方法用起来总感觉不爽,起码不够“专业”。 1、请问大大,还有什么更好的方法吗? 2、小弟不明白,IdTcpClient的OnDisconnected事件为什么只设计在自己的DisConnect方法中才触发呢? 3、是不是小弟理解错误了?如果是,请大大指点,万分感谢!!! 另外,小弟发现在TIdTCPConnection单元的TIdTCPConnection.Disconnect方法中执行了DisconnectNotifyPeer方法(519行),该方法在该单元的402行有说明: // This is called when a protocol sends a command to tell the other side (typically client to // server) that it is about to disconnect. The implementation should go here. 大概的意思是,当协议(Tcp/ip)发送一个命令通知对方关于断开连接时调用此方法,典型的应用时客户端发送到服务器端。 但是DisconnectNotifyPeer方法的实现部分却是空的,没有执行任何代码,并且在其子类中也未被重载或覆盖,难道需要我们自己override吗? |
careychen
尊榮會員 發表:41 回覆:580 積分:959 註冊:2004-03-03 發送簡訊給我 |
|
zhweizw
一般會員 發表:7 回覆:16 積分:9 註冊:2008-01-12 發送簡訊給我 |
感谢Carey的解答,看来我只能使用你说的方法了。
另外,大大们有时间看一下IdConnection.pas源码,我发现TIdTcpClient.OndisConnected事件,仅仅在TIdTcpClient.Disconnect发放中触发,这样设计不合理呀? 是不是我没搞懂呢? ===================引 用 careychen 文 章=================== 就照你上面說的,用 Timer 的時間 Client 自行檢測,因為網路的環境並不一定是穩定的,單靠 Server 並不一定能絕對通知到 Client ,但 Client 可以一定時間內與 Server 做一個類似 Ping 的動作,超時沒有得到 Server 的回應,就該認定斷線,最好雙方都做這個功能,不是只有 Client 才需要 |
Hero
一般會員 發表:3 回覆:10 積分:12 註冊:2002-07-11 發送簡訊給我 |
Indy的client端元件都不是事件驅動的,所以要靠自己來,client這邊只有在讀、寫或是呼叫Connected()才會檢查連線
一般來說會用Thread來進行操作(實在搞不懂Indy都發展到10了,為什這段不一起寫呢?) 我自己寫過一個TCPClient的小程式來debug Server的,參考看看 [code cpp] void __fastcall TReceiveThread::Execute() { UnicodeString Msg; TIdBytes Buffer; int Count; bool NeedToConnect = true; while (!Terminated) { try { if (!Enabled) { WaitForSingleObject(FEnabledEvent, INFINITE); continue; } if (FClient->Connected()) { FClient->IOHandler->CheckForDataOnSource(100); //先讀 if ((Count = FClient->IOHandler->InputBuffer->Size) > 0) { FClient->IOHandler->ReadBytes(Buffer, Count, false); if (FReceiveRingQueue) FReceiveRingQueue->Push(&Buffer[0], Count); } //後寫 if ((Count = FExportRingQueue->Count) > 0) { Buffer.set_length(Count); FExportRingQueue->Pop(&Buffer[0], Count); FClient->IOHandler->Write(Buffer, Count, 0); } } else { //當Server端主動斷開連線時,若剛好不是在讀取、寫入操作則不會引起Exception而跳入catch區段 //這樣會導致非預期自動重連 //加入NeedToConnect用來判斷是否需要連線, //若不需要則跳入catch區段進行是否要自動重連與定時重連的檢查 if (NeedToConnect) { NeedToConnect = false; Msg = Format("Ready to connect to %s:%d...", ARRAYOFCONST((FHost, FPort))); SendMessage(FHandle, JS_MSG, 0, (DWORD)&Msg); if (!CompareText(FBoundIP, "Default")) FClient->BoundIP = EmptyStr; else FClient->BoundIP = FBoundIP; FClient->Host = FHost; FClient->Port = FPort; FClient->Connect(); } else throw Exception(""); } } catch (Exception &E) { if (!E.Message.IsEmpty()) SendMessage(FHandle, JS_MSG, 0, (DWORD)&(E.Message)); WaitForSingleObject(FEvent, 1000); //If you simply need to close a connection, //you probably should call the close method in the IOHandler or Socket (when assigned). //直接呼叫FClient->Disconnect()可能會發生例外 if (FClient->Socket) FClient->Socket->Close(); //檢查是否連線有問題就自動斷線 if (FAutoDisconnect) { FEnabled = false; PostMessage(FHandle, JS_AUTODISCONNECT, 0, 0); continue; } for (int i=FReconnectSecond; i>0; --i) { if (Terminated || !Enabled) break; Msg = Format("After %d seconds, automatically re-connect to %s:%d.", ARRAYOFCONST((i, FHost, FPort))); SendMessage(FHandle, JS_MSG, 0, (DWORD)&Msg); WaitForSingleObject(FEvent, 1000); } NeedToConnect = true; } } } [/code] |
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |