c# 多线程服务器 - 泛型客户端集合是一个可能的问题

本文关键字:一个 问题 服务器 多线程 泛型 客户端 集合 | 更新日期: 2023-09-27 18:30:52

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

如果客户端加入一个房间,则会创建一个本地列表,存储该特定房间的所有用户(我正在使用 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)将从原始客户端列表中删除(并且客户端套接字关闭),并且名为ConnectionFireed的客户端易失性布尔值更改为false(它旨在检查用户是否仍在连接,然后再执行套接字操作,如BeginSend等)。如果客户端与房间 X 断开连接,而其他客户端加入房间 X 怎么办?它肯定仍然在本地列表中,但 ConnectionFired 布尔值会改变它的值吗?我想不是。它只影响主/原始列表。

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

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

c# 多线程服务器 - 泛型客户端集合是一个可能的问题

Yuo 你似乎在这里问了两个问题

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

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

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

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

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