Java 多人游戏 - 网络概念
对于一个学校项目,我们应该用 Java 创建一个多人游戏(应该是客户端/服务器),可以通过互联网玩(我们在学校编程,所以这不是家庭作业)。游戏是回合制的,但应该有聊天,当然是实时的。然而,我们都没有网络编程的经验,而且我读得越多,我的问题似乎就越多。
我的第一个想法是使用套接字 API 来实现多人游戏部分。服务器等待来自客户端的新数据。然而,有多种类型的数据需要接收,例如聊天消息、移动等。此外,一旦与服务器建立连接,就应该发送一些初始数据(例如玩家的姓名)。服务器应该能够看到它收到的消息类型,但是如何呢?我正在考虑创建一个带有字符串字段type
的类Message
。但在我的服务器代码中,我会得到这样的代码:
if (message.type.equals("message")) {
// code to execute for chat messages
} else if (message.type.equals("movement")) {
// code to execute for movement
} else if () {
// ...
} else {
// ...
} // Please ignore syntax errors :P
当有很多不同类型的数据要发送(并且将会有)时,这看起来不是最有效的方法。另外,这意味着服务器和客户端都应该具有此消息类/接口(重复代码)。
其他游戏内容呢?例如,玩家1将他的角色移动到击败另一个角色的位置。玩家 1 的客户端计算此失败并应用正确的操作。但是应该向服务器发送什么内容呢?只是新的球员位置还是失败?对于第一个选项,这意味着所有其他客户端都应该进行计算。这不会带来什么麻烦吗?由于我之前没有网络编程经验,所以我对如何做所有这些事情有点困惑。
我还在 Stackoverflow 上的另一个帖子中读到 RMI 可能是更好的选择。阅读了一些相关信息后,我了解了 RMI 是什么,但我仍然无法看出它是否适合该项目。有什么建议吗?
正如您所看到的,我对如何开始该项目的网络部分有点困惑。我搜索了一些游戏编程书籍(当然是针对 Java 的),但没有一本专注于网络部分。我还搜索过 Java 网络书籍,但这些书籍似乎侧重于技术,而不是良好的代码实践。
如果有人知道一本好书或有一些正确方向的建议,我们将不胜感激。
谢谢
For a school project, we're supposed to create a multiplayer game in Java (it should be client/server) which can be played over the internet (we're programming this at school, so it's not homework). The game is turn-based, but there should be a chat, which ofcourse is real-time. However, none of us has experience with network programming and the more I read about it, the more questions I seem to have.
My first thought was to use the socket API to implement the multiplayer part. The server waits for new data from the clients. However, there are multiple kinds of data to receive, like chat messages, movement, etc. Also, once the connection to the server is made, some initial data (like the Player's name) should be sent. The server should be able to see what kind of message it received, but how? I was thinking of creating a class Message
with a string field type
. But in my server code, I will get code like this:
if (message.type.equals("message")) {
// code to execute for chat messages
} else if (message.type.equals("movement")) {
// code to execute for movement
} else if () {
// ...
} else {
// ...
} // Please ignore syntax errors :P
When there are a lot of different kinds of data to send (and there WILL be), this doesn't look like the most efficient way. Also, this would mean both the server and client should have this Message-class/interface (duplicate code).
What about other game stuff? For example, player 1 moves his character to a position which defeats another character. The client of player 1 calculates this defeatment and applies the correct actions. But what should be send to the server? Just the new player position or also the defeatment? With the first option, it means all other clients should do the calculations. Couldn't this cause any trouble? As I have no prior network programming experience, I'm a bit confused on how to do all these things.
I've also read in another thread here on Stackoverflow that RMI might be a better option. Having read some information about this, I understand what RMI is, but I'm still not able to see whether it is a good option for this project or not. Any tips for this?
As you see, I'm a bit confused on how to start with the networking part of this project. I've searched for some game programming books (for Java ofcourse), but none of them are focussed on the networking part. I've also searched for Java networking books, but these seem to be focussed on the technology, not on good code practices.
If anyone knows a good book or has some advice in the right diection, it would be greatly appreciated.
Thanks
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您走在正确的道路上,但还有一些事情需要澄清。
如果您使用套接字,您就会发现您需要定义一个协议 - 一种用于传达动作和游戏状态的共同语言。套接字可以让您以几乎任何您想要的格式发送任何类型的数据。看起来您正在考虑序列化类 Message 来发送此类型,这是做事之一。如果您使用 RMI(它有自己的协议),您的行为就像调用 Java 方法一样,但本质上您正在做类似的事情,序列化数据并通过套接字传递它。
在客户端和服务器之间共享代码并没有什么隐含的错误 - 事实上,大多数服务都以某种形式执行此操作。您的客户端和服务器都可以使用公共库来定义正在传递的消息类。 RMI 使用方法存根来确定接口。各种 Web 服务定义了如何调用方法。总体思路是只公开接口,而不公开实现。
关于您的代码,为每种消息类型使用不同的 Message 子类可能会更清晰,并且您可以为每个消息添加额外的参数。然后,您可以有一个 MessageProcessor 类,如下所示:
关于发送内容 - 一般原则应该是客户端负责将其移动发送到服务器,它所做的任何其他操作都是额外的好处,因为服务器需要验证移动的合法性移动。服务器应该始终是游戏状态的决定者,以避免作弊和错误的客户端实现。
除非您有兴趣学习如何实现自己的协议或使用 Java 套接字库,否则使用 RMI 会更容易。您还可以使用 SOAP、REST 或任何其他协议,但我现在不会费心考虑使用哪一个。除了RMI 文档,尽管我认为这本书有很多代码示例网络。
You're on the right path, but there are few things to clear up.
If you're using sockets, you've figured out that you need to define a protocol - a mutual language for communicating moves and the state of the game. Sockets will let you send any sort of data in pretty much any format you want. It looks like you're thinking about serializing a class Message to send this type, this is one of doing things. If you use RMI (which has its own protocol), you will act as if you were calling Java methods, but in essence you're doing something similar, serializing data and passing it over a socket.
There's nothing implicitly wrong about sharing code between the client and the server - in fact, most services do this in some form. Your client and server could both use a common library to define the message classes being passed around. RMI uses method stubs to determine the interface. Web services of all sorts define how methods are invoked. The general idea is to only expose the interface, not the implementation.
Regarding your code, it might be cleaner to have a different Message subclass for each message type and you could put additional parameters for each message. You could then have a MessageProcessor class like:
Regarding what to send - the general principle should be that the client is responsible for sending their move to the server, anything else it does is a bonus, because the server needs to verify the legality of the move. The server should always be the determiner of the state of the game to avoid cheating and erroneous client implementations
Unless you're interested in learning how to implement your own protocol or use the Java sockets library, it's going to be easier to use RMI. You could also use SOAP, REST or any other protocol, but I wouldn't bother thinking too hard about which one to use at the moment. I don't have any suggestions beyond the RMI documentation, though I think this book had lots of code examples for networking.
当使用套接字时,每个客户端将拥有自己的连接,服务器线程将在该连接上等待(不要忘记刷新客户端上的流,否则您将永远等待)
每一行将是一个单独的消息并区分消息类型您可以在每条消息的开头使用“标头”(开头的特定 3 个字符序列),例如
msg
、mov
、lgn
并使用 trie 式的选择,带有开关,可以快速决定使用 RMI 时您可以让服务器保留一个管理器对象(在注册表中导出并注册),客户端可以在其上请求“连接”对象,该对象与套接字实现中的连接相同,但您将能够为您想做的每件事提供一个方法尽管回调需要在其他一些地方完成方式(使用套接字,您已准备好连接)
when going with sockets each client will have it's own connection on which a server thread will wait (don't forget to flush the stream on client side or you'll wait forever)
each line will be a separate message and to differentiate the message types you can use a "header" at the start of each message (a specific 3-character sequence at the start) say
msg
,mov
,lgn
and use a trie-like selection with switches to quickly decide which one you gotwhen using RMI you can have the server keep a manager object (exported and registered in the registry) on which a client can request a "connection"-object which will be the same as the connection in the socket implementation but you'll be able to have a method for each thing you wanna do though the callbacks will need to be done in some other way (with sockets you have a connection ready for it)