1. 程式人生 > >[轉]Netty入門(最簡單的Netty客戶端/服務器程序)

[轉]Netty入門(最簡單的Netty客戶端/服務器程序)

serve exc new final 綁定 title graceful 關閉連接 listener

 Java中的NIO是一種解決阻塞式IO問題的基本技術,但是NIO的編寫對java程序員是有比較高的要求的。那麽Netty就是一種簡化操作的一個成熟的網絡IO編程框架。這裏簡單介紹一個程序,代碼是《netty in action》裏面的,不過那個裏面的實例有點問題,反正我沒有跑成功,修改後成功。直接上代碼:


一、服務器編寫

  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 }
技術分享圖片

  具體的處理客戶端連接的代碼

技術分享圖片
 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 }
技術分享圖片

二、客戶端編寫

  具體的連接代碼

技術分享圖片
 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 }
技術分享圖片

三、結果

  先運行server,在運行client即可。

技術分享圖片

技術分享圖片

轉載鏈接:http://www.cnblogs.com/liuming1992/p/4758532.html

以上netty使用的版本

<!-- https://mvnrepository.com/artifact/io.netty/netty-all -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.6.Final</version>
</dependency>

[轉]Netty入門(最簡單的Netty客戶端/服務器程序)