[Netty] - Netty入门(最简单的Netty客户端/服务器程序)

  Java中的NIO是一种解决阻塞式IO问题的基本技术,可是NIO的编写对java程序员是有比较高的要求的。那么Netty就是一种简化操做的一个成熟的网络IO编程框架。这里简单介绍一个程序,代码是《netty in action》里面的,不过那个里面的实例有点问题,反正我没有跑成功,修改后成功。直接上代码:java


 1、服务器编写程序员

  Server代码,监听链接编程

 1 package com.gerry.netty.server;
 2 
 3 import io.netty.bootstrap.ServerBootstrap;
 4 import io.netty.channel.ChannelFuture;
 5 import io.netty.channel.ChannelInitializer;
 6 import io.netty.channel.EventLoopGroup;
 7 import io.netty.channel.nio.NioEventLoopGroup;
 8 import io.netty.channel.socket.SocketChannel;
 9 import io.netty.channel.socket.nio.NioServerSocketChannel;
10 
11 public class EchoServer {
12     private final int port;
13 
14     public EchoServer(int port) {
15         this.port = port;
16     }
17 
18     public void start() throws Exception {
19         EventLoopGroup group = new NioEventLoopGroup();
20         try {
21             ServerBootstrap sb = new ServerBootstrap();
22             sb.group(group) // 绑定线程池
23                     .channel(NioServerSocketChannel.class) // 指定使用的channel
24                     .localAddress(this.port)// 绑定监听端口
25                     .childHandler(new ChannelInitializer<SocketChannel>() { // 绑定客户端链接时候触发操做
26 
27                                 @Override
28                                 protected void initChannel(SocketChannel ch) throws Exception {
29                                     System.out.println("connected...; Client:" + ch.remoteAddress());
30                                     ch.pipeline().addLast(new EchoServerHandler()); // 客户端触发操做
31                                 }
32                             });
33             ChannelFuture cf = sb.bind().sync(); // 服务器异步建立绑定
34             System.out.println(EchoServer.class + " started and listen on " + cf.channel().localAddress());
35             cf.channel().closeFuture().sync(); // 关闭服务器通道
36         } finally {
37             group.shutdownGracefully().sync(); // 释放线程池资源
38         }
39     }
40 
41     public static void main(String[] args) throws Exception {
42         new EchoServer(65535).start(); // 启动
43     }
44 }

   具体的处理客户端链接的代码bootstrap

 1 package com.gerry.netty.server;
 2 
 3 import io.netty.buffer.Unpooled;
 4 import io.netty.channel.ChannelFutureListener;
 5 import io.netty.channel.ChannelHandlerContext;
 6 import io.netty.channel.ChannelInboundHandlerAdapter;
 7 
 8 public class EchoServerHandler extends ChannelInboundHandlerAdapter {
 9     @Override
10     public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
11         System.out.println("server channelRead...; received:" + msg);
12         ctx.write(msg);
13     }
14 
15     @Override
16     public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
17         System.out.println("server channelReadComplete..");
18         // 第一种方法:写一个空的buf,并刷新写出区域。完成后关闭sock channel链接。
19         ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
20         //ctx.flush(); // 第二种方法:在client端关闭channel链接,这样的话,会触发两次channelReadComplete方法。
21         //ctx.flush().close().sync(); // 第三种:改为这种写法也能够,可是这中写法,没有第一种方法的好。
22     }
23 
24     @Override
25     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
26         System.out.println("server occur exception:" + cause.getMessage());
27         cause.printStackTrace();
28         ctx.close(); // 关闭发生异常的链接
29     }
30 }

 

 2、客户端编写服务器

  具体的链接代码网络

 1 package com.gerry.netty.client;
 2 
 3 import io.netty.bootstrap.Bootstrap;
 4 import io.netty.channel.ChannelFuture;
 5 import io.netty.channel.ChannelInitializer;
 6 import io.netty.channel.EventLoopGroup;
 7 import io.netty.channel.nio.NioEventLoopGroup;
 8 import io.netty.channel.socket.SocketChannel;
 9 import io.netty.channel.socket.nio.NioSocketChannel;
10 
11 import java.net.InetSocketAddress;
12 
13 public class EchoClient {
14     private final String host;
15     private final int port;
16 
17     public EchoClient() {
18         this(0);
19     }
20 
21     public EchoClient(int port) {
22         this("localhost", port);
23     }
24 
25     public EchoClient(String host, int port) {
26         this.host = host;
27         this.port = port;
28     }
29 
30     public void start() throws Exception {
31         EventLoopGroup group = new NioEventLoopGroup();
32         try {
33             Bootstrap b = new Bootstrap();
34             b.group(group) // 注册线程池
35                     .channel(NioSocketChannel.class) // 使用NioSocketChannel来做为链接用的channel类
36                     .remoteAddress(new InetSocketAddress(this.host, this.port)) // 绑定链接端口和host信息
37                     .handler(new ChannelInitializer<SocketChannel>() { // 绑定链接初始化器
38                                 @Override
39                                 protected void initChannel(SocketChannel ch) throws Exception {
40                                     System.out.println("connected...");
41                                     ch.pipeline().addLast(new EchoClientHandler());
42                                 }
43                             });
44             System.out.println("created..");
45 
46             ChannelFuture cf = b.connect().sync(); // 异步链接服务器
47             System.out.println("connected..."); // 链接完成
48 
49             cf.channel().closeFuture().sync(); // 异步等待关闭链接channel
50             System.out.println("closed.."); // 关闭完成
51         } finally {
52             group.shutdownGracefully().sync(); // 释放线程池资源
53         }
54     }
55 
56     public static void main(String[] args) throws Exception {
57         new EchoClient("127.0.0.1", 65535).start(); // 链接127.0.0.1/65535,并启动
58     }
59 }

  链接成功后,具体的通讯代码框架

 1 package com.gerry.netty.client;
 2 
 3 import java.nio.charset.Charset;
 4 
 5 import io.netty.buffer.ByteBuf;
 6 import io.netty.buffer.ByteBufUtil;
 7 import io.netty.buffer.Unpooled;
 8 import io.netty.channel.ChannelHandlerContext;
 9 import io.netty.channel.SimpleChannelInboundHandler;
10 import io.netty.util.CharsetUtil;
11 
12 public class EchoClientHandler extends SimpleChannelInboundHandler<ByteBuf> {
13 
14     @Override
15     public void channelActive(ChannelHandlerContext ctx) throws Exception {
16         System.out.println("client channelActive..");
17         ctx.writeAndFlush(Unpooled.copiedBuffer("Netty rocks!", CharsetUtil.UTF_8)); // 必须有flush
18 
19         // 必须存在flush
20         // ctx.write(Unpooled.copiedBuffer("Netty rocks!", CharsetUtil.UTF_8));
21         // ctx.flush();
22     }
23 
24     @Override
25     protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
26         System.out.println("client channelRead..");
27         ByteBuf buf = msg.readBytes(msg.readableBytes());
28         System.out.println("Client received:" + ByteBufUtil.hexDump(buf) + "; The value is:" + buf.toString(Charset.forName("utf-8")));
29         //ctx.channel().close().sync();// client关闭channel链接
30     }
31 
32     @Override
33     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
34         cause.printStackTrace();
35         ctx.close();
36     }
37 
38 }

 

 3、结果异步

  先运行server,在运行client便可。socket