Netty4 1_netty入门

来源:互联网 发布:java 字段 编辑:程序博客网 时间:2024/06/05 18:44

那netty是什么东西呢?

Netty 努力提供一个异步的事件驱动网络程序框架和工具,  能快速开发易于维护的高性能,  高可扩展性的协议服务器和客户端.

换句话说,  Netty 是一个NIO 客户端/ 服务器架构,  可以快速和容易的开发网络程序就像协议服务器和客户端.它极大的简化了网络开发,  如TCP 和UDP 套接字服务器的开发.带着来自于大量协议如FTP,SMTP,  HTTP以及各种二进制和基于文本的传统协议的实现的经验,  Netty被精心设计.   所以,  Netty 成功的找到一种方法去实现简易开发,  性能,  稳定性和灵活性不冲突.


废话一下:本人认为netty还是比较深奥的东西,因为涉及到java NIO以及java多线程,虽然这些都被封装在netty里面,但作为一名优秀的程序员,你有必要对netty的源码进行剖析,同时,netty在设计上也有点让人纳闷,比如netty3和netty4的改动就很大,如果你在网上找到一个netty3的学习资料,那我只能很抱歉的告诉你,你可以放弃那资料了,可能在设计理念上没有多大的差别,但是,对原有netty3项目的维护将会带来一个很大的问题,关于netty3、4区别,我推荐你看一下http://www.oschina.net/translate/netty-4-0-new-and-noteworthy


同时,在学习netty之前,我建议可以去先了解一下nio、多线程并发编程,以及socket编程,这在我前面的博客中有讲到,还有未发布上去的会接着发上去


说明一下:本博客主要以入门为主,介绍运行的大致过程,至于源代码里面的细节接下来的博客中再一起深入探究吧


好吧,初步了解了netty之后,我们开始进行netty的初次出门吧

首先看一个最简单的客户端服务器的例子Discard(可以去github上面下载netty4 example)

/** * 服务器 * @author chenx_000 * */public class DiscardServer{private final int port;public DiscardServer(int port){this.port = port;}public void run() throws Exception{// 创建两个EventLoopGroup,一个充当register处理器bossGroup,bossGroup把处理过的通道交给workerGroup进行io操作EventLoopGroup bossGroup = new NioEventLoopGroup();EventLoopGroup workerGroup = new NioEventLoopGroup();try{// 一个服务器助手类ServerBootstrap b = new ServerBootstrap();b.group(bossGroup, workerGroup)        //用它来建立新accept的连接,用于构造serversocketchannel的工厂类.channel(NioServerSocketChannel.class)//在serverBootstrap内部用该handler去处理实例化的channel.childHandler(new ChannelInitializer<SocketChannel>(){ //当有新accept的时候,这个方法会调用@Overridepublic void initChannel(SocketChannel ch)throws Exception{ch.pipeline().addLast(new DiscardServerHandler());}});// 绑定并等待accept到来的连接ChannelFuture f = b.bind(port).sync();//关闭服务器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();}}



我们先看一下红色方法.childHandler(new ChannelInitializer<SocketChannel>()



再看一下ServerBootstrap的属性


上面的childHandler就是childHandler(new ChannelInitializer<SocketChannel>()进行复制,并在ServerBootstrap中init(Channel)方法中

 @Override    void init(Channel channel) throws Exception {        final Map<ChannelOption<?>, Object> options = options();        synchronized (options) {            channel.config().setOptions(options);        }        final Map<AttributeKey<?>, Object> attrs = attrs();        synchronized (attrs) {            for (Entry<AttributeKey<?>, Object> e: attrs.entrySet()) {                @SuppressWarnings("unchecked")                AttributeKey<Object> key = (AttributeKey<Object>) e.getKey();                channel.attr(key).set(e.getValue());            }        }        ChannelPipeline p = channel.pipeline();        if (handler() != null) {            p.addLast(handler());        }        final EventLoopGroup currentChildGroup = childGroup;        final ChannelHandler currentChildHandler = childHandler;        final Entry<ChannelOption<?>, Object>[] currentChildOptions;        final Entry<AttributeKey<?>, Object>[] currentChildAttrs;        synchronized (childOptions) {            currentChildOptions = childOptions.entrySet().toArray(newOptionArray(childOptions.size()));        }        synchronized (childAttrs) {            currentChildAttrs = childAttrs.entrySet().toArray(newAttrArray(childAttrs.size()));        }        p.addLast(new ChannelInitializer<Channel>() {            @Override            public void initChannel(Channel ch) throws Exception {                ch.pipeline().addLast(new ServerBootstrapAcceptor(                        currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));            }        });    }



由红色部分代码可见刚才在类DiscardServer代码部分加入的channelInittiallizer被重新封装成channelinitalizer加入了channle的piplline中。而pipline中channelContext的handler进行IO操作。


在看一下DiscardServer中的实际的io处理类吧

public class DiscardServerHandler extends SimpleChannelInboundHandler<Object> {    private static final Logger logger = Logger.getLogger(            DiscardServerHandler.class.getName());    //读channel中的msg,该例子是一个discard,所以直接摒弃就是了    @Override    public void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {        ByteBuf b = (ByteBuf) msg;        b.release();    }    //当netty发生错误,执行该方法    @Override    public void exceptionCaught(ChannelHandlerContext ctx,            Throwable cause) throws Exception {        // Close the connection when an exception is raised.        logger.log(                Level.WARNING,                "Unexpected exception from downstream.",                cause);        ctx.close();    }}
这是一个inboundhandler,就是对进来的io进行处理,以后会再讲讲channelhandler的


好吧,这就是服务器端了

好吧,接下来看一下客户端吧

public class DiscardClient{private final String host;private final int port;private final int firstMessageSize;public DiscardClient(String host, int port, int firstMessageSize){this.host = host;this.port = port;this.firstMessageSize = firstMessageSize;}public void run() throws Exception{EventLoopGroup group = new NioEventLoopGroup();try{Bootstrap b = new Bootstrap();b.group(group).channel(NioSocketChannel.class).handler(new DiscardClientHandler(firstMessageSize));// 尝试建立连接ChannelFuture f = b.connect(host, port).sync();// 等待直到连接断开f.channel().closeFuture().sync();} finally{group.shutdownGracefully();}}public static void main(String[] args) throws Exception{if (args.length < 2 || args.length > 3){System.err.println("Usage: " + DiscardClient.class.getSimpleName()+ " <host> <port> [<first message size>]");return;}// Parse options.final String host = args[0];final int port = Integer.parseInt(args[1]);final int firstMessageSize;if (args.length == 3){firstMessageSize = Integer.parseInt(args[2]);}else{firstMessageSize = 256;}new DiscardClient(host, port, firstMessageSize).run();}}

再看一下io处理类

public class DiscardClientHandler extends SimpleChannelInboundHandler<Object>{private static final Logger logger = Logger.getLogger(DiscardClientHandler.class.getName());private final int messageSize;private ByteBuf content;private ChannelHandlerContext ctx;public DiscardClientHandler(int messageSize){if (messageSize <= 0){throw new IllegalArgumentException("messageSize: " + messageSize);}this.messageSize = messageSize;}@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception{this.ctx = ctx;//初始化信息content = ctx.alloc().directBuffer(messageSize).writeZero(messageSize);// 发送已经初始化的信息generateTraffic();}@Overridepublic void channelInactive(ChannelHandlerContext ctx) throws Exception{content.release();}@Overridepublic void channelRead0(ChannelHandlerContext ctx, Object msg)throws Exception{}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)throws Exception{// 关闭连接当抛出一个异常logger.log(Level.WARNING, "Unexpected exception from downstream.",cause);ctx.close();}long counter;private void generateTraffic(){//冲洗出站套接字的缓冲区。刷新后,再次生成相同数量的传送。ctx.writeAndFlush(content.duplicate().retain()).addListener(trafficGenerator);}private final ChannelFutureListener trafficGenerator = new ChannelFutureListener(){@Overridepublic void operationComplete(ChannelFuture future) throws Exception{if (future.isSuccess()){generateTraffic();}}};}

其实客户端和服务器端处理的流程都是差不多,只是一个是等待连接一节accept,一个是connect


到此为止,一个服务器客户端程序就已经完成了,现在可能知道netty是做什么,但对netty的内部还是很迷茫,这也应该很正常的,以后再继续netty4源码分析,一起进一步了解netty的体系吧









3 0
原创粉丝点击