网络化客户端-服务器应用建议

6
我正在设计一个应用程序,允许两个网络用户玩囚徒困境游戏(http://en.wikipedia.org/wiki/Prisoner%27s_dilemma)。
基本上,这包括以下内容:
- 游戏开始(第一轮)。 - 玩家1选择合作或背叛。 - 玩家2选择合作或背叛。 - 然后显示彼此的决定。 - 第二轮开始。 - 以此类推。
我已经思考和搜索了一些,认为应用程序应该包含以下内容:
- 接受传入tcp/ip连接的服务器类。 - Gui客户端(单独的程序)。 - 对于每个连接(最多2个),服务器将创建一个新的ConnectedClient类。该类将包含两个玩家机器/身份的详细信息。 - 服务器类和ConnectedClient类将连接/订阅彼此的事件,以便它们可以在例如服务器指令准备好传输给玩家或玩家已将其输入传输给服务器时相互警报。
我不确定最好的方法是使用单线程完成工作,还是多线程完成。单线程显然更容易,但我不确定在这种情况下是否可行 - 我以前从未制作过需要TCP/IP连接的应用程序,并且我不确定您是否可以在一个线程上监听两个传入连接。
我在网上找到了以下指南,但似乎它在两个线程上打开了两个客户端,并且它们直接相互通信 - 绕过服务器(我将需要控制游戏逻辑):http://www.codeproject.com/Articles/429144/Simple-Instant-Messenger-with-SSL-Encryption-in-Cs 我非常感兴趣,并且很感谢任何有关如何实现应用程序(主要是服务器类)的建议。
我希望我已经清楚地解释了我的意图。提前致谢。
3个回答

8
我的第一个建议是忘记TCP/IP和sockets。当然,你可以使用这些技术来完成任务,但你也会面临很多困难。原因是这些属于太底层的技术,对于这类任务而言不够高级。我建议只在学术研究或者需要极高的通讯控制和性能要求时才使用TCP/IP和sockets。
因此,我的第二个建议是考虑使用WCF技术。如果你之前没有接触过,也不用担心,WCF并不难。如果你准备使用sockets实现你的应用程序,那么你肯定可以掌握WCF。你可以通过任何WCF教程,在1-2小时内从零开始创建基本通信。
所以,我会创建一个WCF服务端,其中包含一些API函数,用于实现业务逻辑。它可以在Windows服务、IIS或者控制台应用程序中托管。客户端可以调用WCF服务,就像调用项目中另一个本地类的函数。WCF还可以帮助你实现你想要的事件(尽管这是一个稍微高级点的话题)。而且,你甚至可以忘记线程,大部分事情都可以自动运行。

我已经调查了WCF,它似乎是正确的选择。您是否建议使用回调以便服务器与客户端进行通信?还是其他方法? - nf313743
你有三个选择。1 - 回调非常好,但缺点是必须在客户端机器上打开特定的端口,如果您可以接受这一点-请不要继续阅读 :)。2 - 客户端作为服务器。客户端托管一些API,可以由服务器调用。与回调几乎相同的方法,具有相同的缺点。3 - 拉取机制。客户端定期调用服务器的API以获取任何更新。没有端口和防火墙问题。 - Max Shmelev

4
首先,像其他人所说的那样,尽可能地将游戏逻辑分离,这样基本功能就不会过多依赖于通信基础设施。
对于通信,WCF可以处理任务。您可以让客户端向托管在IIS中的服务发送请求,进行某种身份验证,并打开一个双工通道,从中您的服务可以推送结果并通知新回合的开始。
一旦有一个客户端连接,它就等待另一个客户端。当发生这种情况时,它使用双工通道回调通知第一个客户端并等待其选择。然后它询问第二个用户,等待其响应。当响应到来时,它会将结果通知两个用户并重新启动游戏。
稍微深入实现:
您将拥有一些操作的服务(例如注册、推送决策,如果需要还有更多)。您还将定义一个回调接口,其中包含您的服务将需要推送到客户端的操作(NotifyResult、RequestDecision,同样,这些是示例)。然后,为您的客户端创建代理,将其映射到您的服务操作,并以使其公开事件的方式实现回调操作,并在服务推送消息时引发它们。
用例:

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

客户端B连接(调用注册),与A做的一样,服务器注意到有两个客户端连接,通过保存的回调请求A的响应。这可能发生在B的注册调用处理期间,也可能在新线程中触发执行(或更好地,在ThreadPool中运行或启动一个新Task)。

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

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

这并不是最终实现,只是一个小指南,为您提供一些想法,而不仅仅是提供一些模糊的建议。当然,使用WCF可能还有许多其他方法。
我们可以首先假设应用程序每次只能处理两个用户,然后,如果需要,您可以进行扩展,让您的服务保持某种状态,并使用映射表和锁定访问等方式。
关于WCF的一些想法:使用Visual Studio工具(svcutil)开始开发WCF很容易,但我不喜欢这种方法。您无法很好地了解WCF基础结构,您会被其生成代理的冗长魔术所束缚,并且您会失去灵活性,特别是在您想要使用Duplex轮询等特殊场景时。
另一种方式是手动创建您的服务和代理,这并不难,一旦您意识到可以做什么,就会变得非常有趣。在此方面,我可以给您一个建议:尽一切可能使您的代理操作使用基于任务的异步模式(您可以在此处看到实现代理操作的不同方法)。当与新的C# async/await关键字结合使用时,这将使您的代码更加清晰直观,并且您的UI将非常易于实现。
我可以推荐一些链接让您入门。其中一些链接已经过时,但非常有教育意义。

1

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

  1. 将逻辑分离(通过理解要在服务器上构建的逻辑的每个部分)

  2. 使您的类能够处理每个事务的多个用户

  3. 尽可能使用IOCP

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


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