Netty学习:搭建一个简单的Netty服务

Netty学习:搭建一个简单的Netty服务

Netty 是一个基于 JAVA NIO 类库的异步通信框架,它的架构特点是:异步非阻塞、基于事件驱动、高性能、高可靠性和高可定制性。换句话说,Netty是一个NIO框架,使用它可以简单快速地开发网络应用程序,比如客户端和服务端的协议。Netty大大简化了网络程序的开发过程比如TCP和UDP的 Socket的开发。Netty 已逐渐成为 Java NIO 编程的首选框架。

项目官方地址:http://netty.io/index.html

一. Netty 的优点:

  • API 使用简单,开发门槛低;
  • 功能强大,预置了多种编解码功能,支持多种主流协议;
  • 定制能力强,可以通过 ChannelHandler 对通信框架进行灵活的扩展;
  • 性能高,通过与其它业界主流的 NIO 框架对比,Netty 的综合性能最优;
  • 社区活跃,版本迭代周期短,发现的 BUG 可以被及时修复,同时,更多的新功能会被加入;
  • 经历了大规模的商业应用考验,质量得到验证。在互联网、大数据、网络游戏、企业应用、电信软件等众多行业得到成功商用,证明了它完全满足不同行业的商用标准。

二. 搭建Netty服务:

  1. 添加pom依赖
    <dependency>
    	<groupId>io.netty</groupId>
    	<artifactId>netty-all</artifactId>
    	<version>4.1.0.Final</version>
    </dependency>
     
  2. SimpleServer(服务端)
    package com.yingjun.netty.server;
    
    import io.netty.bootstrap.ServerBootstrap;
    import io.netty.channel.ChannelFuture;
    import io.netty.channel.ChannelInitializer;
    import io.netty.channel.ChannelOption;
    import io.netty.channel.EventLoopGroup;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.channel.socket.SocketChannel;
    import io.netty.channel.socket.nio.NioServerSocketChannel;
    
    /**
     * 
     * Netty中,通讯的双方建立连接后,会把数据按照ByteBuf的方式进行传输,
     * 例如http协议中,就是通过HttpRequestDecoder对ByteBuf数据流进行处理,转换成http的对象。
     * 
     */
    public class SimpleServer {
    	private int port;
    
    	public SimpleServer(int port) {
    		this.port = port;
    	}
    
    	public void run() throws Exception {
    		//EventLoopGroup是用来处理IO操作的多线程事件循环器
    		//bossGroup 用来接收进来的连接
    		EventLoopGroup bossGroup = new NioEventLoopGroup(); 
    		//workerGroup 用来处理已经被接收的连接
    		EventLoopGroup workerGroup = new NioEventLoopGroup();
    		try {
    			//启动 NIO 服务的辅助启动类
    			ServerBootstrap b = new ServerBootstrap(); 
    			b.group(bossGroup, workerGroup)
    				//配置 Channel
    				.channel(NioServerSocketChannel.class)
    				.childHandler(new ChannelInitializer<SocketChannel>() { 
    						@Override
    						public void initChannel(SocketChannel ch) throws Exception {
    							// 注册handler  
    							ch.pipeline().addLast(new SimpleServerHandler());
    						}
    					})
    				.option(ChannelOption.SO_BACKLOG, 128) 
    				.childOption(ChannelOption.SO_KEEPALIVE, true); 
    
    			// 绑定端口,开始接收进来的连接
    			ChannelFuture f = b.bind(port).sync();
    			// 等待服务器 socket 关闭 。
    			f.channel().closeFuture().sync();
    		} finally {
    			workerGroup.shutdownGracefully();
    			bossGroup.shutdownGracefully();
    		}
    	}
    	
    	public static void main(String[] args) throws Exception {
            new SimpleServer(9999).run();
        }
    }
     
  3. SimpleServerHandler(服务端请求处理Handler)
    package com.yingjun.netty.server;
    
    import io.netty.buffer.ByteBuf;
    import io.netty.channel.ChannelHandlerContext;
    import io.netty.channel.ChannelInboundHandlerAdapter;
    
    public class SimpleServerHandler extends ChannelInboundHandlerAdapter {
    
    	@Override
    	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    		System.out.println("SimpleServerHandler.channelRead");
    		ByteBuf result = (ByteBuf) msg;
    		byte[] result1 = new byte[result.readableBytes()];
    		// msg中存储的是ByteBuf类型的数据,把数据读取到byte[]中
    		result.readBytes(result1);
    		String resultStr = new String(result1);
    		// 接收并打印客户端的信息
    		System.out.println("Client said:" + resultStr);
    		// 释放资源,这行很关键
    		result.release();
    
    		// 向客户端发送消息
    		String response = "hello client!";
    		// 在当前场景下,发送的数据必须转换成ByteBuf数组
    		ByteBuf encoded = ctx.alloc().buffer(4 * response.length());
    		encoded.writeBytes(response.getBytes());
    		ctx.write(encoded);
    		ctx.flush();
    	}
    
    	@Override
    	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
    		// 当出现异常就关闭连接
    		cause.printStackTrace();
    		ctx.close();
    	}
    
    	@Override
    	public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
    		ctx.flush();
    	}
    
    }
     
  4. SimpleServer(客户端)
    package com.yingjun.netty.server;
    
    import io.netty.bootstrap.Bootstrap;
    import io.netty.bootstrap.ServerBootstrap;
    import io.netty.channel.ChannelFuture;
    import io.netty.channel.ChannelInitializer;
    import io.netty.channel.ChannelOption;
    import io.netty.channel.EventLoopGroup;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.channel.socket.SocketChannel;
    import io.netty.channel.socket.nio.NioServerSocketChannel;
    import io.netty.channel.socket.nio.NioSocketChannel;
    
    public class SimpleClient {
    	
    	public void connect(String host, int port) throws Exception {
    		EventLoopGroup workerGroup = new NioEventLoopGroup();
    
    		try {
    			Bootstrap b = new Bootstrap();
    			b.group(workerGroup);
    			b.channel(NioSocketChannel.class);
    			b.option(ChannelOption.SO_KEEPALIVE, true);
    			b.handler(new ChannelInitializer<SocketChannel>() {
    				@Override
    				public void initChannel(SocketChannel ch) throws Exception {
    					ch.pipeline().addLast(new SimpleClientHandler());
    				}
    			});
    
    			// Start the client.
    			ChannelFuture f = b.connect(host, port).sync();
    
    			// Wait until the connection is closed.
    			f.channel().closeFuture().sync();
    		} finally {
    			workerGroup.shutdownGracefully();
    		}
    	}
    	
    	public static void main(String[] args) throws Exception {
    		SimpleClient client=new SimpleClient();
    		client.connect("127.0.0.1", 9999);
    	}
    	
    }
     
  5. SimpleServerHandler(客户端请求处理Handler)
    package com.yingjun.netty.server;
    
    import io.netty.buffer.ByteBuf;
    import io.netty.channel.ChannelHandlerContext;
    import io.netty.channel.ChannelInboundHandlerAdapter;
    
    public class SimpleClientHandler extends ChannelInboundHandlerAdapter {
    
    	@Override
    	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    		System.out.println("SimpleClientHandler.channelRead");  
            ByteBuf result = (ByteBuf) msg;  
            byte[] result1 = new byte[result.readableBytes()];  
            result.readBytes(result1);  
            System.out.println("Server said:" + new String(result1));  
            result.release();  
    	}
    
    	@Override
    	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
    		// 当出现异常就关闭连接
    		cause.printStackTrace();
    		ctx.close();
    	}
    
    	
    	// 连接成功后,向server发送消息  
        @Override  
        public void channelActive(ChannelHandlerContext ctx) throws Exception {  
        	String msg = "hello Server!";  
            ByteBuf encoded = ctx.alloc().buffer(4 * msg.length());  
            encoded.writeBytes(msg.getBytes());  
            ctx.write(encoded);  
            ctx.flush();  
        }  
    }
     
  6. 运行结果:

    SimpleClientHandler.channelRead
    Server said:hello client!
    ------------------------------------------
    SimpleServerHandler.channelRead
    Client said:hello Server!
    SimpleServerHandler.channelRead
    Client said:hello Server!
     

相关推荐