import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelHandler; import org.jboss.netty.buffer.ChannelBuffer; /*DiscardServerHandler继承SimpleChannelHandler, ChannelHandler的接 *口实现类。 SimpleChannelHandler 提供各种事件的处理方法,你可以重载 *它们。到目前为止,继承 SimpleChannelHandler,而不是你自己去实现一个 *handler接口,是足够的。 */ public class DiscardServerHandler extends SimpleChannelHandler { /*我们在这里重载了messageReceived 事件处理方法。这个方法调用时提 *供了MessageEvent,它包含着刚刚从客户端收到的新数据。在这个例子中 *,我们通过什么也不做,来忽略收到的数据,从而实现DISCARD协议。 */ @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) { /*在套接字中传递的消息永远都是ChannelBuffer。ChannelBuffer *是一个核心的数据结构,它存储着Netty中的字节序列。它很像NIO *中的ByteBuffer,不过更加简单和灵活了。例如,Netty允许你构 *建一个由多个ChannelBuffer复合而成的ChannelBuffer,以减少不 *必要的内存复制。 尽管它在很多方面都和NIO的ByteBuffer相像, *仍然建议参考一下API手册。学习如何正确使用ChannelBuffer是 *使用轻松驾驭Netty的重要一步。 */ ChannelBuffer buf = (ChannelBuffer) e.getMessage(); while(buf.readable()) { System.out.println((char) buf.readByte()); System.out.flush(); } } /*当一个异常因为I/O错误由Netty抛出,或者由在处理事件过程中, *handler的实现抛出了异常,exceptionCaught 方法会被调用,并 *提供了ExceptionEvent。 尽管在特定情况下,实现这个方法时, *你需要对异常有不同的处理,但通常情况下,被捕获的异常应该被 *记录,并且对应的channel应该被关闭。例如,你可能想在关闭链接 *之前发送一个错误代码的回应信息。 */ @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) { e.getCause().printStackTrace(); Channel ch = e.getChannel(); ch.close(); } } import java.net.InetSocketAddress; import java.util.concurrent.Executors; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; public class DiscardServer { public static void main(String[] args)throws Exception { /*ChannelFactory 是创建并管理 Channel和它们相关资源的工厂。 *它处理所有的I/O 请求,执行I/O来生成ChannelEvent。Netty提 *供多种ChannelFactory实现。我们现在正在实现一个服务器端的 *例子,因此我们使用NioServerSocketChannelFactory。另一个 *需要知道的是,它并不是自行创建I/O线程。它试图从你在构造方 *法中指定的线程池中获得线程。对于线程是如何在你的应用运行 *环境中去管理的,它给了更多的控制,比如一个具有安全管理 *机制的应用服务器。 */ ChannelFactory factory= new NioServerSocketChannelFactory( Executors.newCachedThreadPool(), Executors.newCachedThreadPool()); /*ServerBootstrap是一个建立服务器的工具类。你当然可以直接 *使用Channel来构建一个服务器,但你要清楚这将是一个繁琐的 *过程,而其实你根本没必要这么做。 */ ServerBootstrap bootstrap = new ServerBootstrap(factory); /*这里,我们配置了ChannelPipelineFactory。当一个新的连接接 *入到服务器,一个新的ChannelPipeline将由指定的ChannelPipelineFactory来 *创建。这个新的Pipeline包含着DiscardServerHandler。随着这个应用逐步完 *善,最终实际你就是添加更多的handler到Pipeline,并抽象出这个匿名类 *成为一个顶级类。 */ bootstrap.setPipelineFactory(new ChannelPipelineFactory() { public ChannelPipeline getPipeline() { return Channels.pipeline(new DiscardServerHandler()); } }); /*你还可以设置针对Channel实现的特定参数。我们正在编写的是TCP/IP服务 *,所以我们可以设置套接字的选项参数,如tcpNoDelay 和 keepAlive。 *请注意到这个"child."前缀出现在所有参数前,它意味着这个选项参数应用 *于接入的Channel,而不是ServerSocketChannel的参数。你可以按下面做法 *来为ServerSocketChannel设定参数。 *bootstrap.setOption("reuseAddress", true); */ bootstrap.setOption("child.tcpNoDelay",true); bootstrap.setOption("child.keepAlive",true); bootstrap.bind(new InetSocketAddress(8080)); } } 刚才我们已经写了我们第一个服务器。现在需要的是测试一下它的运行情况。最简单的测试方法,莫过于使用telnet命令了。例如,你可以在命令行上输入"telnet localhost 8080",然后随便输入些什么。