需要用到netty,之前就当年实习的时候用过Mina,netty没用过,所以加急学习了一下,感觉还不错,不多说,从官网入手,官网地址:http://netty.io/wiki/user-guide-for-4.x.html
有兴趣的朋友可以自己去查看。
<dependencies> <dependency> <groupId>io.nettygroupId> <artifactId>netty-allartifactId> <version>4.1.6.Finalversion> dependency> dependencies>
package netty_beginner; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; /** * Created by moon on 2017/4/5. */ public class DiscardServerHandler extends ChannelInboundHandlerAdapter { // (1) @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { // (2) // super.channelRead(ctx, msg); ((ByteBuf) msg).release(); // (3) // ByteBuf in = (ByteBuf) msg; // try { // while (in.isReadable()) { // System.out.print((char) in.readByte()); // System.out.flush(); // } // } finally { // ReferenceCountUtil.release(msg); // } } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { // (5) // super.exceptionCaught(ctx, cause); cause.printStackTrace(); ctx.close(); } }
DiscardServerHandler
继承自ChannelInboundHandlerAdapter,它是 ChannelInboundHandler
. ChannelInboundHandler的实现。提供可以覆盖的各种事件处理程序方法。现在,只需要扩展ChannelInboundHandlerAdapter即可,而不是自己实现处理程序接口。
在这里,我们重写通道读取channelRead()事件处理方法。每当从客户端收到新数据时,都会使用接收到的消息调用此方法。在这个例子中,接收到的消息的类型是ByteBuf。
为了实现DISCARD协议,处理程序必须忽略收到的消息。ByteBuf是一个引用计数对象,必须通过release()方法显式释放。请记住,处理程序有责任释放传递给处理程序的引用计数对象。通常,channelRead()处理方法的实现方式如下:
@Override public void channelRead(ChannelHandlerContext ctx, Object msg) { try { // Do something with msg } finally { ReferenceCountUtil.release(msg); } }
exceptionCaught()
事件将会被Throwable抛出。在大多数情况下,应该记录捕获到的异常,并在此关闭其关联的通道,虽然这种方法的实现可以根据你想要处理的异常情况而有所不同。例如,您可能希望在关闭连接之前发送带有错误代码的响应消息。package netty_beginner; 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; /** * Created by moon on 2017/4/5. */ public class DiscardServer { private int port; public DiscardServer(int port) { this.port = port; } public void run() throws InterruptedException { 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 InterruptedException { int port; if (args.length > 0) { port = Integer.parseInt(args[0]); } else { port = 8080; } new DiscardServer(port).run(); } }
恭喜,到了现在这个阶段我们已经完成了。下面可以进行尝试,那么在尝试之前,我要说一句,这个例子非常好,就是一点比较费解,即使我开始测试,往本机8080端口发送内容,我们根本看不出来是否成功,因为我们把内容忽略了 - -!。所以改一下,我们的DiscardServerHandler改成如下,打印收到的字符:
package netty_beginner; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.util.ReferenceCountUtil; /** * Created by moon on 2017/4/5. */ public class DiscardServerHandler extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { // super.channelRead(ctx, msg); // ((ByteBuf) msg).release(); ByteBuf in = (ByteBuf) msg; try { while (in.isReadable()) { System.out.print((char) in.readByte()); System.out.flush(); } } finally { ReferenceCountUtil.release(msg); } } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { // super.exceptionCaught(ctx, cause); cause.printStackTrace(); ctx.close(); } }
然后我们启动运行我们的main方法:
由于我用的win,不是linux,所以下面的操作可能有人不好使,因为有的win默认没有启动telnet,这个自己网上百度,很容易。我们打开cmd,输入telnet,进入一个新的窗口:
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { ctx.write(msg); // (1) ctx.flush(); // (2) }
package netty_beginner; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; /** * Created by moon on 2017/4/5. */ public class TimeServerHandler extends ChannelInboundHandlerAdapter { @Override public void channelActive(final ChannelHandlerContext ctx) throws Exception { final ByteBuf time = ctx.alloc().buffer(4); time.writeInt((int) (System.currentTimeMillis() / 1000L + 2208988800L)); final ChannelFuture f = ctx.writeAndFlush(time); f.addListener(new ChannelFutureListener() { public void operationComplete(ChannelFuture future) throws Exception { assert f == future; ctx.close(); } }); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { super.exceptionCaught(ctx, cause); } }
Channel ch = ...; ch.writeAndFlush(message); ch.close();因此,您需要在ChannelFuture完成之后调用close()方法,该方法由write()方法返回,并且在写入操作完成后通知其监听器。请注意,close()也可能不会立即关闭连接,并且它返回ChannelFuture。
f.addListener(ChannelFutureListener.CLOSE);
$ rdate -o -p