Java 多人游戏 - 网络概念
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7586869/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java multiplayer game - networking concepts
提问by Bv202
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.
对于学校项目,我们应该用 Java 创建一个多人游戏(应该是客户端/服务器),可以在互联网上玩(我们在学校编程,所以这不是家庭作业)。游戏是回合制的,但应该有聊天,这当然是实时的。然而,我们都没有网络编程的经验,而且我读的越多,我的问题似乎也就越多。
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:
我的第一个想法是使用套接字 API 来实现多人游戏部分。服务器等待来自客户端的新数据。但是,有多种数据要接收,如聊天消息、移动等。此外,一旦与服务器建立连接,就应该发送一些初始数据(如玩家的姓名)。服务器应该能够看到它收到了什么样的消息,但是如何呢?我正在考虑创建一个Message
带有字符串字段的类type
。但是在我的服务器代码中,我会得到这样的代码:
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.
其他游戏内容呢?例如,玩家 1 将他的角色移动到击败另一个角色的位置。玩家 1 的客户端计算此失败并应用正确的动作。但是应该向服务器发送什么?只是新的球员位置还是失败?对于第一个选项,这意味着所有其他客户端都应该进行计算。这不会造成什么麻烦吗?因为我之前没有网络编程经验,所以我对如何做所有这些事情有点困惑。
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?
我还在 Stackoverflow 上的另一个线程中读到 RMI 可能是更好的选择。阅读了有关此的一些信息后,我了解了 RMI 是什么,但我仍然无法确定它是否是该项目的好选择。有什么提示吗?
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.
如您所见,我对如何开始这个项目的网络部分感到有些困惑。我搜索了一些游戏编程书籍(当然是 Java),但没有一本专注于网络部分。我还搜索了 Java 网络书籍,但这些书籍似乎侧重于技术,而不是良好的代码实践。
If anyone knows a good book or has some advice in the right diection, it would be greatly appreciated.
如果有人知道一本好书或对正确的用语有一些建议,将不胜感激。
Thanks
谢谢
采纳答案by dfb
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.
如果您正在使用套接字,您就会发现需要定义一个协议——一种用于交流移动和游戏状态的相互语言。套接字可以让你以几乎任何你想要的格式发送任何类型的数据。看起来你正在考虑序列化一个类 Message 来发送这种类型,这是做事之一。如果您使用 RMI(它有自己的协议),您的行为就好像您在调用 Java 方法,但本质上您正在做类似的事情,序列化数据并通过套接字传递它。
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.
在客户端和服务器之间共享代码没有任何隐含的错误——事实上,大多数服务都以某种形式这样做。您的客户端和服务器都可以使用一个公共库来定义被传递的消息类。RMI 使用方法存根来确定接口。各种 Web 服务都定义了调用方法的方式。一般的想法是只公开接口,而不是实现。
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:
关于您的代码,为每种消息类型设置不同的 Message 子类可能会更清晰,并且您可以为每条消息添加额外的参数。然后你可以有一个 MessageProcessor 类,如:
class MessageProcessor{
void process(Move1Message m) {...}
void process(Move2Message m) {...}
....
}
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 bookhad lots of code examples for networking.
除非您对学习如何实现自己的协议或使用 Java 套接字库感兴趣,否则使用 RMI 会更容易。您还可以使用 SOAP、REST 或任何其他协议,但我不会费心考虑目前使用哪个协议。除了RMI 文档之外,我没有任何建议,尽管我认为这本书有很多用于网络的代码示例。
回答by ratchet freak
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 got
每行将是一条单独的消息,为了区分消息类型,您可以在每条消息的开头使用“标题”(开头的特定 3 个字符序列)说msg
, mov
,lgn
并使用类似trie的选择和开关快速决定你得到哪一个
when 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)
使用 RMI 时,您可以让服务器保留一个管理器对象(在注册表中导出并注册),客户端可以在该对象上请求“连接”对象,该对象将与套接字实现中的连接相同,但您将能够尽管回调需要以其他方式完成,但为您想做的每件事都有一个方法(使用套接字,您已经准备好连接)