Netty入门介绍

背景

最近在看如何实现一个简单的RPC服务。所使用的技术涉及到:Zookeeper、netty、spring。这篇文章不讲怎么实现RPC。因为涉及到了netty,所以我就去看了一下netty的一些资料。这里先大概讲一下netty,来个入门认识。

netty入门介绍

netty官网

Netty是NIO客户端服务器框架,能够快速轻松地开发诸如协议服务器和客户端之类的网络应用程序。 它大大简化了网络编程流程,如TCP和UDP套接字服务器。

“快速而简单”并不意味着由此产生的应用程序将受到可维护性或性能问题的困扰。 Netty已经通过实施许多协议(如FTP,SMTP,HTTP以及各种基于二进制和基于文本的传统协议)获得的经验仔细设计。 因此,Netty成功地找到了一种方法来实现轻松的开发,性能,稳定性和灵活性,而无需妥协。

特征

设计

  1. 用于各种传输类型的统一API - 阻塞和非阻塞套接字
  2. 基于灵活可扩展的事件模型,可以明确分离问题
  3. 高度可定制的线程模型 - 单线程,一个或多个线程池,如SEDA
  4. 真正的无连接数据报插座支持(自3.1版)

使用方便

  1. 详细的Javadoc,用户指南和示例
  2. 没有额外的依赖关系,JDK 5(Netty 3.x)或6(Netty 4.x)就足够了

    注意:某些组件(如HTTP / 2)可能有更多的要求。 有关详细信息,请参阅“需求”页面。

性能

  1. 更好的吞吐量,更低的延迟
  2. 资源消耗减少
  3. 最小化不必要的内存副本

安全

  1. 完成SSL / TLS和StartTLS支持

netty例子

官网站给的例子很充分,去clone下来看下就可以了。我看的是3.7的版本

放个栗子:

服务器通常应该响应请求。 我们学习如何通过实现ECHO协议向客户端写入响应消息,其中任何接收到的数据都将被发回。

public class EchoServerHandler extends SimpleChannelUpstreamHandler {

    private static final Logger logger = Logger.getLogger(
            EchoServerHandler.class.getName());

    private final AtomicLong transferredBytes = new AtomicLong();

    public long getTransferredBytes() {
        return transferredBytes.get();
    }

    @Override
    public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
        // Send back the received message to the remote peer.
        transferredBytes.addAndGet(((ChannelBuffer) e.getMessage()).readableBytes());
        e.getChannel().write(e.getMessage());
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
        // Close the connection when an exception is raised.
        logger.log(Level.WARNING, "Unexpected exception from downstream.", e.getCause());
        e.getChannel().close();
    }
}


public class EchoServer {

    private final int port;

    public EchoServer(int port) {
        this.port = port;
    }

    public void run() {
        // Configure the server.
        ServerBootstrap bootstrap = new ServerBootstrap(
                new NioServerSocketChannelFactory(
                        Executors.newCachedThreadPool(),
                        Executors.newCachedThreadPool()));

        // Set up the pipeline factory.
        bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
            public ChannelPipeline getPipeline() throws Exception {
                return Channels.pipeline(new EchoServerHandler());
            }
        });

        // Bind and start to accept incoming connections.
        bootstrap.bind(new InetSocketAddress(port));
    }

    public static void main(String[] args) throws Exception {
        int port;
        if (args.length > 0) {
            port = Integer.parseInt(args[0]);
        } else {
            port = 8080;
        }
        new EchoServer(port).run();
    }
}


public class EchoClientHandler extends SimpleChannelUpstreamHandler {

    private static final Logger logger = Logger.getLogger(
            EchoClientHandler.class.getName());

    private final ChannelBuffer firstMessage;
    private final AtomicLong transferredBytes = new AtomicLong();

    /**
     * Creates a client-side handler.
     */
    public EchoClientHandler(int firstMessageSize) {
        if (firstMessageSize <= 0) {
            throw new IllegalArgumentException("firstMessageSize: " + firstMessageSize);
        }
        firstMessage = ChannelBuffers.buffer(firstMessageSize);
        for (int i = 0; i < firstMessage.capacity(); i ++) {
            firstMessage.writeByte((byte) i);
        }
    }

    public long getTransferredBytes() {
        return transferredBytes.get();
    }

    @Override
    public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) {
        // Send the first message.  Server will not send anything here
        // because the firstMessage's capacity is 0.
        e.getChannel().write(firstMessage);
    }

    @Override
    public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
        // Send back the received message to the remote peer.
        transferredBytes.addAndGet(((ChannelBuffer) e.getMessage()).readableBytes());
        e.getChannel().write(e.getMessage());
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
        // Close the connection when an exception is raised.
        logger.log( Level.WARNING,"Unexpected exception from downstream.",e.getCause());
        e.getChannel().close();
    }
}

public class EchoClient {

    private final String host;
    private final int port;
    private final int firstMessageSize;

    public EchoClient(String host, int port, int firstMessageSize) {
        this.host = host;
        this.port = port;
        this.firstMessageSize = firstMessageSize;
    }

    public void run() {
        // Configure the client.
        ClientBootstrap bootstrap = new ClientBootstrap(
                new NioClientSocketChannelFactory(
                        Executors.newCachedThreadPool(),
                        Executors.newCachedThreadPool()));

        // Set up the pipeline factory.
        bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
            public ChannelPipeline getPipeline() throws Exception {
                return Channels.pipeline(
                        new EchoClientHandler(firstMessageSize));
            }
        });

        // Start the connection attempt.
        ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port));

        // Wait until the connection is closed or the connection attempt fails.
        future.getChannel().getCloseFuture().awaitUninterruptibly();

        // Shut down thread pools to exit.
        bootstrap.releaseExternalResources();
    }

    public static void main(String[] args) throws Exception {
        // Print usage if no argument is specified.
        if (args.length < 2 || args.length > 3) {
            System.err.println("Usage: " + EchoClient.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 EchoClient(host, port, firstMessageSize).run();
    }
}

理解

netty的编程实现的方式是:服务器端开放出自己的端口,客户端去将请求发送到服务器端的该端口号。这个和一般的项目是一样的。不一样的是netty封装了很多东西,使得我们不必去理会底层的一些知识,可以直接来快捷的编程。

使用方式:

服务器端通过ServerBootstrap来配置服务,然后设置管道工厂,并加入处理方法EchoServerHandler,然后将服务绑定到指定的端口号和开始接受请求。

客户端通过ServerBootstrap来配置客户端的配置,然后设置管道工厂,并加入处理方法EchoClientHandler,然后将请求发送到指定的地址和端口号,开始接受。然后等待返回的结果(也可以不等待),最后关闭线程。

在这些操作中几乎是差不多的,只不过是需求不一样,配置不一样。

对数据流的处理的方法在Handler这个类中,我们可以在这个类里实现自己需要的东西。比如该例子就是继承SimpleChannelUpstreamHandler,然后在其中放入echo所需要的代码。


参考资料:
网上资料
备注:
转载请注明出处:http://blog.csdn.net/wsyw126/article/details/75212978
作者:WSYW126

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值