c# multithreaded server - Generic client collection being a possible issue
我正在使用异步套接字开发C中的游戏emu。目前,程序使用一个列表来存储客户机。
如果客户机加入一个房间,则会创建一个本地列表,存储来自该特定房间的所有用户(我使用的是findall(x=>x.room==this.room))。这个列表是必需的,因为当一个客户端改变房间时,服务器必须发送一个特定的包来通知一个客户端加入的房间中的所有其他玩家。
像这样:
1 2 3 4 5 | 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 bool会更改其值吗?我想不是。它只影响主/原始列表。
我担心的是,如果发生这种情况,那么服务器可以尝试将数据发送到一个关闭的套接字(因为检查此情况的bool,connectionfire,在需要时不会更改其值)。
为了避免这类事情,我应该避免克隆列表,直接在主列表上使用for吗?(我最初做这个本地列表的事情是为了避免集合被修改异常)。
你好像在问两个问题
您关心的是以线程安全的方式管理集合
当另一方断开连接时,您关心的是尝试通过套接字发送数据。
在信息有限的情况下回答您的问题
如果有多个线程访问您的列表,那么您需要一个线程安全实现。你可以自己用锁等工具滚动一个,也可以使用新的.NET工具。http://msdn.microsoft.com/en-us/library/dd997305.aspx关于您对"本地"列表的评论,简单的答案是不要制作本地副本,除非您想冒数据过时的风险。使用线程安全列表并直接枚举它。如果使用LINQ表达式,则可以进行复杂的查询,而无需复制集合。
当通过套接字发送数据时,当另一方不在时,您总是需要处理这种情况。如果它们消失了,那么您必须处理错误并决定是否要重试,或者继续执行下一个任务。你无法提前预测另一方何时死亡,或者是否会优雅地告诉你(例如"再见")。因此,在一个非常简单的解决方案中,将您的发送包包装在一些异常处理/日志中。