赞助商的续订功能不再被呼叫

时间:2013-09-22 11:11:51

标签: vb.net ipc remoting

我有一台服务器和客户端进程都在同一台机器上运行。客户端创建一个CAO对象并使用它一段时间(<1s到几小时)。它占用了大量内存,所以我希望在客户端完成后尽快处理掉这个对象。

我将InitialLeaseTime和RenewOnCallTime设置为10s(0.1s和15s具有相同的问题)。我可以看到赞助商的Renweal功能每10分钟就会被召唤几分钟。几分钟后,客户开始做不同类型的工作,赞助商停止被叫(这似乎是错误的)。几分钟后,当客户端尝试使用远程对象时,它会抛出一个异常,说它已断开连接(可能是因为赞助商长时间没有被调用)。

似乎租赁经理在一段时间后停止尝试检查租约。

2 个答案:

答案 0 :(得分: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(),那么该对象将永远保持活跃状态​​。但在我的情况下,服务器由客户端启动和停止,因此无关紧要。

答案 1 :(得分:1)

长时间的中间响应,但我认为其他人也可能遇到这个问题,所以这里。

我建议在VS中附加到您的服务器,进入“调试”菜单,选择“例外”,&#39;然后检查System.Net.Sockets.SocketException&#39;例外。这将在发生的任何套接字异常时中断程序。

在我的情况下,我最近开始看到这个问题,并且在经过大量调试后注意到在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相关对象何时断开连接,编组和解组。这对于弄清楚发生了什么是一个很大的帮助,因为我可以看到一个对象正在被断开,而不是从呼叫停止发生的事实推断它。