Netty是业界最流行的NIO框架之一,它的健壮性、功能、性能、可定制性和可扩展性在同类框架中都是首屈一指的,它已经得到成百上千的商用项目验证,例如Hadoop的RPC框架avro使用Netty作为底层通信框架。很多其它业界主流的RPC框架,也使用Netty来构建高性能的异步通信能力。
通过对Netty的分析,我们将它的优点总结如下:
1) API使用简单,开发门槛低;
2) 功能强大,预置了多种编解码功能,支持多种主流协议;
3) 定制能力强,可以通过ChannelHandler对通信框架进行灵活的扩展;
4) 性能高,通过与其它业界主流的NIO框架对比,Netty的综合性能最优;
5) 成熟、稳定,Netty修复了已经发现的所有JDK NIO BUG,业务开发人员不需要再为NIO的BUG而烦恼;
6) 社区活跃,版本迭代周期短,发现的BUG可以被及时修复,同时,更多的新功能会被加入;
7) 经历了大规模的商业应用考验,质量已经得到验证。在互联网、大数据、网络游戏、企业应用、电信软件等众多行业得到成功商用,证明了它可以完全满足不同行业的商业应用。
正是因为这些优点,Netty逐渐成为Java NIO编程的首选框架。
接下来看一个demo
1、用到的jar
配置文件 config.properties
- #netty 服务端ip
- nioServerIp=127.0.0.1
- #netty 服务端端口
- nioServerPort=19990
2.服务段代码:
- package netty.test;
- import java.io.InputStream;
- import java.util.Properties;
- /** properties文件加载类
- * @author xiefg
- *
- */
- public class Configuration {
- private static Properties SYSTEM_CONFIG = new Properties();
- public static String fileName = "";
- private static final String PATH_SERVER_CONF = "netty/config/config.properties";
- public static void init() {
- try {
- InputStream inputStream = null;
- ClassLoader classLoader = null;
- classLoader = Thread.currentThread().getContextClassLoader();
- inputStream = classLoader.getResourceAsStream(PATH_SERVER_CONF);
- SYSTEM_CONFIG.load(inputStream);
- fileName = "";
- int index = PATH_SERVER_CONF.lastIndexOf("/") == -1 ? PATH_SERVER_CONF
- .lastIndexOf("\\") : PATH_SERVER_CONF.lastIndexOf("/");
- if (index > 0) {
- fileName = PATH_SERVER_CONF.substring(index + 1);
- }
- inputStream.close();
- } catch (Exception e) {
- e.printStackTrace();
- }
- return;
- }
- public static String getProperty(String key, String defaultValue) {
- try {
- return SYSTEM_CONFIG.getProperty(key, defaultValue);
- } catch (Exception e) {
- return null;
- }
- }
- public static String getProperty(String key) {
- try {
- String value = SYSTEM_CONFIG.getProperty(key);
- return value;
- } catch (Exception e) {
- return null;
- }
- }
- public static void main(String[] args) {
- init();
- System.out.println(Configuration.getProperty("nioServerIp"));
- }
- }
- package netty.test;
- import io.netty.bootstrap.ServerBootstrap;
- import io.netty.channel.Channel;
- import io.netty.channel.ChannelFuture;
- import io.netty.channel.ChannelInitializer;
- import io.netty.channel.ChannelPipeline;
- import io.netty.channel.EventLoopGroup;
- import io.netty.channel.nio.NioEventLoopGroup;
- import io.netty.channel.socket.nio.NioServerSocketChannel;
- import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
- import io.netty.handler.codec.LengthFieldPrepender;
- import io.netty.handler.codec.string.StringDecoder;
- import io.netty.handler.codec.string.StringEncoder;
- import io.netty.util.CharsetUtil;
- /***
- *
- * @ClassName: NettyServer
- * @Description: TODO netty 提供服务
- * @author xiefg
- * @date 2016年8月4日 下午5:02:05
- *
- */
- public class NettyServer {
- //ip 地址
- private static String IP = "127.0.0.1";
- //默认端口
- private static int PORT = 5656;
- private static final int BIZGROUPSIZE = Runtime.getRuntime().availableProcessors()*2;
- private static final int BIZTHREADSIZE = 100;
- private static final EventLoopGroup bossGroup = new NioEventLoopGroup(BIZGROUPSIZE);
- private static final EventLoopGroup workerGroup = new NioEventLoopGroup(BIZTHREADSIZE);
- public static void init() throws Exception {
- ServerBootstrap bootstrap = new ServerBootstrap();
- bootstrap.group(bossGroup, workerGroup);
- bootstrap.channel(NioServerSocketChannel.class);
- bootstrap.childHandler(new ChannelInitializer<Channel>() {
- @Override
- protected void initChannel(Channel ch) throws Exception {
- // TODO Auto-generated method stub
- ChannelPipeline pipeline = ch.pipeline();
- pipeline.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4));
- pipeline.addLast(new LengthFieldPrepender(4));
- pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));
- pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8));
- pipeline.addLast(new ServerHandler());
- }
- });
- IP =Configuration.getProperty("nioServerIp");
- PORT=Integer.parseInt(Configuration.getProperty("nioServerPort"));
- System.out.println("【TCP服务器IP】"+IP+"【TCP服务器PORT】"+PORT);
- ChannelFuture f = bootstrap.bind(IP, PORT).sync();
- f.channel().closeFuture().sync();
- System.out.println("TCP服务器已启动");
- }
- protected static void shutdown() {
- workerGroup.shutdownGracefully();
- bossGroup.shutdownGracefully();
- }
- public static void main(String[] args) throws Exception {
- System.out.println("初始化配置文件...");
- Configuration.init();
- System.out.println("开始启动TCP服务器...");
- NettyServer.init();
- // HelloServer.shutdown();
- }
- }
- package netty.test;
- import io.netty.channel.ChannelHandlerContext;
- import io.netty.channel.ChannelInboundHandlerAdapter;
- /**
- *
- * @ClassName: ServerHandler
- * @Description: TODO
- * @author xiefg
- * @date 2016年8月4日 下午5:34:19
- *
- */
- public class ServerHandler extends ChannelInboundHandlerAdapter {
- @Override
- public void channelRead(ChannelHandlerContext ctx, Object msg)
- throws Exception {
- System.out.println("server receive message :"+ msg);
- ctx.channel().writeAndFlush("yes server already accept your message" + msg);
- ctx.close();
- }
- @Override
- public void channelActive(ChannelHandlerContext ctx) throws Exception {
- // TODO Auto-generated method stub
- System.out.println("【channelActive】。。。");
- }
- @Override
- public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
- System.out.println("【exception is general】");
- }
- }
- package netty.test;
- import io.netty.bootstrap.Bootstrap;
- import io.netty.channel.ChannelFuture;
- import io.netty.channel.ChannelInitializer;
- import io.netty.channel.ChannelOption;
- import io.netty.channel.ChannelPipeline;
- import io.netty.channel.EventLoopGroup;
- import io.netty.channel.nio.NioEventLoopGroup;
- import io.netty.channel.socket.SocketChannel;
- import io.netty.channel.socket.nio.NioSocketChannel;
- import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
- import io.netty.handler.codec.LengthFieldPrepender;
- import io.netty.handler.codec.string.StringDecoder;
- import io.netty.handler.codec.string.StringEncoder;
- import io.netty.util.CharsetUtil;
- /**
- *
- * @ClassName: NettyClient
- * @Description: TODO
- * @author xiefg
- * @date 2016年8月4日 下午5:46:43
- *
- */
- public class NettyClient implements Runnable {
- @Override
- public void run() {
- EventLoopGroup group = new NioEventLoopGroup();
- try {
- Bootstrap b = new Bootstrap();
- b.group(group);
- b.channel(NioSocketChannel.class).option(ChannelOption.TCP_NODELAY, true);
- b.handler(new ChannelInitializer<SocketChannel>() {
- @Override
- protected void initChannel(SocketChannel ch) throws Exception {
- ChannelPipeline pipeline = ch.pipeline();
- pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4));
- pipeline.addLast("frameEncoder", new LengthFieldPrepender(4));
- pipeline.addLast("decoder", new StringDecoder(CharsetUtil.UTF_8));
- pipeline.addLast("encoder", new StringEncoder(CharsetUtil.UTF_8));
- pipeline.addLast("handler", new Client());
- }
- });
- ChannelFuture f = b.connect("127.0.0.1", 19990).sync();
- f.channel().writeAndFlush("Netty Hello Service!"+Thread.currentThread().getName()+":--->:"+Thread.currentThread().getId());
- f.channel().closeFuture().sync();
- } catch (Exception e) {
- } finally {
- group.shutdownGracefully();
- }
- }
- public static void main(String[] args) throws Exception {
- for (int i = 0; i < 10; i++) {
- new Thread(new NettyClient(),"【this thread】 "+i).start();
- }
- }
- }
- package netty.test;
- import io.netty.channel.ChannelHandlerContext;
- import io.netty.channel.ChannelInboundHandlerAdapter;
- /**
- *
- * @ClassName: Client
- * @Description: TODO
- * @author xiefg
- * @date 2016年8月4日 下午6:18:08
- *
- */
- public class Client extends ChannelInboundHandlerAdapter {
- @Override
- public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
- System.out.println("【client接收到服务器返回的消息】:" + msg);
- }
- @Override
- public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
- System.out.println("【client exception is general】");
- }
- }
启动服务端如下图:
服务端接收消息如下图