Tip:
Highlight text to annotate it
X
Hi, in this screencast I'll be showing you how to create a simple chat application
using Netty in under 15 minutes.
First we'll need to create a new Java project, and I'm going to use Maven for this.
For this screencast I'll be using the netty-all library.
And to avoid some runtime warnings I'm also adding the javassist library.
Also since we're not living in the dark ages anymore, I want Maven to use the latest Java
1.7 for this project.
Alright, now we're ready to get started.
Let's create a new class called the ChatClient, and we'll need to assign it a new package.
Let's create a constructor using two parameters: the host to connect to, and the port to connect to.
And let's store these into two local final variables.
We'll also write a public run method for the actual client behavior.
First we'll need an instance of Netty's new IO event loop group.
Next we're going to use the Bootstrap class to setup a Channel using this EventLoopGroup.
And we're going to tell it to use the new IO Sockets.
Finally we'll tell it that we want the Channel to be handled by the ChatClientIntializer
class which we'll implement in a minute.
Now we can ask the Bootstrap object to create a connection to the server using the specified
host and port.
Once connected, we can ask for the Channel object which we can use for interaction with
the server.
We'll also need a BufferedReader to capture the user's input from the console.
We'll add a while loop which takes the user's input from the console and writes it to the server.
And finally when we exit the loop for whatever reason we'll need to shutdown the EventLoopGroup.
Also let's add a main method which we can run to start a ChatClient on port 8000 on
localhost.
Now it's time to implement the ChatClientInitializer.
In stead of implementing the general ChannelHandler interface we want it to extend the ChannelInitializer
class.
Keep in mind that we want this class to initialize SocketChannels, so we'll need to make some
changes.
Here's we'll define what Netty calls a pipeline. It basically describes how we want to organize
our communication.
First we'll tell Netty we're expecting frames of at most 8192 in size, each delimited with
line endings.
Since we're just exchanging Strings between the server and clients, we can use the StringDecoder
to decode received bytes into Strings.
And we can use the StringEncoder to encode Strings into bytes, which we can then send
over to the server.
And finally we'll need to define a class which will handle all the decoded incoming Strings
from the server.
This class will need to implement the ChannelInboundMessageHandlerAdapter class.
Note that we want this class to handle incoming String objects, so we'll have to modify it
a bit.
All we want to do is to print any String message we receive from the server to the console.
All that remains for the ChatClient are a few calls which could potentially throw Exceptions.
For simplicity I'm just going to ignore these.
The ChatClient is now finished. Now let's start on the ChatServer by creating the ChatServer
class.
We're going to create a similar setup as to the ChatClient class. Let's start by creating
a constructor with a single parameter: the port to listen on for incoming connections.
And let's store this in a local final variable.
Next we'll create a run method, which will listen for incoming connections and hand them
off for processing.
We'll also need two new IO EventLoopGroups. The boss group will accept incoming connections
as they arrive and pass them on processing to the worker group.
Similarly to how the ChatClient class uses the Bootstrap class to set up a Channel, we
can use the ServerBootstrap class here to define how the server will process incoming
connections.
We first specify that it should use the boss group and the worker group.
And like the ChatClient, we want to use the new IO ServerSockets for communication.
Next we need to specify a class which will handle any incoming messages. We'll implement
this in a minute.
Finally we can tell the ServerBootstrap object to bind to the specified port, and start listening
for incoming connections.
And before we exit the run method it's a good practice to clean up the used EventLoopGroups.
Let's also add a main method which will start a ChatServer using port 8000 to listen for
incoming connections.
Now it's time to implement the ChatServerInitializer class.
Again we don't want to implement the general ChannelHandler interface, but rather extend
the ChannelInitializer class.
This initializer should initialize SocketChannels, so we'll need to make some minor changes.
Like the ChatClientInitializer class, we'll need to specify the ChannelPipeline.
However the framer, decoder and encoder are the exact same as in the ChatClientInitializer
class. So we can just copy these over.
Finally, we'll need to specify a handler class which
will handle any incoming messages from the clients.
This class should extend the ChannelInboundMessageHandlerAdapter class in favor of implementing the general
ChannelHandler interface.
We'll need to slightly modify it because we are going to process incoming String messages
here.
In order to identify who has sent us a message, we can ask for the Channel object.
Next, we will need to send a message to everybody else. We can do this by iterating over all
known Channels and write a message to each Channel except for the one on which we
received the message.
We can keep track of these Channels in the ChannelGroup object.
Remember that we should only send the message to all Channels except for the one which has sent
the message to the server.
We're almost done. We still need to keep track of our active Channels.
We can do this by overriding the handlerAdded method.
This method will be called when a new ChatClient connects to the ChatServer.
Here we can notify the other ChatClients that a new client has joined.
And finally, also add it to the ChannelGroup object.
We'll also have to keep track of when ChatClients disconnect from the ChatServer.
We can do this by overriding the handlerRemoved method.
Here we can also notify all ChatClients that one client
has disconnected and left the conversation
And finally, remove it from the ChannelGroup object.
Finally, one method call could potentially throw an exception, but I'm going to ignore
this in this screencast.
Alright! We're done writing code. It time to test our new chat system!
Let's start by running a ChatServer instance.
Next, I'll start a ChatClient.
Also, let's add and position a second console for you so that we can display two ChatClients
side by side.
As you can see, there is only one ChatClient running so let's start a second one.
On the left you will see the first client and on the right the second. Now let's play
around a bit.
Alright! Everything seems to work properly.
Thank you for watching this screencast I hope you've enjoyed it.