6

我正在尝试设计一个应用程序,允许两个用户通过网络播放囚犯的

困境游戏(http://en.wikipedia.org/wiki/Prisoner%27s_dilemma)。

基本上,这涉及:

  • 比赛开始(第一轮)。
  • 玩家 1 选择合作或背叛。
  • 玩家 2 选择合作或背叛。
  • 然后显示彼此的决定
  • 第二轮开始
  • 等等。

我做了一些思考和搜索,我认为应用程序应该包含以下内容:

  • 接受传入 tcp/ip 连接的服务器类
  • Gui 客户端(单独的程序)
  • 对于每个连接(最多 2 个),服务器将创建一个新的 ConnectedClient 类。此类将包含两个玩家的机器/身份的详细信息。
  • Server 类和 ConnectedClient 类将连接/订阅每个事件,以便它们可以在例如服务器指令准备好传输给玩家或玩家已经将他们的输入传输到服务器时相互提醒。

我不确定最好的方法是使用单线程来完成工作,还是使用多线程。单线程显然会更容易,但我不确定这种情况是否可能 - 在需要 TCP/IP 连接之前我从未创建过应用程序,而且我不确定你是否可以监听两个传入连接一根线。

我在网上找到了以下指南,但似乎它在两个线程上打开了两个客户端,并且它们直接相互通信 - 绕过服务器(我需要控制游戏逻辑):http://www。 codeproject.com/Articles/429144/Simple-Instant-Messenger-with-SSL-Encryption-in-Cs

我非常感兴趣,如果您有任何关于如何实施应用程序(主要是服务器类)的建议,我将不胜感激。

我希望我已经清楚地解释了我的意图。提前致谢。

4

3 回答 3

8

我的第一个建议是在这里忘记 TCP/IP 和套接字。您绝对可以使用该技术堆栈来做到这一点,但是实现您想要的所有东西也会让您非常头疼。原因是此类任务的技术水平太低。我只会出于学术兴趣,或者如果我需要对通信进行巨大控制,或者如果我有非常高的性能要求,我会使用 tcp/ip 和套接字。

所以,我的第二个建议是看看 WCF 技术。如果您以前没有使用过它,请不要害怕。这并不难。如果您准备好为您的应用程序使用套接字,那么您绝对可以处理 WCF。对于您的任务,您可以使用任何 WCF 教程在 1-2 小时内从头开始创建基本通信。

因此,我将创建一个服务器 WCF 服务,该服务将具有一些包含您的业务逻辑的 API 函数。它可以托管在 Windows 服务、IIS 甚至控制台应用程序中。您的客户将使用该 WCF 服务,调用他们的函数,就像它是您项目中另一个本地类的函数一样。WCF 还可以帮助您执行您想要的事件(虽然它是一个更高级的主题)。你甚至可以忘记这里的线程,大多数事情都会开箱即用。

于 2012-11-12T17:54:53.457 回答
4

首先,正如其他人所说,尽可能多地分离你的游戏逻辑,这样基本的功能就不会过多地依赖于你的通信基础设施。

对于通信,WCF 可以处理任务。您可以让您的客户端向 IIS 中托管的服务发送请求,进行某种识别/身份验证,并打开一个双工通道,您的服务可以从该通道推送结果并传达新一轮的开始。

一旦一个客户端连接,它就会等待另一个客户端。当它发生时,它使用双工通道回调通知第一个客户端并等待它的选择。然后它询问第二个用户,等待它的响应。当它到来时,它会将结果通知给双方并重新开始游戏。

在实现中更深入一点:

您将获得具有一些操作的服务(如注册、推送决策,如果需要,还可以进行更多操作)。您还将定义一个回调接口,其中包含您的服务需要推送到客户端的操作(NotifyResult、RequestDecision,这些都是示例)。然后,您为映射到您的服务操作的客户端创建代理,并以公开事件并在服务推送消息时引发它们的方式实现回调操作。

一个用例:

客户端 A 创建代理,调用服务器上的注册。服务器接收调用,注册客户端并将回调对象保存在一个状态中。将建立双工连接。这意味着什么?这意味着(如果您使用 PollingDuplexBinding,您可能会这样做)从现在开始,客户端 A 中的代理对象将对服务器进行长轮询请求,检查是否有回调消息。如果没有,那么它会再次进行长轮询。如果有,它会调用代理中的回调方法,传递服务器已推送的数据。代理中的回调方法通常会引发事件或执行委托,由您选择。

客户端 B 连接(调用 Register),执行与 A 相同的操作,服务器注意到两个客户端已连接,通过其保存的回调请求对 A 的响应。这可能发生在 B 的 Register 调用的处理过程中,或者它可以被触发以在 B 的 register 调用中的新线程中执行(或者更好的是,在ThreadPool中运行或启动新的Task)。

客户端 A 将收到请求其选择的服务器回调。然后它可以通知用户并通过 UI 获得选择。对服务器进行新调用(例如,PushDecision)。服务器收到客户端 A 的选择,以同样的方式询问 B。一旦它有两个响应,它就会计算结果并将结果推送给客户端。

将双工通道与 PollingDuplex 与 WPF 一起使用的一个优点是,由于它使用长轮询,因此无需使用 80 以外的其他端口。

这绝不是最终的实现,只是给你一些想法的小指南,而不是给你一些模糊的建议。当然,使用 WCF 可能还有很多其他方法可以做到这一点。

我们可以首先假设应用程序每次只能处理两个用户,然后,如果您愿意,您可以扩大规模,使您的服务保持某种形式的状态,并使用锁定访问的映射表,作为另一个示例。

关于 WCF 的一些想法: 使用 Visual Studio 工具 (svcutil) 开始使用 WCF 开发是一种简单的方法,但我不喜欢这种方法。您没有很好地“了解” WCF 基础结构,您会被它用来生成代理的冗长魔法所束缚,并且您会失去灵活性,尤其是在特殊情况下,例如您可能想要使用的双工轮询。

另一种方法,即手动创建服务和代理,并不难,一旦你意识到你可以用它做什么,它就会变得非常有趣。与此相关,我可以给你一个建议:尽你所能让你的代理操作使用基于任务的异步模式(你可以在这里看到实现代理操作的不同方法)。当与新的 C# async/await关键字结合使用时,这将使您的代码更加简洁明了,并且您的 UI 将很容易实现。

我可以推荐一些链接来帮助您入门。其中一些是旧的,但非常具有教育意义。

  • 此链接中曾经有一篇很棒的 WCF 文章,但现在似乎已离线。幸运的是,我在此链接的文件中找到了可用的内容。
  • 涵盖了您的托管选项。
  • 关于 WCF 基础结构的主题:链接
  • 双工服务主题:链接 链接 链接
  • 基于任务的异步模式的主题:链接 链接 链接
于 2012-11-21T16:04:31.483 回答
1

如果您坚持所有用户都通过服务器进行通信并且您希望您的应用程序可扩展,那么我可以给您一个建议:

  1. 分离你的逻辑(通过理解你想在服务器上构建的逻辑的每一部分)

  2. 使您的类可以处理每个事务的多个用户

  3. 尽可能使用 IOCP

  4. 如果您需要身份验证和用户配置文件等,这取决于您的应用程序的结构。您可以为用户引入 WCF 或任何 Web 服务,并在后台隐藏您的实际操作(这会降低您的性能,但它可能是唯一的你有合适的解决方案),所以你可能在服务器逻辑的顶部有你的身份验证框架,在后面有一个流水线操作逻辑..即用户经过身份验证才能访问服务器提供的服务,但是这些服务管道所有用户并同时处理尽可能多的用户-如果您不需要身份验证,那么您可以直接与服务器逻辑通信,并且您可以根据用户的请求使用完成端口-这里有很多工作要做。

于 2012-11-21T10:24:41.053 回答