Python游戏程序的抽象与客户端/服务器架构问题
目前我正在设计一款卡牌游戏,目的是为将来的工作利用一些主要组件。现在让我感到困惑的是,如何在服务器和客户端之间创建一个抽象层。服务器启动后,可以有一个或多个客户端连接(可以是本地的,也可以是远程的)。我正在设计一个厚客户端,但我的朋友想做一个基于网页的客户端。我希望设计服务器的方式能够让不同的客户端调用一组共同的服务器命令。
所以,首先我想创建一个“服务器”,来管理游戏规则和玩家互动,同时在本地命令行界面(我为了方便使用的是Ubuntu Linux)上创建一个“客户端”。我正在尝试理清这两个部分应该如何互动,而不要求未来的客户端必须是基于命令行的或在本地机器上。
我找到以下两个问题,它们对我有帮助,但并没有完全解决我的困惑。
我并不需要立刻有一个功能齐全的系统;我只是想建立一些基本的抽象机制,以便最终的代码能够正确反映出客户端和服务器之间的关系:客户端/服务器关系与一个整体应用程序之间的假设是不同的。
我该从哪里开始呢?你有什么推荐的资源吗?
免责声明:我对多种编程语言和一般编程/逻辑概念都有一定了解,但在编写大量代码方面的实际经验不多。这个小项目是我想要弥补这一点的尝试。
另外,我知道网上已经有很多信息,但我感觉自己可能在细节中迷失了方向。
3 个回答
我建议所有的服务器和客户端之间的互动都基于HTTP协议,可能会使用JSON格式的数据。这种方式虽然不能直接让服务器主动发起互动(也就是“服务器推送”),但有一种比较新的解决办法,就是用AJAX技术(虽然这里的X其实不太合适,因为我提到的是JSON而不是XML)。简单来说,客户端会向服务器的一个特定网址发起异步请求(可以通过一个单独的线程或者其他方式),然后服务器会对这些请求做出响应,实际上就实现了“推送”的效果。从你说的情况来看,这种方法的局限性似乎不会成为问题。
这种互动方式的一个主要好处是,它和编程语言完全无关——所以用JavaScript写的网页客户端和用Python写的命令行客户端都可以一样好用。当然,服务器可以在本地运行,但这并不是必须的,因为HTTP网址可以指定任何运行服务器的主机等等。
首先,不管你的客户端是在本地还是远程,你都会通过一个已经建立的基于消息的接口进行沟通。所有的客户端都会基于一套共同的请求和响应来工作,服务器会根据游戏状态来处理和拒绝这些请求。无论你是在同一台机器上处理本地客户端,还是通过HTTP处理远程客户端,从抽象的角度来看,这些都没有区别,因为它们都是通过相同的请求和响应进行交流。
这就涉及到你的协议。你的协议应该是客户端和服务器之间一个明确且技术上合理的语言,这样可以让客户端a) 有效参与,b) 公平参与。这个协议应该定义客户端可以发送哪些消息(‘动作’),以及何时发送和服务器将如何响应。
在你开始编写游戏逻辑之前,协议应该被完全定义和记录下来——这两者是紧密相连的,先完全定义协议可以节省很多时间和精力。
你的协议就是客户端和服务器之间的抽象,它还将作为设计文档和编程指南。
协议设计主要涉及状态、状态转换和验证。游戏服务器通常会有一套相对常见的、通用的状态,比如初始化、大厅、游戏进行中、暂停、回顾、关闭游戏等等。
每个状态都有重要的状态数据。例如,服务器端的“大厅”状态可能包含每个玩家的已知状态……比如自上次消息或ping过去了多久,玩家在做什么(选择头像、切换设置、去冰箱等)。在代码中组织和管理状态及其子状态数据是很重要的。
管理这些状态以及每个状态所需的数据是一个需要精心规划的过程,因为它们直接关系到工作量和项目复杂性——这非常重要,如果你打算通过这个项目迈向更大的目标,这也是很好的实践。
另外,你必须记住,如果你有一个游戏,并且让人们来玩,人们就会作弊。这是生活中的一个事实。为了尽量减少这种情况,你必须仔细设计你的协议和状态管理,只允许有效的状态转换。永远不要完全信任单个客户端的数据包。
对于每种客户端/服务器状态的组合,你必须强制执行一套有限的有效游戏消息,并且在允许玩家做什么以及何时允许他们做这些事情时要非常小心。
项目的复杂性通常是指数级的,而不是线性的——客户端/服务器游戏编程通常是学习这一点的一个好方法,也可能会让人感到痛苦。这个问题很好。希望这对你有帮助,祝你好运!
了解一下RESTful架构。
你的胖客户端可以使用REST。它会用urllib2
来向服务器发送RESTful请求,并且可以用JSON格式来交换数据。
一个网页客户端也可以使用REST。它可以通过浏览器发起简单的HTTP请求,或者用JavaScript组件发起更复杂的REST请求,依然使用JSON格式。
你的服务器可以简单地用WSGI应用来搭建,使用任何简单的WSGI组件就可以了。标准库里有不错的组件,或者你也可以使用Werkzeug。你的服务器只需要接受REST请求,并返回REST响应。你的服务器可以处理HTML格式(供浏览器使用)或JSON格式(供胖客户端或JavaScript客户端使用)。