我正在尝试设计一个允许网络上的两个用户玩囚犯的应用程序
困境游戏(http://en.wikipedia.org/wiki/Prisoner%27s_dilemma)。
基本上,这涉及:
我已经做了一些思考和搜索,我认为应用程序应该包含以下内容:
我不确定最好的approch是使用单个线程来做或工作,还是让它多线程。单线程显然会更容易,但我不确定是否可能出现这种情况 - 我从未在需要TCP / IP连接之前创建应用程序,而且我不确定您是否可以侦听两个传入连接一个帖子。
我在网上找到了以下指南,但它似乎在两个线程上打开了两个客户端,它们直接相互通信 - 绕过服务器(我需要控制游戏逻辑):{{3 }}
我非常感兴趣,如果你有关如何实现应用程序(主要是服务器类)的任何建议,我将不胜感激。
我希望我清楚地解释了我的意图。提前谢谢。
答案 0 :(得分:8)
我的第一个建议是忘记TCP / IP和套接字。你绝对可以用这个技术堆栈来做到这一点,但是你也会在实现你想要的所有东西时遇到很多麻烦。原因是这类任务的技术水平太低。我会选择tcp / ip和socket作为学术兴趣,或者如果我需要对通信有很大的控制权,或者我有非常高的性能要求。
所以,我的第二个建议是看看WCF技术。如果你之前没有使用它,请不要害怕。这并不困难。如果你准备好为你的应用程序使用套接字,你可以肯定地处理WCF。对于您的任务,您可以使用任何WCF教程从头开始创建1-2小时的基本通信。
所以,我会创建一个服务器WCF服务,它将包含一些包含业务逻辑的API函数。它可以托管在Windows服务,IIS或控制台应用程序中。 并且您的客户端将使用该WCF服务,从项目中的另一个本地类调用它们的函数。 WCF也可以帮助你做你想要的事件(虽然这是一个更高级的主题)。你甚至可以忘记这里的线程,大多数事情都是开箱即用的。
答案 1 :(得分:4)
首先,正如其他人所说的那样,尽可能地分离你的游戏逻辑,因此基本的功能不会太依赖于你的通信基础设施。
对于通信,WCF可以处理该任务。您可以让您的客户端向IIS中托管的服务发送请求,进行某种身份验证/身份验证,并打开一个双工频道,您的服务可以从该频道推送结果并开始新一轮的开始。
一旦客户端连接,它就会等待另一个客户端。当它发生时,它会使用双工频道回调通知第一个客户端,并等待其选择。然后它询问第二个用户,等待其响应。当它到来时,它会将结果通知两者并重新开始游戏。
进一步深入实施:
您将获得一些具有某些操作的服务(如Register,PushDecision,如果需要,还有更多操作)。您还将定义一个回调接口,其中包含您的服务需要推送到客户端的操作(NotifyResult,RequestDecision,这些都是示例)。然后,为客户端创建映射到服务操作的代理,并以公开事件的方式实现回调操作,并在服务推送消息时引发它们。
用例:
客户端A创建代理,在服务器上调用Register。服务器接收呼叫,注册cilent并将回调对象保存在某个状态。将建立双工连接。那是什么意思?这意味着(如果您使用PollingDuplexBinding,就像您可能会这样),从现在起,客户端A中的代理对象将对服务器执行长轮询请求,检查是否存在回调消息。如果没有,那么它再次进行长期民意调查。如果有,它会调用代理中的回调方法传递服务器推送的数据。代理中的回调方法会以简单的方式引发事件或执行委托,由您自行选择。
客户端B连接(调用Register),与A相同,服务器注意到两个客户端已连接,通过其保存的回调请求对A的响应。这可能发生在B的Register调用处理期间,或者可以触发在B的寄存器调用中执行新线程(或更好,在ThreadPool中运行或启动新Task)。
客户端A将收到请求其选择的服务器回调。然后,它可以通知用户并通过UI获得选择。对服务器进行了新的调用(例如,PushDecision)。服务器接收客户端A选择,以相同的方式询问B.一旦它有两个响应,它会计算结果并将结果推送给客户。
将PollexDuplex与WPF一起使用的双工通道的一个优点是,由于它使用长轮询,因此不需要使用80以外的其他端口。
这绝不是最终的实施,只是一个向您提供一些想法的指南,而不仅仅是给您一些朦胧的建议。当然,使用WCF可能还有很多其他方法。
我们可以首先假设应用程序每次只能处理两个用户,然后,如果需要,您可以扩展,使您的服务保持某种形式的状态,并使用具有锁定访问权限的映射表,作为另一个示例。 / p>
关于WCF的一些想法:使用Visual Studio工具(svcutil)开始使用WCF开辟一条简单的路径,但我不喜欢这种方法。你没有很好地“了解”WCF基础设施,你变得与它生成你的代理的冗长魔法联系在一起,你就失去了灵活性,特别是在特殊场景中,比如你可能想要使用的双工轮询。
另一方面,即手动创建服务和代理,并不是那么难,并且一旦你意识到你可以用它做什么就变得非常有趣。与此相关的我可以给你一个建议:尽一切可能使你的代理操作使用基于任务的异步模式(你可以看到实现代理操作的不同方法here)。这将使您的代码在与新的C#async/await关键字结合使用时更加清晰和直接,您的用户界面将是一种乐趣。
我可以推荐一些链接来帮助您入门。其中一些是陈旧的,但非常有说服力。
答案 2 :(得分:1)
如果您坚持要求所有用户通过服务器进行通信并希望您的应用程序可扩展,我可以给您一个建议:
分离您的逻辑(通过了解您要在服务器上构建的逻辑的每个部分)
使您的课程可以处理每个交易的多个用户
尽可能使用IOCP
如果您需要身份验证和用户配置文件等,它取决于您的应用程序的结构。您可以为用户介绍WCF或任何Web服务,并在后台隐藏您的实际操作(这将花费您的性能但它可能是您拥有的唯一合适的解决方案),因此您可能将您的身份验证框架置于服务器逻辑的顶部,并在后面使用流水线操作逻辑。即,用户将获得身份验证,以便能够访问由服务器,但这些服务管道所有用户并尽可能多地同时处理 - 如果您不需要身份验证,那么您可以直接与服务器逻辑通信,并且您可以根据用户的请求使用完成端口 - 需要完成大量工作这里。