继续翻译:http://netty.io/wiki/user-guide-for-5.x.htmlhtml
最简单的协议不是hello,而是DISCARD. bootstrap
也就是说,忽略全部收到的数据,不返回任何响应。api
为了完成这个协议,你仅仅须要作的是忽略全部收到的数据,让咱们开始从handler实现开始,这个处理IO事件(来源于Netty).服务器
package io.netty.example.discard;网络
import io.netty.buffer.ByteBuf;多线程
import io.netty.channel.ChannelHandlerContext;app
import io.netty.channel.ChannelHandlerAdapter;socket
/**tcp
* Handles a server-side channel.ide
*/
public class DiscardServerHandler extends ChannelHandlerAdapter { // (1)
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) { // (2)
// Discard the received data silently.
((ByteBuf) msg).release(); // (3)
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { // (4)
// Close the connection when an exception is raised.
cause.printStackTrace();
ctx.close();
}
}
DiscardServerHandler extends ChannelHandlerAdapter, 是对ChannelHandler的一个实现. ChannelHandler 提供了各类各样的事件方法可覆盖.
目前,继承 ChannelHandlerAdapter足够了 而不是本身实现接口里的方法。
咱们重写了channelRead() 事件方法,这个方法被接收到的消息调用,当从客户端里接收到新数据时。在这个例子当中,接收到的信息是 ByteBuf.
为了实现DISCARD协议,方法必须忽略收到的消息,ByteBuf 是一个计数器方式引用的对象,只有显式的经过release()方法才能够释放这个对象。请注意:这个handler有责任来释听任何传给本身的计数器引用的对象。
一般, channelRead() 方法用如下形式实现
@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) { try { // Do something with msg } finally { ReferenceCountUtil.release(msg); }}
The exceptionCaught() 事件方法:
当处理事件时,IO错误或者handler实现里有异常抛出。
大多数状况下,异常应该记录下来,而且相关的channel应该被关闭,尽管这个方法的实现能够不一样,这依赖于你想怎么处理。
好比,你也许想发送一个响应消息伴随错误码在关闭链接以前。
咱们已经实现了一半,剩下的是写main()方法来启动这个服务器。
package io.netty.example.discard;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
/**
* Discards any incoming data.
*/
public class DiscardServer {
private int port;
public DiscardServer(int port) {
this.port = port;
}
public void run() throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup(); // (1)
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap(); // (2)
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class) // (3)
.childHandler(new ChannelInitializer<SocketChannel>() { // (4)
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new DiscardServerHandler());
}
})
.option(ChannelOption.SO_BACKLOG, 128) // (5)
.childOption(ChannelOption.SO_KEEPALIVE, true); // (6)
// Bind and start to accept incoming connections.
ChannelFuture f = b.bind(port).sync(); // (7)
// Wait until the server socket is closed.
// In this example, this does not happen, but you can do that to gracefully
// shut down your server.
f.channel().closeFuture().sync();
} finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
int port;
if (args.length > 0) {
port = Integer.parseInt(args[0]);
} else {
port = 8080;
}
new DiscardServer(port).run();
}
}
1. NioEventLoopGroup 是一个多线程的事件循环,处理IO操做。
Netty提供了各类各样的 EventLoopGroup实现来应对不一样种类的传输。
咱们在例子中实现服务器端的工程,所以两个NioEventLoopGroup 将会被使用,第一个,常常叫作boss,接收一个进来的链接,第二个,叫作worker,处理流量(接受的链接)一旦 boss接收了链接而且注册接收的链接到worker.多少线程被使用而且它们如何映射到建立的Channels依赖于 EventLoopGroup 实现,也能够经过构造器配置。
2. ServerBootstrap 是一个帮助类来安装服务器,你能够经过Channel来直接安装。
3. 尽管如此,要知道,这是一个单调的过程,大多数状况下不须要作这个。
4. 这里,咱们使用了 NioServerSocketChannel 类来初始化一个新的Channel来接收进来的链接。这个handler老是被新接受的channel调用。
5. ChannelInitializer是一个特别的handler,目的是帮助一个用户来配置一个新的Channel. 最有可能的就是你想配置 ChannelPipeline of the new Channel 经过增长新的句柄方法好比DiscardServerHandler 来实现你的网络工程。
6. 一旦工程变复杂了,你将增长更多的方法到pipeline上来,提取这个匿名类到一个底层类里。
7. 你也能够设置参数(特定于channel实现),咱们在写一个TCP/IP服务器,因此咱们能够设置socket的参数好比tcpNoDelay and keepAlive.
8. 请参考ChannelOption 和特定的ChannelConfig实现来获取支持的选项说明。
9. 你意识到option()和childOption()?
10. option()是为了NioServerSocketChannel ,这个接受链接。childOption()是为了channels(被父ServerChannel接受) ,在例子当中是 NioServerSocketChannel 。
11. 咱们准备好了,剩下的就是绑定端口和启动服务器,这里,咱们绑定到8080端口,你能够调用bind()方法任意屡次只要愿意。(能够以不一样的绑定定制).
祝贺,你已经完成了第一个服务器的开发。
翻译 | ok | ok | ok |
理解 | ok | ok | ok |