Example: Shutting down the time server
To apply the three steps above to the TimeClient, TimeClient.main() could shut itself down gracefully by closing the only one client connection and releasing all resources used by ChannelFactory: package org.jboss.netty.example.time; public class TimeClient { public static void main(String[] args) throws Exception { ... ChannelFactory factory = ...; ClientBootstrap bootstrap = ...; ... ChannelFuture future = bootstrap.connect(...); future.awaitUninterruptibly(); if (!future.isSuccess()) { future.getCause().printStackTrace(); } future.getChannel().getCloseFuture().awaitUninterruptibly(); factory.releaseExternalResources(); } } The connect method of ClientBootstrap returns a ChannelFuture which notifies when a connection attempt succeeds or fails. It also has a reference to the Channel which is associated with the connection attempt. Wait for the returned ChannelFuture to determine if the connection attempt was successful or not. If failed, we print the cause of the failure to know why it failed. the getCause() method of ChannelFuture will return the cause of the failure if the connection attempt was neither successful nor cancelled. Now that the connection attempt is over, we need to wait until the connection is closed by waiting for the closeFuture of the Channel. Every Channel has its own closeFuture so that you are notified and can perform a certain action on closure. Even if the connection attempt has failed the closeFuture will be notified because the Channel will be closed automatically when the connection attempt fails. All connections have been closed at this point. The only task left is to release the resources being used by ChannelFactory. It is as simple as calling its releaseExternalResources() method. All resources including the NIO Selectors and thread pools will be shut down and terminated automatically. Shutting down a client was pretty easy, but how about shutting down a server? You need to unbind from the port and close all open accepted connections. To do this, you need a data structure that keeps track of the list of active connections, and it's not a trivial task. Fortunately, there is a solution, ChannelGroup. ChannelGroup is a special extension of Java collections API which represents a set of open Channels. If a Channel is added to a ChannelGroup and the added Channel is closed, the closed Channel is removed from its ChannelGroup automatically. You can also perform an operation on all Channels in the same group. For instance, you can close all Channels in a ChannelGroup when you shut down your server. To keep track of open sockets, you need to modify the TimeServerHandler to add a new open Channel to the global ChannelGroup, TimeServer.allChannels: @Override public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) { TimeServer.allChannels.add(e.getChannel()); } Yes, ChannelGroup is thread-safe. Now that the list of all active Channels are maintained automatically, shutting down a server is as easy as shutting down a client: package org.jboss.netty.example.time; public class TimeServer { static final ChannelGroup allChannels = new DefaultChannelGroup("time-server"); public static void main(String[] args) throws Exception { ... ChannelFactory factory = ...; ServerBootstrap bootstrap = ...; ... Channel channel = bootstrap.bind(...); allChannels.add(channel); waitForShutdownCommand(); ChannelGroupFuture future = allChannels.close(); future.awaitUninterruptibly(); factory.releaseExternalResources(); } } DefaultChannelGroup requires the name of the group as a constructor parameter. The group name is solely used to distinguish one group from others. The bind method of ServerBootstrap returns a server side Channel which is bound to the specified local address. Calling the close() method of the returned Channel will make the Channel unbind from the bound local address. Any type of Channels can be added to a ChannelGroup regardless if it is either server side, client-side, or accepted. Therefore, you can close the bound Channel along with the accepted Channels in one shot when the server shuts down. waitForShutdownCommand() is an imaginary method that waits for the shutdown signal. You could wait for a message from a privileged client or the JVM shutdown hook. You can perform the same operation on all channels in the same ChannelGroup. In this case, we close all channels, which means the bound server-side Channel will be unbound and all accepted connections will be closed asynchronously. To notify when all connections were closed successfully, it returns a ChannelGroupFuture which has a similar role with ChannelFuture.