.NET Remoting:如何处理断开连接的对象
首先,让我解释一下我的设置。我的服务器设置为 Marshaled 单例对象:
RemotingServices.Marshal(lsServer, ServerObject.objectUri);
为了从服务器到客户端进行双向通信,客户端激活 ServerObject,然后传入自己的 ClientObject(也是 MarshalByRefObject),服务器使用 ClientObject 来与客户端对话:
var lsClient = new ClientObject();
var lsServer = (ServerObject)Activator.GetObject(typeof(ServerObject), url);
lsServer.attach(lsClient);
当调用attach方法时,服务器获取ClientObject并将其存储在列表中:
public void attach(ClientObject client) {
clientList.Add(client);
}
然后服务器可以调用ClientObject上名为“SendMessage”的方法来与每个客户端进行通信列表中的客户端:
foreach(var c in clientList) {
c.SendMessage("Hello");
}
这非常有效,直到遇到已断开连接的客户端。在这种情况下,会抛出有关客户端拒绝连接的错误。我可以捕获该错误,但问题是我无法从服务器列表中删除对 ClientObject 的引用。每当客户端断开连接时,以下内容都会重新抛出“连接被拒绝”异常:
clientList.Remove(badClient);
因此有几个问题:
1-是否有一种方法可以检测客户端的连接状态而无需捕获错误?
2-当我确实检测到已断开连接的客户端时,为什么尝试从服务器列表中删除对象似乎与客户端“通信”(从而导致再次抛出异常?)
编辑
正如帕特里克下面指出的,从列表中删除会导致列表迭代我的对象并对它们进行比较(调用 .Equals) - 这就是导致我的 ClientObject 尝试再次通信并因此引发异常的原因。
为了解决这个问题,我将列表更改为字典,该字典在连接到服务器时关闭了客户端提供的唯一 ID。然后我使用该唯一 ID 删除客户端。
除了捕获错误之外,我从未找到直接的方法来确定客户端是否已断开连接。
First, let me explain a little bit about my setup. My server is setup as a Marshaled singleton object:
RemotingServices.Marshal(lsServer, ServerObject.objectUri);
In order to have two-way communication from the server to the client, the client activates a ServerObject, then passes in its own ClientObject (which is also a MarshalByRefObject) the server uses the ClientObject to talk back to the client:
var lsClient = new ClientObject();
var lsServer = (ServerObject)Activator.GetObject(typeof(ServerObject), url);
lsServer.attach(lsClient);
When the attach method is called, the server takes the ClientObject and stores it in a List:
public void attach(ClientObject client) {
clientList.Add(client);
}
The server can then call a method on the ClientObject called "SendMessage" to communicate to each client in its list:
foreach(var c in clientList) {
c.SendMessage("Hello");
}
This works great until a client is encountered that has disconnected. In this case, an error is thrown about the client refusing the connection. I can catch the error, but the problem is I cannot remove the reference to the ClientObject from the server's List. The following re-throws the "connection refused" exception anytime a client has been disconnected:
clientList.Remove(badClient);
So a couple of questions:
1- Is there a way to detect the connection state of a client without having to catch an error?
2- When I do detect a client that has disconnected, why does the attempt to remove the object from the server's list appear to "communicate" with the client (thus causing the exception to be thrown again?)
EDIT
As Patrick pointed out below, doing a Remove from a list causes the List to iterate my objects and do a comparison on them (calling .Equals) - this is what caused my ClientObject to attempt to communicate again and thus throw the exception.
To resolve it, I instead changed the List to a dictionary keyed off a unique ID supplied by my Client at the time of attaching to the server. Then I used that unique ID to remove the client.
I never did find a direct way for determining if a client had disconnected other than catching the error.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
不确定#2。但是,如果您尝试在 foreach 循环内从
clientList
中删除项目,则不能。这是一条 .NET 规则——在枚举可枚举对象时不得更改其内容。相反,如果您在 foreach 循环中捕获错误,请将其存储在另一个列表(“断开连接”列表)中。在 foreach 之后,从
clientList
中删除所有断开连接的项目。Not sure on #2. However, if you're trying to remove an item from
clientList
from inside the foreach loop, you can't. That's a .NET rule -- no changing the contents of an enumerable object while it's being enumerated.Instead, if you catch the error inside the foreach loop, store it in another list (a "disconnected" list). After the foreach, remove all of the disconnected items from the
clientList
.