package org.jboss.netty.example.discard; public class DiscardServerHandler extends SimpleChannelHandler {1 @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {2 } @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {3 e.getCause().printStackTrace(); Channel ch = e.getChannel(); ch.close(); } }
DiscardServerHandler
extends
SimpleChannelHandler
, which is an implementation of
ChannelHandler
.
SimpleChannelHandler
provides various event handler methods that you can override. For now, it is just enough to extend
SimpleChannelHandler
rather than to implement the handler interfaces by yourself.
We override the messageReceived
event handler method here. This method is called with aMessageEvent
, which contains the received data, whenever new data is received from a client. In this example, we ignore the received data by doing nothing to implement the DISCARD protocol.
exceptionCaught
event handler method is called with anExceptionEvent
when an exception was raised by Netty due to I/O error or by a handler implementation due to the exception thrown while processing events. In most cases, the caught exception should be logged and its associated channel should be closed here, although the implementation of this method can be different depending on what you want to do to deal with an exceptional situation. For example, you might want to send a response message with an error code before closing the connection.
package org.jboss.netty.example.discard; import java.net.InetSocketAddress; import java.util.concurrent.Executors; public class DiscardServer { public static void main(String[] args) throws Exception { ChannelFactory factory = new NioServerSocketChannelFactory1( Executors.newCachedThreadPool(), Executors.newCachedThreadPool()); ServerBootstrap bootstrap = new ServerBootstrap2(factory); bootstrap.setPipelineFactory(new ChannelPipelineFactory() {3 public ChannelPipeline getPipeline() { return Channels.pipeline(new DiscardServerHandler()); } }); bootstrap.setOption("child.tcpNoDelay", true);4 bootstrap.setOption("child.keepAlive", true); bootstrap.bind(new InetSocketAddress(8080));5 } }
ChannelFactory
is a factory which creates and managesChannel
s and its related resources. It processes all I/O requests and performs I/O to generateChannelEvent
s. Netty provides various ChannelFactory
implementations. We are implementing a server-side application in this example, and thereforeNioServerSocketChannelFactory
was used. Another thing to note is that it does not create I/O threads by itself. It is supposed to acquire threads from the thread pool you specified in the constructor, and it gives you more control over how threads should be managed in the environment where your application runs, such as an application server with a security manager.
ServerBootstrap
is a helper class that sets up a server. You can set up the server using aChannel
directly. However, please note that this is a tedious process and you do not need to do that in most cases.
Here, we configure the ChannelPipelineFactory
. Whenever a new connection is accepted by the server, a newChannelPipeline
will be created by the specifiedChannelPipelineFactory
. The new pipeline contains theDiscardServerHandler
. As the application gets complicated, it is likely that you will add more handlers to the pipeline and extract this anonymous class into a top level class eventually.
You can also set the parameters which are specific to the Channel
implementation. We are writing a TCP/IP server, so we are allowed to set the socket options such astcpNoDelay
and keepAlive
. Please note that the"child."
prefix was added to all options. It means the options will be applied to the acceptedChannel
s instead of the options of the ServerSocketChannel
. You could do the following to set the options of theServerSocketChannel
:
bootstrap.setOption("reuseAddress", true);
We are ready to go now. What's left is to bind to the port and to start the server. Here, we bind to the port8080
of all NICs (network interface cards) in the machine. You can now call thebind
method as many times as you want (with different bind addresses.)
*****
ChannelFactory生产和管理所有渠道和渠道相关资源,并且处理所有io请求, 将io请求封装成ChannelEvents。另外需要注意ChannelFactory并不会自主创建线程对象。它从线程池中获取线程。 而线程池中的线程则根据传入的参数来确定。
例如NioServerSocketChannelFactory 有两个构造方法, 一个参数为(Executor bossExecutor, Executor workerExecutor), 一个为(Executor bossExecutor, Executor workerExecutor, int workerCount)其中workerCount就是线程数。第一个构造方法中没有传入workerCount则默认回去取cpu可以支持的最大线程数,再乘以2。
public NioServerSocketChannelFactory( Executor bossExecutor, Executor workerExecutor) { this(bossExecutor, workerExecutor, SelectorUtil.DEFAULT_IO_THREADS); }
static final int DEFAULT_IO_THREADS = Runtime.getRuntime().availableProcessors() * 2;这里有一点需要注意, 我的机器是thinkpad420, 处理器个数为2, 但是支持超线程, 最大线程数可以达到4,所以在我机器上DEFAULT_IO_THREADS的值为8。
*******
为bootstrap添加了channelFactory后, 每次服务端接收到客户端的连接请求, 都会创建相应的管道pipeline, 这个管道中包含了我们自定义的用来处理客户端请求的handler。
bootstrap.setOption 方法的key值如果是为接入的客户端渠道设置属性则需要加上“child.”前缀, 如果没有这个前缀,则属性就是为服务端ServerSocketChannel设置的。