2013-09-22 85 views
1

我有一臺服務器和客戶端進程都運行在同一臺機器上。客戶創建一個CAO對象並在一段時間內使用它(< 1個小時)。它需要很多內存,所以我想在客戶端完成後儘快處理這個對象。贊助商的更新功能停止被稱爲

我將InitialLeaseTime和RenewOnCallTime設置爲10秒(0.1s和15s有相同的問題)。我可以看到,幾分鐘後,贊助商的Renweal功能每10秒鐘就會調用一次。幾分鐘後,客戶開始做不同類型的工作,並且贊助商停止被叫(這看起來是錯誤的)。幾分鐘後,當客戶端嘗試使用遠程對象時,它會拋出一個異常,說它已經斷開連接(可能是因爲贊助者很久沒有被調用過)。

似乎租賃經理不知何故停止嘗試檢查租賃一段時間後。

回答

1

很長的時間之間的響應,但我認爲別人也可能會遇到這個問題,所以在這裏。

我建議在VS中連接到你的服務器,進入Debug菜單,選擇'exceptions',然後檢查'System.Net.Sockets.SocketException'異常。這會在發生任何套接字異常時破壞您的程序。

就我而言,我最近開始看到這個問題,經過大量的調試發現就在Lease Manager停止檢查租約之前,發生了一個SocketException。在我的情況,插座的例外是AddressChangedCallback,與堆棧跟蹤:

1  [External Code] 
2  System.dll!System.Net.Dns.TryGetAddrInfo(string name = "me.win.mycompany.com", System.Net.AddressInfoHints flags, out System.Net.IPHostEntry hostinfo = null) 
3  System.dll!System.Net.Dns.GetAddrInfo(string name) 
4  System.dll!System.Net.Dns.InternalGetHostByName(string hostName, bool includeIPv6) 
5  System.dll!System.Net.Dns.GetHostEntry(string hostNameOrAddress) 
6  System.Runtime.Remoting.dll!System.Runtime.Remoting.Channels.CoreChannel.UpdateCachedIPAddresses() 
7  System.Runtime.Remoting.dll!System.Runtime.Remoting.Channels.CoreChannel.OnNetworkAddressChanged(object sender = null, System.EventArgs e = {System.EventArgs}) 
8  mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx) 
9  mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx) 
10  mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state) 
11  System.dll!System.Net.NetworkInformation.NetworkChange.AddressChangeListener.AddressChangedCallback(object stateObject, bool signaled) 
12  mscorlib.dll!System.Threading._ThreadPoolWaitOrTimerCallback.PerformWaitOrTimerCallback(object state, bool timedOut) 
13  [External Code] 

AddressChangedCallback,其中,於我而言,似乎與一個網絡適配器下降或正在改變(你可以看到你的網絡適配器通過持有windows+r然後輸入ncpa.cpl - 如果您有兩個或更多可能的事件是由您在它們之間切換引起的)似乎會導致套接字停止讀取。這意味着下次LeaseManager使用遠程連接來檢查遠程租約時,它無法從死鎖套接字讀取租約。所以,它做了合理的事情 - 斷開贊助商,因爲我們不能再閱讀它,並將其從贊助商名單中刪除。而且由於它可能是所討論對象的唯一讚助商,因此該對象得不到LeaseManger的贊助,讓它免費供GC最終接受。

解決此問題的一種方法是,在您的InitializeLifetimeService()方法中,返回null而不是設置超時。這繞過了LeaseManager,因此您不必擔心因爲套接字異常而被取消贊助的對象,因爲您首先不使用租約。但是,如果您像我一樣,這也意味着您可以在服務器上在一段時間內建立對象和非託管資源的堆積。圍繞我看到的構建問題的唯一方法是讓您的遠程對象實現Dispose,並確保您在完成時處置它。基本上,你不能依賴LeaseManager處理垃圾收集,所以你必須自己做GC,這是一種老式的方式。

另外值得注意組成:ITrackingHandler對象將允許您跟蹤時LeaseManager相關的對象斷開,編組和取消封送。這對於弄清楚發生了什麼是一個很大的幫助,因爲我可以看到一個對象正在斷開連接,而不是從電話停止發生的事實中推斷出來。

1

我已經將贊助商放在服務器上而不是客戶端上了。服務器端贊助商似乎已經足夠可靠地保持遠程對象的活性。

Class SelfSponsor 
    Implements ISponsor 
    Public Function Renewal(ByVal lease As ILease) As System.TimeSpan Implements ISponsor.Renewal 
     Return lease.RenewOnCallTime 
    End Function 
End Class 

而且班上MarshalByRef遠程對象:

Private Sponsor As SelfSponsor 

Public Sub SponsorYourself() 
    Sponsor = New SelfSponsor 
    DirectCast(GetLifetimeService(), ILease).Register(Sponsor) 
End Sub 

Public Sub UnSponsorYourself() 
    DirectCast(GetLifetimeService(), ILease).Unregister(Sponsor) 
End Sub 

不知怎的,如果它放在構造函數,因此客戶端創建對象後調用SponsorYourself立即SponsorYourself()代碼拋出異常。

如果服務器始終在運行並且客戶端來來去去,這將是一個糟糕的解決方案,因爲如果客戶端在沒有明確調用UnsponsorYourself()的情況下異常退出,那麼該對象將永遠保持活動狀態。但在我的情況下,服務器是由客戶端啓動和停止的,因此無關緊要。