I’ve made a small simple but complete java NIO server (with full source included) that is free for anyone to use for anything. At the moment, it only deals with sending and receiving strings, and isn’t optimized, but if anyone wants to improve it and send me the changes then I’ll post up an improved version here.
Download, documentation, license details, tutorial etc after the jump…
EDIT: I’ve now created a SourceForge project for this project – http://javanioserver.sourceforge.net/
EDIT2: Because WordPress is utterly, utterly crap at allowing you to have category pages, the old “main news page” for the project no longer exists. Blame WordPress, and hope that *one day* they will bother to fix their code so that it supports this standard blogging feature :).
Download
The most important thing is the full source code (DOWNLOAD FROM SOURCEFORGE LINK ABOVE), but if you decide just to use it as-is, you’ll probably want the much smaller binary-only jar (DOWNLOAD FROM SOURCEFORGE LINK ABOVE). NOTE: both jars have an auto-run that runs a very simple Hello,World! server so you can check they are working OK.
You’ll also need log4j (the fast, powerful, and extremely widely used open-source logging-library) – if you want the application to auto-run, you’ll need to name your log4j file “log4j-1.2.8.jar” (there’s a copy of the latest version here (DOWNLOAD FROM SOURCEFORGE LINK ABOVE), already renamed for you, that you can download directly; sorry, that was my mistake when building the JAR).
Finally, there are fully-documented javadocs here that should answer all your questions and explain how to use this library.
Why did I make this?
Mainly because Sun’s NIO libraries are good, but very low-level, with a few major flaws and a few unfixed bugs,
so that it takes a lot of time and effort to make even the simplest of working
client/server applications with them. This small, simplistic library (fewer than 1000 lines of code)
is designed so that you can:
- easily implement a new single-threaded, non-blocking NIO server in minutes
- edit the fully-documented source to customize it any way you need
- read all the source code and understand how it was done so you can make your own servers from scratch
In case you weren’t aware, MOST resources on the internet providing source code
for Java NIO servers are WRONG and FULL OF BUGS that mean they WILL NOT WORK –
including BOTH of the O’Reilly books I’ve read (“Java NIO” and “Learning Java”).
That’s pretty shameful considering those are both extremely widely-used books :(.
In both cases, the authors clearly A) never read the API properly, and B) never
actually tried writing any NIO server code in their life. Or, at least, they
wrote it but never ran it on the internet – a glance at their source code shows
it won’t work except on a local switched LAN, and even then only for VERY simple
programs.
So, although this library is NOT particularly optimized (mostly in that it is
wasteful with how it creates ByteBuffers), it DOES ACTUALLY WORK and is pretty
simple and well-documented, so hopefully you can use it to make your own servers.
Why string-based, and TCP only?
TCP only: because I created this for “incubation” projects – i.e. small game
experiments I wanted to try out. The code supplied will actually work reasonably
well for most realtime games with current internet performance (I’ve made various
simple multiplayer games with it) – but if you find your game is particularly good
and want to make a proper multiplayer version over the internet, you’ll want to
replace the TCP with UDP. That will be very, very easy to do – but not necessary
for the majority of people who are just making simple games.
String-based: because A) you ALWAYS need strings! (what, your game has no in-game
chat? Shame on you!), and B) it’s much, much easier to debug, and C) when you’re
developing code very fast (I’m using Scrum) strings allow you to use “fuzzy”
message protocols, such as XML + XPath, which means that when you switch around
features, or change the message format, most of your code carries on working fine.
Binary protocols tend to break every time you make even one tiny change.
When you get to the point where strings aren’t good enough performance for your
game, you’ve already got a pretty damned advanced game, and you’ll find the only
thing you need to do to make this server work purely in bytes is to REMOVE lines
of code (all the Charset encoding and decoding) and to change one or two method
signatures to accept bytearrays or bytebuffers instead of strings as argument.
33 replies on “Java NIO Server Example”
more stuff on nio is always welcome in my book :)
i am very interested to know exactly what the “few major flaws and a few unfixed bugs” are – as much as i dont really like the api, my game im making seems to be working ok so far – i mostly used online tutorials to help me learn nio. Only thing i can thing of is maybe a lack of built in timeout handling?
Using Apache MINA doesn’t do the trick ?
gareth – for instance, SelectionKey.attach() is still fundamentally broken AFAICS – it “deletes” the attachment if you do certain things, none of which is documented in the API, and you have to discover by trial and error – so that the entire method is mostly useless. IIRC the most detailed response I got from a Sun engineer was along the lines: “well, that’s because one of the underlying OS libraries we’re using causes that, we’re not going to work around it, so you ought to learn the OS-specific libraries we’re implemetning – the JVM source is freely available, you know”. WTF? Shrug.
Andres – historically, MINA has been a complicated but severely under-documented API. AFAICS, the documentation is noticeably a lot better right now, but still appears to be missing vast chunks. Currently I do not have the time to deduce how to use someone else’s complex architecture that is undocumented, no matter how powerful it may be :(. Once the documentation reaches a level that is equivalent to the complexity and richness of the library, I’m hoping I’ll have the chance to learn it properly.
Also … this overly-simplistic implementation is quite easy (I think!) to read and understand and learn for yourself what is going on…
Hi there,
was interested by your post and project…
I am in the analysis phase of a big project to build a Internet Chess Server from Scratch that will eventually support 5.000 simult. users
could you please reply (using my email) so that we can talk a little about this framework and its suitability for such a project.
also interested in your skills
thanks
@Michael – Hi. For a chess game, assuming standard two players per match, you should find this pretty easy, even with spectators; on a scale of one to ten, where 1 is “singleplayer game” and 10 is “MMO FPS”, I’d rank this at around 3. The only complexities would be creating a lobby system and splitting the actual games across multiple servers. Any good programmer should be able to architect something for this – I’d suggest reading the Gamasutra articles on RTS multiplayer games (although they’re peer to peer, they’re more than powerful enough for your needs, and feature good solutions for common problems and guidance on features you may not have thought of)
Then again, off the top of my head, I think the last online chess system I looked at had hundreds of thousands of simultaneously connected clients, so I suspect you should be able to find some good prior art that is chess specfic and more than adequate to your needs.
Happy to help with basic questions, but please note that I currently work for one of the world’s biggest massively multiplayer online game publishers / developers, so there are limits to how much I can get involved with other people’s games – unless we’re going to fund or publish them.
Hello,
I am (with educational purposes) making a server for a MMORPG-game, that is supposed to be able to hold up to around 2000 players at once, so I got a few questions to ask:
1. Does the RAM-requirement (either if it is 30.000 kB or above 100.000 kB) have any visible impact on the servers efficiency?
2. What would be the best method to handle static game-data (XML files using XStream, or something else)?
3. What algorithm should preferrably be used for area-searching, to see which entities overlap the view-field of the current entity?
4. Do you know of any very good books about the subject MMORPG-game development for Java, or something covering other heavy server-frameworks?
re: books – sorry, no. I started writing one a few years ago, and had a publishing contract etc sorted out, but in the end decided I didn’t have enough time, so went back to concentrate fulltime on making them :).
The “massively multiplayer game development” books from CRM sound good on the cover, but are almost totally useless in fact, being full of mostly overly simplistic or even downright poor ideas and implementations. So I would suggest avoiding them. They’re the most technical books I’ve seen, though.
RAM is generally only a problem if you run out, and you’ll know how much you need pretty quickly when you start developing. Any more detailed answer is going to take a LOT more detail to answer, sorry :).
For area-searching, I very much doubt it will be a major issue for you in the longrun, unless you’re truly stupid with your implementation. Google for work on “2d collision detection” – it’s the same problem, phrased slightly differently, and all modern games have good algorithms for this stuff already.
Database performance is usually the one that kills people…
First of all, I want to thank you for the work you put into this. It looks quite nice. Also wanted to tell you that I found a bug in the code. If a client sends to the server a partial message the server spins trying to read the message even do the client has disconnected. It does not look like a bug in your code, it may be an issue in windows. However this is what I did to reproduce. I connected to the server using telnet and typed the following “1234567890”, the server read the first 4 bytes set it self to wait for a large message. On the telnet side, I pressed ctrl+] and quited out of telnet. The server stayed in a loop trying to read from client.
I read somewhere that selectors can only handle 64 sockets, I can’t recall were I read this and as you said the doc on nio is spotty at best. If it is so, what would you think is the best approach on your code to handle this. 1) create a thread for each selector or to process all the selectors using the same thread iterating threw the selectors ?
Thank You Again
Diego Cassinera
Thanks, well spotted :).
Re: 64 sockets – that’s the default limit that Windows puts on IOCP (completion ports), although you can programmatically tell windows to change the limit to something higher.
From memory, there WAS a bug in Java 1.4.0 (about 4 years ago) where the Sun programmers had forgotten to increase this limit, but it’s been fixed for many years now. I suspect that what you read was a rumour from a half-remembered description of that bug?
Adam, I’m running into another issue, and again I don’t think its your code.
During ProcessStringMessage I’m attaching my session object to the key. On following calls to ProcessStringMessage for the same client, the attachment is gone.
I read the documentation and it does not say anything about when or for how long the attachment will be there so I’m going with the assumption that is for the life of the key.
I know that its being set because I can retrieve it with a call attachment() after I have set it. Originally I was doing the attachment from a different thread, but I have changed my code so its done in ProcessStringMessage.
I also looked into your code and you are not using the attachment, so the only conclusion I have is that java lost it.
The attachment its not crucial since I can store my session object in a hashtable, however it would be nice to get to my session without the need of a lookup.
Also I have run the code under the debugger with a watch on the attachment, the watch does not trigger, but attachment still returns null.
Thank You
Again Diego
If you read through the docs I wrote for this, you’ll find somewhere something that says “NEVER USE ATTACHMENT() – IT DOESNT WORK” (although in more words than that :)).
Yes, attachment() is broken.
Yes, Sun has known about this for at least 4 years (I logged a bug on it with them).
No, as far as I know, they haven’t fixed it yet.
Yes, this is pretty depressing :).
Oh, and – if you read any of the books published on NIO, they probably won’t mention this. Because most of the authors never actually tried using NIO on any real project. Sigh.
Thanks.
In regards to the spinning bug that I mentioned before. The simple fix is to add the following code to readIncomingMessageFromKey
if (bytesRead == -1)
{
throw new IOException(“Channel Closed”);
}
after
if( bufferIsEmpty )
{
bytesRead = ((ReadableByteChannel) key.channel()).read( bb );
}
Another question
In StringBasedServer.run after
Set keys = selector.selectedKeys();
Iterator iterator = keys.iterator();
while( iterator.hasNext() )
Hello again. I have a little heads up.
I wrote a nice chat server using the code. It worked fine on windows using the sun vm. However when I moved the code to my suse Linux server the server gets stuck when sending data to a channel that does not have incoming data. Suse Linux by default installs IBM j9 vm. To fix the problem I installed the Sun vm and now everything works fine.
Diego
Hi Diego,
I need to write a chat and a voice chat server, which should support around 1000 users, Could you please guide me in this?
~Sandy
Adam,
Thanks for this sample code, it’s great. I just wonder about how the client connection is supposed to get notified that the server has sent it a message. It seems that in StringBasedClient, there is a member:
iMessageProcessor messageProcessor
It’s not set anywhere, so I just added a parameter to connect(), so that it takes a reference to an iMessageProcessor object. Once set, it seems to work fine with the string client calling receiveMessage() everytime the server pushes a message to the client. This is how it’s supposed to work, right?
Thanks,
Mark
Sandy,
I’m not quite sure if this is the place to discuss a specific implementation of a chat server using this code, so I just will give you a gist.
1)Created a class that extends the StringBasedServer class.
In the overloaded processStringMessage member function I enqueue the received message along with its SelectionKey into a LinkedBlockingQueue.
2)Created a class called MessagePump that implements Runnable and dequeues messages from the LinkedBlockingQueue. This class implements most of the chat server protocol that I’m using. For example when a message its dequeued from the queue and the SelectionKey has never been seen by this class, a session object its created. In the session object I store the SelectionKey, and all other chat protocol information. The session object is stored in a Hashtable that uses the SelectionKey as its key.
3)To support 1000’s of users I did some modifications to Adam’s code. The key modifications that I did is to be able to extend StringBasedServer in a non listening mode. I did this mainly so I can have multiple threads that extend StringBasedServer each one processing all IO for a subset of the open connections. For my server the order at which messages are sent and received is not important, so I have multiple instances of StringBasedServer and MessagePump. Overall its more important to have multiple instances of message pump since one incoming message can become 1000 of outgoing messages. Also since the message pump implements the protocol its a bit more cpu intense than the network worker thread.
Since this is Adam’s page I’m not quite sure if he is interested on the details of a full blown description of my implementation. Theres are a few other modifications that I did, but this is just a gist of what I had to do. If you need to contact me directly, I can be reached at http://www.uiija.com, use the contact us link at the bottom of the page.
Hi,
How can we reject a connection? Let’s say I only want to support 5 users. I added a piece of code like this:
if( key.isAcceptable() )
System.out.println(“Client wants to connect………”);
if (getShouldAllowNewConnection(key)) {
key.channel().close();
continue;
}
// Normal stuff for adding the new key to “connectedChannels”.
That works, but then that same client can never attempt to reconnect again. It seems like the client will keep using the same socket channel somehow which the server has permanently condemned because of the channel().close() call. What’s the right way reject the client, but still let them attempt to connect thereafter?
Thanks,
Mark
Have you tried accepting the channel, THEN closing it?
I would suggest at least that you should accept it, and then add it to a queue of channels to reject as soon as they become writeable.
Then you can at least output e.g. a message “Too many connections; try again later”.
This will make your debugging much easier when you find at some unexpected time in the future one of your clients can’t connect for no apparent reason (i.e. you’ve got another client somewhere that’s still connected that you forgot about ;))
Diego – feel free to write as much as you want. I’m just glad it’s useful to you :).
Hi Adam,
I opted to let the client connect, but then I send them a ‘please disconnect’ command. My client sidegets the message then politely closes the connection from its side. That seems to work great. The only thing I’m worried about is – the server right now can’t hard kick a user if it wants to, it needs to ask the client to do it! I’ll give your recommendation a try though, it sounds like another correct way of doing it.
The code you posted is great by the way, I was previously using a classic threaded server model, this architecture is much easier to work with in my opinion,
Thanks!
EDIT: This project now has its own page for all info related to it – http://t-machine.org/index.php/category/projects/nio-server/
I just wanted to let everybody know that I’m running into an issue where the selector stops responding after running for 6 hours. I verified that the thread still running, however, selectedKeys() stops returning any keys. This is most probable a VM bug, I’m running 1.6.0.2 from sun on linux suse linux.
To work around the issue I added code to recreate the selector after 60 seconds of inactivity and no connected clients.
The code of the change I made follows:
Renamed the run function to runEx.
In the runEx function after while( iterator.hasNext() ) added
lastMessage = System.currentTimeMillis();
After lastPostProcessBegan = currentPostProcessBegan; added the following code to break out of the function if no messages were received in the las 60 seconds and I have no open connections.
if (currentPostProcessBegan – lastMessage > 60000 &&
connectedChannels.isEmpty())
{
System.out.println (Thread.currentThread().getName()+”::runEx “+
“No messages in the last 60 secs (rerun)”);
return;
}
created a new run function that calls runEx the function looks like this
public void run ()
{
while (status != STOPPING)
{
lastMessage = System.currentTimeMillis();
status = STARTED;
runEx();
if (listener)
{
try
{
ssc.close();
}
catch (Exception e)
{
e.printStackTrace();
}
ssc = null;
}
}
}
Note that the member variable listener is something I added to the code to support multiple threads working in parallel to support 1000’s of users where only one of the threads acts as a listener.
One more comment in regards to the change i mentioned yesterday.
The new run function does not need to cleanup ssc, since its cleanned in runex by the finally block.
Another change I implemented is a NOOP message in my protocol. When the selector does not return any keys for 60 I send an NOOP to all connected channels. This is done to really test if the socket its really open.
This statement is incorrect
This is done to really test if the socket its really open.
This is not done to test, is done to force an error if the connection is stale
In regards to closing a connection, its very simple. In your implementation of processStringMessage throw a closedChannelException, this in turn will do the cleanup of the socket.
Thanks Diego, I’ll give it a try.
If I’m reading the source right, there’s just a single thread handling the IO stuff – so everything is synchronized already? For example, If I have clients connecting, sending messages, and clients dropping their connection all at the same time, in the server class I’ll see everything serialized, something like:
processStringMessage();
processStringMessage();
keyCancelled();
processStringMessage();
keyCancelled();
processStringMessage();
etc…
I ask because I’m making a small player manager class which keeps a hash map of all connected clients etc. I guess I don’t need to synchronize anything in it because all these notifications are coming in serialized, as far as I can tell.
Thanks
[…] For those of you who wanted the source recently, there’s links to the downoad page from the SF page – the three files marked “version 1.0.0″ are *precisely* the same ones I originally uploaded to the blog post. […]
Hi Adam,
I ‘am in the process of researching comet in general. I just wanted to prototype comet for one of my application where I am currently polling the server ( especially a queue) to download the messages if any.It would be gr8 if you could provide some hands on for this.
Thanks
Hi. I am trying to create a client-server application for windows, that does the following:
From the client side (extending StringBasedClient):
– Install a windows hook and detect application window activations by capturing window focus events.
– On window focus detection, get the window title and process id, and send them to the server.
From the server side (extending StringBasedServer):
– Listen for window focus events, sent by one or more clients.
– show the window text and the application process id from those events in a gui
I’m creating strings to perform communication between the clients and the server, concatenating first the PID with a ‘\n’, and later the window text, just when the user activates an app.
I’m interested in creating a JList that handles the current connected clients. I’ve done it holding a SelectionKey that the user selects with the valueChanged event on the JList, to filter what messages are seen on the gui, using this code for the server:
public void processStringMessage(SelectionKey key, String message)
{
if(key.equals(usrSelectedKey)
{
//take the message, parse it and put the contents on the gui
}
}
Unfortunately, the code does work well, and I’m not sure what is the cause. Maybe I have missing a synchronized block, or maybe is something that I havenĀ“t seen on the documentation.
Thank you.
Hello all,
is anybody still using this server?
I noticed there is a FIXME in the ResponseListener.java class.
Has anybody fixed it? if yes, how?
It says the bug existed on the Server too, so does it mean it’s fixed already on the server side?
thanks a lot.
Server has a bug of close of channel. So it has many FINWAIT2.
This is idea of improve the performance of server. How about this ?
Single thread can’t accept the many connection at the same time,
Over 500 connection makes error and can’t handle.
Separate the accept(include bind) from the single thread, and make new thread.
This thread will be start by main thread. And accepted key stored queue for main thread.