1

我正在使用异步套接字在 c# 中开发游戏 emu。目前,该程序使用 List 来存储客户端。

如果客户加入一个房间,则会创建一个本地列表来存储来自该特定房间的所有用户(我正在使用 FindAll(x => x.room == this.room))。该列表是必需的,因为当客户端更改房间时,服务器必须发送特定数据包来通知客户端加入的房间中的所有其他玩家。

像这样的东西:

var localist = Clients.FindAll(x=> x.room == this.room);
foreach(stateObj client_in_room in locallist)
{
    client_in_room.sendPacket(...); //what if the client_in_room disconnected in the meanwhile?
}

当客户端断开连接时,它 (stateObj) 会从原始客户端列表中删除(并且客户端套接字关闭),并且名为 ConnectionFired 的客户端可变布尔值更改为 false(这意味着在执行套接字操作之前检查用户是否仍然连接像 BeginSend 等)。如果一个客户端从房间 X 断开连接,而其他客户端加入房间 X 怎么办?它肯定仍会在本地列表中,但 ConnectionFired 布尔值会改变它的值吗?我猜不是。它只影响主/原始列表。

我担心的是,如果发生这种情况,那么服务器可以尝试将数据发送到一个关闭的套接字(因为检查这个的布尔值 ConnectionFire 在需要时不会改变它的值)。

为了避免这种事情,我应该避免对列表进行克隆,并直接在主列表上使用for吗?(我最初做这个 locallist 的事情是为了避免集合被修改异常)。

4

1 回答 1

1

悠悠好像在这里问了两个问题

  1. 您担心以线程安全的方式管理集合

  2. 您担心在对方断开连接时尝试通过套接字发送数据。

在信息有限的情况下回答您的疑虑

  1. 如果您有多个线程访问您的列表,那么您需要一个线程安全的实现。您可以使用 lock 等自己滚动一个,也可以使用新的 .NET 之一。 http://msdn.microsoft.com/en-us/library/dd997305.aspx 关于您对“本地”列表的评论,简单的答案是不要制作本地副本,除非您要冒着拥有过时数据的风险。使用线程安全列表并直接枚举它。如果您使用 LINQ 表达式,那么您可以进行复杂的查询,而无需复制您的集合。

  2. 通过套接字发送数据时,您总是需要处理对方离开的情况。如果它们已经消失,那么您必须处理错误并决定是要重试还是继续下一个任务。您根本无法提前预测另一方何时可能会死,或者它是否会以优雅的方式告诉您(例如“再见”)。因此,在一个非常简单的解决方案中,将您的 sendPacket 包装在一些异常处理/日志记录中。

于 2013-09-10T16:14:52.903 回答