首先,让我解释一下我的设置。我的服务器设置为Marshaled单例对象:
RemotingServices.Marshal(lsServer, ServerObject.objectUri);
为了从服务器到客户端进行双向通信,客户端激活ServerObject,然后传入自己的ClientObject(也是MarshalByRefObject),服务器使用ClientObject与客户端进行对话: / p>
var lsClient = new ClientObject();
var lsServer = (ServerObject)Activator.GetObject(typeof(ServerObject), url);
lsServer.attach(lsClient);
当调用 attach 方法时,服务器获取ClientObject并将其存储在List中:
public void attach(ClientObject client) {
clientList.Add(client);
}
然后,服务器可以调用名为“SendMessage”的ClientObject上的方法,以便与其列表中的每个客户端进行通信:
foreach(var c in clientList) {
c.SendMessage("Hello");
}
这种方法很有效,直到遇到断开连接的客户端。在这种情况下,会拒绝客户端拒绝连接的错误。我可以捕获错误,但问题是我无法从服务器的List中删除对ClientObject的引用。以下在客户端断开连接时重新抛出“连接被拒绝”异常:
clientList.Remove(badClient);
所以有几个问题:
1-有没有办法检测客户端的连接状态而不必捕获错误?
2-当我检测到已断开连接的客户端时,为什么从服务器列表中删除对象的尝试似乎与客户端“通信”(从而导致再次抛出异常?)
修改
正如Patrick在下面指出的那样,从列表中删除会导致List迭代我的对象并对它们进行比较(调用.Equals) - 这就是导致我的ClientObject再次尝试通信然后抛出异常的原因
要解决此问题,我改为将List更改为一个字典,该字典是在我的客户端连接到服务器时提供的唯一ID。然后我使用该唯一ID删除客户端。
我从未找到确定客户端是否已断开连接而不是捕获错误的直接方法。
答案 0 :(得分:0)
在#2上不确定。但是,如果您尝试从foreach循环内部移除clientList
中的项目,则不能。这是一个.NET规则 - 在枚举时不会更改可枚举对象的内容。
相反,如果您在foreach循环中捕获错误,请将其存储在另一个列表中(“已断开连接”列表)。在foreach之后,从clientList
删除所有已断开连接的项目。