Netty框架入门
来源:互联网 发布:淘宝闲置物品怎么下架 编辑:程序博客网 时间:2024/06/08 04:05
1:下载netty的jar和官方文档:http://www.jboss.org/netty/。现在的稳定版netty-3.6.3.Final-dist.tar.bz2。
2:将一个jar(netty-3.6.3.Final.jar)加到项目中,另一个源码包(netty-3.6.3.Final-sources.jar)也可以加进去。
3:例子实现
《服务端程序》
(一)首先编写解码器
MessageDecoder.java
/** * 解码器的类 */package test;import org.jboss.netty.buffer.ChannelBuffer;import org.jboss.netty.channel.Channel;import org.jboss.netty.channel.ChannelHandlerContext;import org.jboss.netty.handler.codec.frame.FrameDecoder;/** * @author 桑叶 * */public class MessageDecoder extends FrameDecoder{@Overrideprotected Object decode(ChannelHandlerContext ctx, Channel channel,ChannelBuffer buffer) throws Exception {// TODO 自动生成的方法存根if (buffer.readableBytes() < 4) {return null;}int dataLength = buffer.getInt(buffer.readerIndex());if (buffer.readableBytes() < dataLength+4) {return null;}buffer.skipBytes(4);byte[] decoded = new byte[dataLength];buffer.readBytes(decoded);String msg = new String(decoded);return msg;}}MessageDecoder继承自FrameDecoder,FrameDecoder是Netty code包中的辅助类,它是个ChannelUpstreamHandler,decode方法是FrameDecoder子类需要实现的。在上面的代码中有:
(1)检查ChannelBuffer中的字节数,如果ChannelBuffer可读的字节数少于4,则返回null等待下次读事件。
(2)继续检查ChannelBuffer中的字节数,如果ChannelBuffer可读的字节数少于dataLength+4,则返回null等待下次读事件。
(3)越过dataLength的字节。
(4)构造解码的字符串返回。
(二)编码器
/** * 编码器 */package test;import org.jboss.netty.buffer.ChannelBuffer;import org.jboss.netty.buffer.ChannelBuffers;import org.jboss.netty.channel.Channel;import org.jboss.netty.channel.ChannelHandlerContext;import org.jboss.netty.handler.codec.oneone.OneToOneEncoder;/** * @author 桑叶 * */public class MessageEncoder extends OneToOneEncoder {@Overrideprotected Object encode(ChannelHandlerContext ctx, Channel channel,Object msg) throws Exception {// TODO 自动生成的方法存根if (!(msg instanceof String)) {return msg;}String res = (String)msg;byte[] data = res.getBytes();int dataLength = data.length;ChannelBuffer buffer = ChannelBuffers.dynamicBuffer();buffer.writeInt(dataLength);buffer.writeBytes(data);return buffer;}}MessageEncoder是个ChannelDownstreamHandler。对该类的注解如下:
(1)如果编码的msg不是合法的类型,就直接返回该msg,之后OneToOneEncoder会调用ctx.sendDownstream(evt);来调用下一个ChannelDownstreamHandler。对于该例子来说,这种情况不应该出现的。
(2)开发者创建ChannelBuffer的用武之地就是这儿了,通常使用dynamicBuffer即可,表示得到的ChannelBuffer可动态增加大小。
(3)返回编码后的ChannelBuffer之后,OneToOneEncoder会调用Channels.write将数据写回客户端。
(三)服务端业务处理
/** * 服务端业务处理 */package test;import java.util.logging.Level;import java.util.logging.Logger;import org.jboss.netty.channel.ChannelHandlerContext;import org.jboss.netty.channel.ChannelStateEvent;import org.jboss.netty.channel.ExceptionEvent;import org.jboss.netty.channel.MessageEvent;import org.jboss.netty.channel.SimpleChannelUpstreamHandler;/** * @author 桑叶 * */public class MessageServerHandler extends SimpleChannelUpstreamHandler {private static final Logger logger = Logger.getLogger(MessageServerHandler.class.getName());@Overridepublic void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {if (!(e.getMessage() instanceof String)) {return ;}String msg = (String)e.getMessage();System.err.println("got msg:"+msg);e.getChannel().write(msg);}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {logger.log(Level.WARNING,"Unexpected exception from downstream.",e.getCause());e.getChannel().close();}public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {}}MessageServerHandler是服务端业务处理handler,其继承自SimpleChannelUpstreamHandler,并主要实现messageReceived事件。对该类的注解如下:
(1)该upstream事件流中,首先经过MessageDecoder,其会将decoder返回的解码后的数据结构造成MessageEvent.getMessage(),所以在handler上下文关系中,MessageEvent.getMessage()并不一定都返回ChannelBuffer
(2)MessageServerHandler只是简单的将得到的msg再写回给客户端。
e.getChannel().write(msg);操作将触发DownstreamMessageEvent事件,也就是调用上面的MessageEncoder将编码的数据返回给客户端。
(三)服务端主程序
/** * 服务端 */package test;import java.net.InetSocketAddress;import java.util.concurrent.Executors;import org.jboss.netty.bootstrap.ServerBootstrap;import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;/** * @author 桑叶 * */public class MessageServer {/** * @param args */public static void main(String[] args) throws Exception {// TODO 自动生成的方法存根ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory(Executors.newCachedThreadPool(),Executors.newCachedThreadPool()));bootstrap.getPipeline().addLast("decoder", new MessageDecoder());bootstrap.getPipeline().addLast("encoder", new MessageEncoder());bootstrap.getPipeline().addLast("handler", new MessageServerHandler());bootstrap.bind(new InetSocketAddress(9550));}}
(1)启动服务端主程序
(2)创建了3个ChannelHandler,需要将他们注册到ChannelPipeline,而ChannelPipeline又是和Channel对应的(是全局单例还是每个Channel对应一个ChannelPipline实例依赖于实现)。
(3)可以实现ChannelPipline的工厂接口ChannelPiplineFactory实现该目的。
(4)最后绑定端口号
《客户端程序》
(一)客户端处理
/** * 客户端处理 */package test;import java.util.logging.Level;import java.util.logging.Logger;import org.jboss.netty.channel.ChannelHandlerContext;import org.jboss.netty.channel.ChannelStateEvent;import org.jboss.netty.channel.ExceptionEvent;import org.jboss.netty.channel.MessageEvent;import org.jboss.netty.channel.SimpleChannelUpstreamHandler;/** * @author 桑叶 * */public class MessageClientHandler extends SimpleChannelUpstreamHandler {private static final Logger logger = Logger.getLogger(MessageClientHandler.class.getName());@Overridepublic void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) {String message = "hello kafka0102";e.getChannel().write(message);}@Overridepublic void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {System.out.println("messageReceived send message "+e.getMessage());try {Thread.sleep(3000);} catch (InterruptedException ex) {// TODO: handle exceptionex.printStackTrace();}e.getChannel().write(e.getMessage());}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {logger.log(Level.WARNING,"Unexpected exception from downstream.",e.getCause());e.getChannel().close();}}(1)客户端是先发送数据到服务端(downstream事件流),然后是处理从服务端接收的数据(upstream事件流)。
(2)这里有个问题是,怎么把需要发送的数据送到downstream事件流里呢?
这就用到了ChannelUpstreamHandler的channelConnected事件了。
(二)客户端主程序
/** * 客户端 */package test;import java.io.IOException;import java.net.InetSocketAddress;import java.util.concurrent.Executors;import org.jboss.netty.bootstrap.ClientBootstrap;import org.jboss.netty.channel.ChannelFuture;import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;/** * @author 桑叶 * */public class MessageClient {/** * @param args */public static void main(String[] args) throws IOException {// TODO 自动生成的方法存根create();}public static void create() {String host = "127.0.0.1";int port = 9550;//实例化一个客户端Bootstrap实例,其中NioClientSocketChannelFactory实例由Netty提供ClientBootstrap bootstrap = new ClientBootstrap(new NioClientSocketChannelFactory(Executors.newCachedThreadPool(),Executors.newCachedThreadPool()));//设置PipelineFactory,由客户端自己实现bootstrap.getPipeline().addLast("decoder", new MessageDecoder());bootstrap.getPipeline().addLast("encoder", new MessageEncoder());bootstrap.getPipeline().addLast("handler", new MessageClientHandler());//开始请求连接ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port));//等待连接关闭 或 请求连接失败future.getChannel().getCloseFuture().awaitUninterruptibly();//释放外部资源bootstrap.releaseExternalResources();}}
《调试》
首先运行 MessageServer 服务端程序,然后再运行 MessageClient 客户端程序.
结果如下:
messageReceived send message hello kafka0102
messageReceived send message hello kafka0102
messageReceived send message hello kafka0102
......
- Netty框架入门
- Netty框架入门
- Netty框架入门
- 【Netty入门】Netty概述
- Netty框架
- Netty 入门
- Netty入门
- Netty入门
- netty入门
- Netty入门
- Netty入门
- Netty入门
- netty入门
- Netty入门
- netty(七)netty入门应用
- Netty框架解读
- Netty框架启动详解
- Netty RPC框架
- Hdu 1039 - Easier Done Than Said?
- JDBC连接MySQL数据库
- 低电平中断和下降沿中断的区别
- PDF library in Java
- 面向对象
- Netty框架入门
- Lua syntax
- web性能优化14法则
- SSDP(简单服务发现协议)
- java打包命令
- ASP.NET页面传值的各种方法和分析
- ZeroMemory、memset和 “={0}” 的区别
- pat_1034
- 复杂的消息缓冲问题PV