Looking for advice on Java game server

Started by
16 comments, last by d000hg 5 years, 9 months ago

This is linked to another question that I asked here a couple of days ago:

I'm looking at making a client-server game with a game server programmed in Java. The game will be a 2D turn-based game (like a board game), with a maximum of around 50-100 games going on at any one time. So, the performance requirements are not very high. The reason I would like to use Java for the server are because I already have some familiarity with it and I would like the server to not be tied to one particular platform. I would also like to design it so that the client interface to the server is as generic as possible, so that the same server could be used with multiple different clients. For example, there might be a web-based client, or someone else might design a stand-alone 3D client application later on, using the same server.

So, I am looking for some advice on where to start with this, as I have very little experience with coding servers.

I was planning to use web sockets for the client-server connection, which apparently uses Java EE (Enterprise Edition), which seems to require the use of the GlassFish server. However, I have been advised that a fully-fledged application server, like GlassFish, may be overkill for a game server. So, here are my questions:

  1. Should I use something like GlassFish? Does it makes sense for the type of game server I am describing?
  2. If not, then what sort of networking protocol/library would experienced Java game designers recommend? Are there any existing, general-purpose Java game servers that exist, which I might be able to use as a starting point? (Or even free software/open-source client-server games?)
  3. Or, should I look at coding my own game server from scratch? In which case, again, what sort of connection type/library would be recommended?
  4. Does anyone know of any suitable introductory tutorials that deal with how to make this sort of game server in Java?

I guess my priority is probably minimizing the learning curve and the amount of time/effort involved, over performance. How much effort is this sort of undertaking going to require?

Thanks in advance! :-)

Advertisement

There isn't really a lot of overhead to using a "bigger" server than you need. Yes, it will load a bit more code and use a bit more memory, but if it has features you need, that's probably OK.

There MAY be a cost to using a server that doesn't have a good match to your needs. For example, if you need to scale across more than one server instance, then if your application server assumes that applications are stateless web apps, you will have a poor match to requirements.

One common model of development is to build the servers as intermediate layers, using some kind of messaging system (ZeroMQ, Thrift, GRPC, protocol-buffers-over-TCP, or whatever) and then build a separate front-end/gateway for the particular kinds of communication protocols you need. Thus, you could use a Node.js server with socket.io for translating websockets to your server mechanism, you could use an nginx/PHP gateway to translate polled HTTP to your server, and you could use something in Erlang to translate between mobile phone UDP packets and mobile push. Or whatever other combination you want. You'd define game packets using whatever your RPC mechanism is, and implement that mechanism for the server. Define some way to map "game instance id" to "which server does this live on." Have the gateways know how to map traffic for a particular game instance to the appropriate server, and forward traffic/requests as appropriate. These gateways may also have some kind of semi-persistent store for session authorization state (or use signed tickets/cookies.)

The game servers would, in turn, talk to databases or whatever your persistent store is. This ends up being a four-tier architecture -- client tier, gateway tier, game server tier, and storage tier.

Of course, if you'll only ever use a single server, and don't need scalability, just rolling it all into one is simpler, by far, and costs less to get started, too (no need to spin up and manage multiple different server processes.)

The only general-purpose Java game server I've tried to use was Darkstar, and it ... didn't scale. I don't recommend it.

enum Bool { True, False, FileNotFound };

@hplus0603 Thank you for your detailed reply. I know my question is quite broad - I'm trying to feel my way to a good place to start with this.

I'm not so sure about the 4-layer system that you describe though. It sounds quite complex and like it might be quite a lot of work to learn how to put all of that together. Sorry, I didn't quite follow what the advantages would be of using a 4-tier architecture, over a simpler 3-tier one. Could you please clarify?

In terms of the communication protocol, I think I've narrowed it down to some sort of socket (either websocket or TCP). This is because I want my game to have a turn timer, which the server would pause, if one of the clients got disconnected. So, because of that, I think I will need to have the persistent connection of a socket (as opposed to HTTP requests), so that the server can be aware of when a connection has been lost. Does that make sense?

So, in terms of whether it should be a websocket or TCP, the other thing is that I want the server to be able to connect to different types of clients. One might be browser-based, but others might not. Would either websockets or TCP sockets be better-suited for that? I assume that a websocket could be implemented in a client that is not necessarily browser-based? Otherwise, perhaps I could make my server able to handle both types of sockets, depending on the type of client that is trying to connect?

At this point, I think I'm leaning towards writing my own server, with just the functionality that I need.

I didn't quite follow what the advantages would be of using a 4-tier architecture, over a simpler 3-tier one.

The fourth (gateway) tier can do protocol translation for you, so that the back-end only needs to understand one canonical protocol.

Additionally, if you have multiple shards/servers, the gateways can do the dispatch to the correct server for a player connection, no matter which gateway the player happens to connect to.

Yes, this is more complex, because it buys you certain kinds of freedoms and flexibilities, especially if you need protocol translation and if you're using TCP or HTTP connections. On the other hand, if you want the shortest path between client and server, three-tier is smaller and less complex.

If you need to talk to web browsers, and you need a connection that's persistent, then you need to use websockets. Else you should probably use TCP, because it's simpler and needs less supporting libraries. One option is to start with TCP, a 3-tier architecture, and not support web browsers, and when you need that support, you add a fourth tier that translates from websockets to your TCP protocol.

enum Bool { True, False, FileNotFound };

Ok, thanks again, @hplus0603, I appreciate your advice :-)

One gotcha in developing a server-client application is that you can run into a chicken-egg situation. In order to test the server, you need a fully functional client. In order to test a client, you need a fully functional server. Which one do you develop first? Developing both at the same time can be time consuming if you do not have a solid protocol specification. If you change the protocol, you are updating both server and client code. What packets are being sent to clients when a player disconnects, when a player moves, etc. etc. Did the server respond correctly? Did the client respond correctly? What happen if they get out of synced?

There is a lot of details that need to be hashed out before your server and client applications can even reach their alpha status.

I have found out in the past that supporting HTTP can be helpful in testing some functionalities of the server, because HTTP is widely supported by the browsers. In other words, you have already gotten a fully functioning client, without the game logic obviously. Some people also recommend using telnet as your first client. However, I find telnet to be too rudimentary for testing once the logic gets a bit complicated.

I don't think that's so bad. You typically develop a low-level framing protocol (what's at the beginning/end of a datagram, and how do multiple messages fit in.) That can be tested using unit tests, and then using two processes that just send well-formed empty packets between each other.

Then, you develop a message dispatch and serialization protocol -- for each message within the protocol, how do you know what data type it is, and how do you know who should get it, and once you know the data type, how do you know to unpack it. (And, conversely, how do you pack it.) At this point, you'll typically build some kind of simple reflection system on top of your language, that lest you describe each data type with simple macros or "builder" function calls once, and then marshal to/from the format. Again, this code can be tested using unit tests, and then using simple processes that send/receive messages of designated data types, without putting any gameplay behind it.

Btw, in this phase, some developers try using built-in serialization mechanisms in languages like Java, C#, Python, and so forth, and realize that those mechanisms have totally different design goals than games, and end up generating way too big packets. You will want to define your own packet formats, that rely on both sides agreeing on schema (so field order/types/names aren't needed in the packets) and then implement serialization using reasonably efficient byte packing.

Finally, you tie the gameplay to the messages (entities created/destroyed, players giving commands, entities moving, and so forth,) and at that point, you should be able to build bigger integration tests in your code (poke at the game code to generate the intended kind of events, make sure the right kind of messages are generated into the network code.)

Only after all this is done do you need to set up the full client/server integration test, where you need the "fully formed" (as far as you've gotten) client and server to talk to each other.

enum Bool { True, False, FileNotFound };

I am going to answer specifically for Java & Websockets. I can't tell you whether this is the best technology choice or not for your game that's entirely up to you.

There is no correct choice here but there are a variety of solid options available to you. And by that I mean they're tried, tested, well(ish) documented and have active communities using them so you can ask questions online and reasonably expect someone out there will know the answer.

This is not an exhaustive list mind you. Just some of the more common options to help you evaluate:

  • Use a full-blown JavaEE appserver like Glassfish, Wildfly, TomEE, Weblogic, Websphere. This is the enterprise way to go, you have everything and the kitchen sink available to you. This is particularly useful if you think that you'll want to use other JEE standards for the purposes of managing logic & state, transactions, databases, etc.
  • Use a JEE servlet container like Tomcat or Jetty - Good if you are only interested in the web subsets of the JEE (like servlets & websockets). These can also be embedded so that your application can run standalone. Here's an example I found of Jetty embedded as a websocket server
  • Use a JEE server generator like Wildfly Swarm - This lets you pick and choose just the bits of the JEE that you need and lets you link them into your application so you can package the whole thing up into a single jar. Allowing for more light-weight servers when you only need a few JEE dependencies.
  • Use the JSR 356 (websockets) reference implementation - If you are simply only interested in running a websocket server using Java's websocket API but without any other JEE gumpf then this is how to do it.
  • Use the Play Framework - This is not JEE, it's not 'standard'. It's a Java & Scala web framework with a fresh and modern air to it. This is probably the newest player to the field.
  • Use Spring Boot - Spring has always been the main alternative to JEE. JEE has come along way in recent years but historically where JEE has been lacking features or was complex to use then Spring was easier, cleaner and more feature rich.  You can use the Spring Boot websocket starter to get up and running quickly.

@alnite and @hplus0603: Regarding the client/server development, what hplus0603 said is more-or-less the sort of thing I had in mind. I think I will have to develop them both in parallel, starting very simple and gradually building up. The first thing I will probably do is go through some tutorials for whichever web server option I decide on and try to make a very simple client to interact with it. For example, just a web page with a single button that sends a request to the server when it is pressed and then displays the response from the server. As hplus0603 says, I imagine I'll probably have to get the communication protocol side working first, before I try to build up to more complicated functionality and eventually do the actual game coding.

Although, I haven't done any of this before, so it seems like it will be a lot of work and a lot of things to learn! :-)

@dmatter: Thanks for your post and for listing all those options - many of them seem very interesting. With so many options available, it seems difficult to figure out where to start. Which one would you recommend to someone who is very new and inexperienced with client-server web app design?

Of those options, I think I'm leaning towards the Jetty servlet container, as it seems to incorporate websockets and seems to be more dedicated towards web applications. So, with that, my game server would be implemented as a Java servlet, running inside Jetty? Does Jetty also provide functionality for user authentication and communicating with a MySQL database? Also, how would I implement the other pages of the website with that option (i.e. outside of the 'game' application page)?

This topic is closed to new replies.

Advertisement