Netty框架的基本使用

来源:互联网 发布:淘宝祖国版手办 编辑:程序博客网 时间:2024/06/02 02:36

    Java在1.4之前,使用的都是传统的io进行操作的,基于此的socket的通信也是阻塞的;当服务端启动后,需要等待客户端发送过来一个数据才能进行后续操作;此情况下,当有大量的客户端发送请求时,会产生大量的线程,给服务器造成过大的压力。故而在Java 1.4之后引入了一个新的API——Java NIO

    

 NIO与原来的IO有同样的作用和目的,但是使用的方式完全不同,NIO支持面向缓冲区的、基于通道的IO操作。NIO将以更加高效的方式进行文件的读写操作。
 IO与NIO的区别

IO

NIO                            面向流                               面向缓冲区                            阻塞IO                                 非阻塞IO                            基于流                                 基于通道                               无                                  选择器    

 NIO会向当前系统内核注册一个监听器,在客户端消息未发来之前,服务器可以处理其他事物,只有当消息过来时才会触发监听器,服务端开始处理消息。这样一来服务器就可以不用一直处于阻塞状态等待客户端的消息。

  现在开始说下封装了NIO连接内核注册监听器的操作的,只需要我们写业务代码的框架Netty

  1.下载netty包,下载地址http://netty.io/

   2.服务端

package netty.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;/** * • 配置服务器功能,如线程、端口 • 实现服务器处理程序,它包含业务逻辑,决定当有一个请求连接或接收数据时该做什么 * @author wb-jlh258576 * */public class EchoServer {private final int port;public EchoServer(int port) {this.port = port;}public void start() throws Exception{ServerBootstrap serverBootstrap = new ServerBootstrap();EventLoopGroup eventLoopGroup = new NioEventLoopGroup();serverBootstrap.group(eventLoopGroup)   .channel(NioServerSocketChannel.class)   .localAddress("localhost", port)   .childHandler(new ChannelInitializer<Channel>() {@Overrideprotected void initChannel(Channel ch) throws Exception {// TODO Auto-generated method stubch.pipeline().addLast(new EchoServerHandler());}});// 最后绑定服务器等待直到绑定完成,调用sync()方法会阻塞直到服务器完成绑定,然后服务器等待通道关闭,因为使用sync(),所以关闭操作也会被阻塞。try {ChannelFuture channelFuture = serverBootstrap.bind().sync();System.out.println("开始监听,端口为:" + channelFuture.channel().localAddress());channelFuture.channel().closeFuture().sync();} catch (InterruptedException e) {e.printStackTrace();}finally{eventLoopGroup.shutdownGracefully().sync();}}public static void main(String[] args) throws Exception {new EchoServer(8888).start();}}
3.服务端处理业务类

package netty.server;import java.util.Date;import io.netty.buffer.ByteBuf;import io.netty.buffer.Unpooled;import io.netty.channel.ChannelHandlerContext;import io.netty.channel.ChannelInboundHandlerAdapter;public class EchoServerHandler extends ChannelInboundHandlerAdapter {@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {System.out.println("server 开始读取数据。。。");ByteBuf buf = (ByteBuf)msg;byte[] req = new byte[buf.readableBytes()];buf.readBytes(req);String body = new String(req, "UTF-8");System.out.println("接收客户端数据:" + body);//向客户端发送数据System.out.println("server向client发送数据。。。");String currentTime = new Date(System.currentTimeMillis()).toString();System.out.println("服务端当前的时间:"+currentTime);        ByteBuf resp = Unpooled.copiedBuffer(currentTime.getBytes());        ctx.write(resp);}@Overridepublic void channelReadComplete(ChannelHandlerContext ctx) throws Exception {// TODO Auto-generated method stubSystem.out.println("server 数据处理完毕");ctx.flush();}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {// TODO Auto-generated method stubcause.printStackTrace();ctx.close();}}


4.客户端启动类

package netty.client;import io.netty.bootstrap.Bootstrap;import io.netty.bootstrap.ServerBootstrap;import io.netty.channel.Channel;import io.netty.channel.ChannelFuture;import io.netty.channel.ChannelHandler;import io.netty.channel.ChannelHandlerContext;import io.netty.channel.ChannelInitializer;import io.netty.channel.EventLoopGroup;import io.netty.channel.nio.NioEventLoopGroup;import io.netty.channel.socket.nio.NioServerSocketChannel;import io.netty.channel.socket.nio.NioSocketChannel;import netty.server.EchoServer;import netty.server.EchoServerHandler;public class EchoClient {private final int port;public EchoClient(int port) {this.port = port;}public void start() throws Exception{// 客户端引导类Bootstrap bootstrap = new Bootstrap();EventLoopGroup eventLoopGroup = new NioEventLoopGroup();bootstrap.group(eventLoopGroup)   .channel(NioSocketChannel.class)   .remoteAddress("localhost", port)   .handler(new ChannelInitializer<Channel>() {@Overrideprotected void initChannel(Channel ch) throws Exception {// TODO Auto-generated method stubch.pipeline().addLast(new EchoClientHandler());}});// 链接服务器try {ChannelFuture channelFuture = bootstrap.connect().sync();channelFuture.channel().closeFuture().sync();} catch (InterruptedException e) {e.printStackTrace();}finally{eventLoopGroup.shutdownGracefully().sync();}}public static void main(String[] args) throws Exception {new EchoClient(8888).start();}}

5.客户端处理业务类(回调)

package netty.client;import io.netty.buffer.ByteBuf;import io.netty.buffer.Unpooled;import io.netty.channel.ChannelHandler;import io.netty.channel.ChannelHandlerContext;import io.netty.channel.SimpleChannelInboundHandler;public class EchoClientHandler extends SimpleChannelInboundHandler<ByteBuf> {@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {System.out.println("客户端连接服务器,开始发送数据……");byte[] req = "请求当前服务端时间".getBytes();//消息ByteBuf buffer = Unpooled.buffer(req.length);buffer.writeBytes(req);ctx.writeAndFlush(buffer);}@Overrideprotected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {// TODO Auto-generated method stubSystem.out.println("client 读取server数据..");// 服务端返回消息后ByteBuf buf = (ByteBuf) msg;byte[] req = new byte[buf.readableBytes()];buf.readBytes(req);String body = new String(req, "UTF-8");System.out.println("服务端当前时间 :" + body);}}


最后服务端的输出结果为
server 开始读取数据。。。接收客户端数据:请求当前服务端时间server向client发送数据。。。服务端当前的时间:Thu Jul 20 14:45:00 CST 2017server 数据处理完毕

客户端的输出结果

客户端连接服务器,开始发送数据……client 读取server数据..服务端当前时间 :Thu Jul 20 14:45:00 CST 2017

值得一提的是,当服务端注册了多个handler时,如果是InboundHandler,执行顺序为注册顺序;如果是OutboundHandler,执行顺序为注册顺序的逆序,且必须有一个InboundHandler在最后注册



 

原创粉丝点击