This topic has not yet been written. The content below is from the topic description.
1.5. Writing a Time Server The protocol to implement in this section is the TIME protocol. It is different from the previous examples in that it sends a message, which contains a 32-bit integer, without receiving any requests and loses the connection once the message is sent. In this example, you will learn how to construct and send a message, and to close the connection on completion. Because we are going to ignore any received data but to send a message as soon as a connection is established, we cannot use the messageReceived method this time. Instead, we should override the channelConnected method. The following is the implementation: package org.jboss.netty.example.time; public class TimeServerHandler extends SimpleChannelHandler { @Override public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) { Channel ch = e.getChannel(); ChannelBuffer time = ChannelBuffers.buffer(4); time.writeInt(System.currentTimeMillis() / 1000); ChannelFuture f = ch.write(time); f.addListener(new ChannelFutureListener() { public void operationComplete(ChannelFuture future) { Channel ch = future.getChannel(); ch.close(); } }); } @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) { e.getCause().printStackTrace(); e.getChannel().close(); } } As explained, channelConnected method will be invoked when a connection is established. Let us write the 32-bit integer that represents the current time in seconds here. To send a new message, we need to allocate a new buffer which will contain the message. We are going to write a 32-bit integer, and therefore we need a ChannelBuffer whose capacity is 4 bytes. The ChannelBuffers helper class is used to allocate a new buffer. Besides the buffer method, ChannelBuffers provides a lot of useful methods related to the ChannelBuffer. For more information, please refer to the API reference. On the other hand, it is a good idea to use static imports for ChannelBuffers: import static org.jboss.netty.buffer.ChannelBuffers.*; ... ChannelBuffer dynamicBuf = dynamicBuffer(256); ChannelBuffer ordinaryBuf = buffer(1024); As usual, we write the constructed message. But wait, where's the flip? Didn't we used to call ByteBuffer.flip() before sending a message in NIO? ChannelBuffer does not have such a method because it has two pointers; one for read operations and the other for write operations. The writer index increases when you write something to a ChannelBuffer while the reader index does not change. The reader index and the writer index represents where the message starts and ends respectively. In contrast, NIO buffer does not provide a clean way to figure out where the message content starts and ends without calling the flip method. You will be in trouble when you forget to flip the buffer because nothing or incorrect data will be sent. Such an error does not happen in Netty because we have different pointer for different operation types. You will find it makes your life much easier as you get used to it -- a life without flipping out! Another point to note is that the write method returns a ChannelFuture. A ChannelFuture represents an I/O operation which has not yet occurred. It means, any requested operation might not have been performed yet because all operations are asynchronous in Netty. For example, the following code might close the connection even before a message is sent: Channel ch = ...; ch.write(message); ch.close(); Therefore, you need to call the close method after the ChannelFuture, which was returned by the write method, notifies you when the write operation has been done. Please note that, close also might not close the connection immediately, and it returns a ChannelFuture. How do we get notified when the write request is finished then? This is as simple as adding a ChannelFutureListener to the returned ChannelFuture. Here, we created a new anonymous ChannelFutureListener which closes the Channel when the operation is done. Alternatively, you could simplify the code using a pre-defined listener: f.addListener(ChannelFutureListener.CLOSE);