Table of ContentsOnline Scoring for Star AssaultConclusion

Advanced Networking

What you've done in this chapter so far is probably the most basic of MIDlet networking. If you're planning to develop a multiplayer game, there are a few other things I'd like to cover to give you a heads-up on what you'll need to know.

Using Sessions

HTTP uses a stateless connection model, which means that each request is sent independent of any other request. By default there is no method to determine whether multiple requests have come from the same client.

The problem with this system occurs when the server side starts doing heavy processing. For example, suppose you wanted to save the score to a database. To validate the player you would first need to load up his account details using a validated user name and password.The way it works at the moment, you would need to do this for every single request for every user. For a multiplayer game involving many requests, this would quickly generate excessive load on your server, and it's pointless.

To get around this problem, J2ME adds the concept of a session. A single session represents any stream of connections from an individual client. Each session is then tracked by assigning a session ID to all the connections; this session ID is then passed back and forth by the client and server to track it (independently of the IP address). This is done either by embedding the session ID into the URL or by setting a cookie.

NOTE

Note

A common misconception is that you can use the IP address of the client to represent a unique connection. Due to the use of NAT (Network Address Translation) and other relay technologies (such as proxies), you can quite commonly see connections coming from many different clients, all originating from a single IP.

You can obtain a session from within a servlet using a call to getSession on the request object. (The server will take care of associating a session with a request based on the session ID.)

HttpSession session = request.getSession();

You can tell whether this is a new session by calling the isNew method on the HttpSession object. Based on this you can carry out work to initialize the session for use, such as loading up details for a user.

if (session.isNew())
{
    // do init work for a new session
}

After you have made the call to getSession, the server will create a new session that is ready to use. You can now place data in the session, ready for later retrieval. For example, you could store a User object after the user has logged in successfully.

if (request.getParameter("username") != null)
{
    // load up the user from the database
    User u = new User(username);
    // set it in the session
    session.setAttribute("User-Object", user);
} else
{
    // retrieve the user object from the session
    User u = (User)session.getAttribute("User-Object");
    if (u == null)
        throw new Exception("oops, no user object set in session");
}

You now have a User object associated with the session on the server. Next you need to make sure your client properly identifies itself on each subsequent request. Normally an HTTP server will talk to a Web browser (an HTTP client), which will take care of handling the session ID for you. With a MIDlet, however, you need to take care of this manually. For example, if your server handles session IDs using cookies, you need to read the cookie (using the getHeaderField method), store the session ID it contains, and then set the session ID as a parameter in any future request you make using setRequestProperty.

Server-Side Persistence

There's a major problem with your little online scoring system: If you stop the server, the scores are lost. To resolve this you need to add code to persist the data by writing it to a file or database.

The most powerful (and flexible) solution is to use an SQL-compatible database. I recommend using the open-source MySQL database available from http://www.mysql.com. To access the database from Java you can use the JDBC (Java Database Connectivity) API. To talk to MySQL via JDBC, you also need to download and install the Connector/J JDBC driver (also available from the MySQL Web site).

Using JDBC is a good solution for very simple persistence; however, if you're getting serious you'll quickly find that manually handling SQL statements will become tiresome, buggy, and difficult to maintain. A better solution is to use an object/relational persistence system to automate the synchronization of Java objects with the database. That way you'll be able to deal purely with Java objects instead of having to map your SQL data to object instances and back again. You can find out more information on a popular (and free) per-sistence layer known as Hibernate at http://www.hibernate.org. Learning to use a persistence layer such as Hibernate is not easy, but I've found it substantially improves the development speed and overall quality of projects. Spend some time on it; it'll fundamentally change the way you work with SQL.

Multi-Server

There might be a point in the future when your game becomes so popular your server starts to have kittens handling the load. At this point you can buy a bigger server, but even that will only get you so far before you need to upgrade yet again. You also have the problem of your game being completely reliant on a single machine. If anything goes wrong, the whole game goes down until it's fixed. To resolve these issues you can design your server code and hardware setup to distribute the load among multiple servers.

Because you're dealing with HTTP as your protocol, you can take advantage of a host of technology already available to do this. Tomcat 5, for example, now includes a load-balancing system by default. Figure 22.4 shows a diagram of the basic structure of a distributed system.

Figure 22.4. A load balancer acts as a request router to backend server resources.

graphic/22fig04.gif


For all intents and purposes, the load balancer in Figure 22.4 appears to the client device (MID) as an HTTP server. The load balancer will take a request and then have it handled by any of its available backend servers. The load balancer has the opportunity to make a decision about which server handles the request based on all types of factors (such as backend server load).

You might be wondering what happens to your sessions in this case. If you create a session on one server, then what happens if on the next request the load balancer decides to route the request to a different server? You'd create another session. If you were to store data in that session, you'd start getting weird results as requests went to different servers. To accommodate this problem, load balancers are session-aware; they'll check whether a session ID has been set and then make sure all subsequent requests containing the same session ID are routed to the same server.

Session-aware load balancing solves the problem of session state; however, your current online scoring system would have another issueserver state. Each server will have its own instance of the online scores Vector. If you have 10 backend servers handling the score rankings, you'll have 10 completely different sets of scores and rankings. To resolve this you need to move the scores list into a memory state that can be shared among all servers.

The most common system for doing this is to use a database server accessible from all the machines. On each request you'll need to query the database, store the score, and then read back the updated ranking.

Using a database to share a game state among many servers works very well; however, the database itself can quickly become a critical point of load and failure if your system starts to get too big. At that point you might want to consider using a centralized application server such as JBoss (http://www.jboss.org) or moving to clustered DB caching based on the Clustered JDBC project (http://c-jdbc.objectweb.org).

Other Considerations

In this chapter you looked at the basics of adding network features to your game. As you can see, it's not particularly difficult to add elements that really improve game play. However, there are some serious pitfalls with multiplayer gaming that you should not ignore and these are lessons I wish I'd been told about, instead of having to learn the (very) hard way.

First, because you'll commonly be dealing with multiple threads on both the client and server, you'll want to spend some time learning how to deal with the concurrency issues. (See the use of the synchronized keyword in Java.) If you ignore this, you'll find out why concurrency-related bugs are considered the most difficult to track down.

Second, you need to assume your client will be hacked by players. The online scoring example I used in this chapter would be figured out quickly by malicious players, who would then upload whatever scores they liked. Encrypting messages, moving much of the state to the server, and using tokens to validate messages are all techniques you should explore before embarking on a large multiplayer project. Above all, always consider how players can abuse an aspect you add to a game.

    Table of ContentsOnline Scoring for Star AssaultConclusion