多播套接字用于多人游戏

3
我正在研究多人游戏中服务器和客户端通信的结构。我得出结论,由于UDP使用“射击并忘记”的方式,不会阻塞应用程序,因此UDP是最好的选择。我还将使用TCP发送需要可靠性的数据包,例如在登录过程中和信息交换(如更改服务器、更改地图、更新等)期间。它还将运行基于IRC的聊天室(所有命令实际上都是IRC风格的自定义消息)。
我想知道在服务器和客户端之间发送交互消息(移动、咒语、物品、动作等)的最佳方法是什么。
通过阅读一些文档,我了解到MulticastSocket。
我的问题是:
是向所有客户端发送持续的信息流更好,为每个玩家启动一个线程(就像在TCP通信中所做的那样),其中每个DatagramSockets将侦听队列并将每条新消息发送到其客户端。这意味着所有地图和所有移动(假设可以有50个玩家遍布全地图)将发送给所有玩家,并且每个数据包必须更大才能包含所有这些信息。 还是更好地为每个地图使用一个线程,仅在某些玩家位于该特定地图内时才激活,使用组播通信,仅向位于该地图内的玩家发送消息,并使用MulticastSocket侦听。
我了解到使用组播存在防火墙或路由器问题,但我无法想象这些问题可能会有什么不同(与普通UDP不同)。
应用程序应该可以被任何人使用,而且配置问题很少。

有些路由器被配置为阻止多播数据包,因为它们可能会在网络上引起不必要的流量。想象一下恶意用户使用通配符地址在整个网络上发送虚假的多播数据包。数据包的范围也很重要。相比于像私有局域网这样的小型网络,如果数据包在更大的网络(如互联网)上,它们就不太可能到达。至于是否可以避免这种情况(同时仍然使用多播),我无法给您一个好的答案。 - initramfs
我并不是固守组播,事实上,问题是关于使用UDP创建通讯服务器和客户端的最佳方式,而我可以毫无问题地进行更改。也许我可以创建一个模拟组播套接字的类,将同一数据包同时发送给多个客户端?但我不知道它是否足够快。感谢您的评论。 - Gianmarco
我更关心带宽而不是速度。与传统的网络结构需要每个连接一个数据包相比,多播数据包只发送一次。如果服务器上有50个玩家,则必须考虑50倍的带宽,而不是单个连接用户。我只是在提供关于多播数据包的见解。 - initramfs
我不清楚单线程连接的结构可能是什么,但我也不明白为什么你告诉我每个玩家一个线程(这意味着每个玩家一个套接字)会更快。我原本想为每个玩家使用一个线程,但我从未考虑过可能出现的同步问题。再次感谢您的评论。 - Gianmarco
谢谢你,你给了我很多想法,为什么不试着把它们放在一个答案中,收到我的赞成票呢? - Gianmarco
显示剩余3条评论
1个回答

3
看看你上面的场景,你需要决定你的应用程序是否绝对需要TCP连接,因为TCP连接需要一个线程来处理每个TCP连接,没有例外(除非使用nio)。
现在针对程序的UDP部分,你有两个基本选择:
a)你为所有玩家生成一个接收数据报包的线程。在这种情况下,所有玩家都将其数据报包发送到单个接收器,然后该接收器决定如何处理数据。可以将此数据发送到各种队列以供其他线程进行处理。可以使用单个线程或多个线程(每个玩家)向所有玩家发送数据。
优点: - 资源使用率低 - 程序开销低
缺点: - 可能会出现网络缓慢(由于大量数据包朝向同一套接字) - 更高的数据包丢失率(再次由于大量数据包传输到同一套接字) - 序列化处理 - 断开连接事件混乱且难以处理
b)你为每个玩家生成一个线程,并侦听每个玩家的不同端口。在这种情况下,所有玩家都有自己的处理程序线程,可以直接处理数据或将其发送到中央处理队列。通过这样做,可以并行处理数据,从而实现更快的处理速度和更高的资源使用率。同步也需要特别关注,可能需要使用原子和可重入读/写锁。向套接字写回通常应在另一个“每个玩家线程”上进行。
优点: - 并行处理 - 模块化(将每个玩家的所有处理代码放在一个线程中,在玩家加入时启动线程) - 断开连接更容易处理,不会对其他玩家造成问题。 - 快速网络响应,同时接收数据包。
缺点: - 资源使用率高(更多对象) - 高同步开销 - 高线程计数(可能是玩家比例的2〜4倍)
无论哪种情况,使用TCP都需要至少一个线程来处理每个玩家。问题是你是否愿意为了获得服务器更流畅、更快速的响应而使用更多的资源。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接