Netty5基础知识介绍及简单使用

Netty基础知识

Netty 是一个 NIO client-server(客户端服务器)框架, 使用 Netty
可以快速开发网络应用,例如服务器和客户端协议。Netty
提供了一种新的方式来使开发网络应用程序,这种新的方式使得它很容易使用和有很强的扩展性。Netty 的内部实现时很复杂的,但是 Netty
提供了简单易用的 api 从网络处理代码中解耦业务逻辑。Netty 是完全基于 NIO 实现的,所以整个 Netty 都是异步的。

网络应用程序通常需要有较高的可扩展性,无论是 Netty 还是其他的基于 Java NIO的框架,都会提供可扩展性的解决方案。Netty 中一个关键组成部分是它的异步特性。
为什么使用 Netty ?

  • 作为一个 NIO client-server 框架,Netty 提供了这样的一个间接的解决方法。Netty 提供了高层次的抽象来简化
    TCP 和 UDP 服务器的编程,但是你仍然可以使用底层地 API。
  • 多年来,Netty 变的更广为人知,它是 Java 网络的首选框架,在一些开源或非开源的项目中可以体现。并且,Netty 在 2011
    年获得 Duke’s Choice Award(Duke’s Choice 奖)。此外,在 2011 年,Netty 的创始人 Trustion Lee 离开 RedHat 后加入 Twitter,在这一点上,Netty 项目奖会成为一个独立的项目组织。RedHat 和 Twitter 都使用 Netty,所以它毫不奇怪。使用 Netty 的项目越来越多,Netty 的用户群体和项目以及 Netty 社区都是非常活跃的。
  • NIO 是一个比较底层的 APIs,它依赖于操作系统的 IO APIs。Java 实现了统一的接口来操作
    IO,其在所有操作系统中的工作行为是一样的,这是很伟大的。使用 NIO 会经常发现代码在 Linux 上正常运行,但在 Windows
    上就会出现问题。我建议你如果使用 NIO 编写程序, 就应该在所有的操作系统上进行测试来支持,
    使程序可以在任何操作系统上正常运行;即使在所有的 Linux 系统上都测试通过了,也要在其他的操作系统上进行测试;你若不
    验证,以后就可能会出问题。
  • NIO2 看起来很理想,但是 NIO2 只支持 Jdk1.7+,若你的程序在 Java1.6 上运行,则无法使用
    NIO2。另外,Java7 的 NIO2 中没有提供 DatagramSocket 的支持,所以 NIO2只支持 TCP 程序,不支持
    UDP 程序。 Netty 提供一个统一的接口, 同一语义无论在 Java6 还是 Java7 的环境下都是可以运行的,开发者无需关心底层
    APIs 就可以轻松实现相关功能。

Netty官网下载
下载地址 http://netty.io/
服务端

package com.cyq.server;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;

public class EchoServer {

    private final int port;

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

    public void start() throws Exception {
        //指定 NioEventLoopGroup 来接受和处理新连接
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            //create ServerBootstrap instance
            ServerBootstrap b = new ServerBootstrap();
            //Specifies NIO transport, local socket address
            /*Adds handler to channel pipeline 指定通道类型为 NioServerSocketChannel
            设置 InetSocketAddress 让服务器监听某个端口已等待客户端连接
             */
            b.group(group).channel(NioServerSocketChannel.class).
                   localAddress(port).childHandler(new ChannelInitializer<Channel>() {
                @Override
                protected void initChannel(Channel ch) throws Exception {
                    ch.pipeline().addLast(new EchoServerHandler());
                }
            });
            /*Binds server, waits for server to close, and releases resources
             * 绑定服务器等待直到绑定完成,调用 sync()方法会阻塞直到服务器完成绑定,
             * 然后服务器等待通道关闭,因为使用 sync(),所以关闭操作也会被阻塞。
             * 现在你可以关闭EventLoopGroup 和释放所有资源,包括创建的线程。
             * */
            ChannelFuture f = b.bind().sync();
            System.out.println(EchoServer.class.getName() + "started and listen on “" + f.channel().localAddress());
            f.channel().closeFuture().sync();
        } finally {
            group.shutdownGracefully().sync();
        }
    }

    public static void main(String[] args) throws Exception {
        new EchoServer(65535).start();
    }
}
package com.cyq.server;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;

public class EchoServerHandler extends ChannelHandlerAdapter{

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("Server received: " + msg);
        ctx.write(msg);
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)throws Exception {
        cause.printStackTrace();
        ctx.close();
    }

}

客户端

package com.cyq.client;
import java.net.InetSocketAddress;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;

/**
 * @author cyq
 * 创建 Bootstrap 对象用来引导启动客户端
 创建 EventLoopGroup 对象并设置到 Bootstrap 中,EventLoopGroup 可以理解为是一个线程池,这个线程池用来处理连接、接受数据、发送数据
 创建 InetSocketAddress 并设置到 Bootstrap 中,InetSocketAddress 是指定连接的服务器地址
 添加一个 ChannelHandler,客户端成功连接服务器后就会被执行
 调用 Bootstrap.connect()来连接服务器
 最后关闭 EventLoopGroup 来释放资源
 */
public class EchoClient {

    private final String host;
    private final int port;

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

    public void start() throws Exception {
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            Bootstrap b = new Bootstrap();
            b.group(group).channel(NioSocketChannel.class).remoteAddress(
                    new InetSocketAddress(host, port)).
                     handler(new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(SocketChannel ch) throws Exception {
                    ch.pipeline().addLast(new EchoClientHandler());
                }
            });
            ChannelFuture f = b.connect().sync();
            f.channel().closeFuture().sync();
        } finally {
            group.shutdownGracefully().sync();
        }
    }
    public static void main(String[] args) throws Exception {
        new EchoClient("localhost", 65535).start();
    }
}
package com.cyq.client;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.util.CharsetUtil;

public class EchoClientHandler extends SimpleChannelInboundHandler<ByteBuf>
{

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        ctx.writeAndFlush(Unpooled.copiedBuffer("Netty rocks!",CharsetUtil.UTF_8));
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
            throws Exception {
        cause.printStackTrace();
        ctx.close();
    }

    @Override
    protected void messageReceived(ChannelHandlerContext arg0, ByteBuf msg) throws Exception {
        // TODO Auto-generated method stub
        System.out.println("Client received: " + ByteBufUtil.hexDump(msg.readBytes(msg.readableBytes())));
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值