Netty入门(一)-- 客户端示例
前言
本文主要实现基于Netty实现客户端,向服务器定时发送数据
如下为一个简单的Netty实例,本实例主要描述了Client向服务端定时发送数据,并实现重连机制及轮询发送数据
先直接上代码,后续在整理一些用法相关知识
例子中如有误,欢迎各位指正
1、pom.xml
1 <dependency> 2 <groupId>io.netty</groupId> 3 <artifactId>netty-all</artifactId> 4 <version>4.1.36.Final</version> 5 </dependency>
2、NettyClient.java:主要为初始化Client Socket
1 import io.netty.bootstrap.Bootstrap; 2 import io.netty.channel.*; 3 import io.netty.channel.nio.NioEventLoopGroup; 4 import io.netty.channel.socket.nio.NioSocketChannel; 5 import io.netty.handler.codec.string.StringDecoder; 6 import io.netty.handler.codec.string.StringEncoder; 7 import io.netty.util.CharsetUtil; 8 9 10 public class NettyClientTest implements Runnable{ 11 12 private static volatile EventLoopGroup workerGroup; 13 14 private String ip; 15 16 private int port; 17 18 public NettyClientTest(String ip, int port) { 19 this.ip = ip; 20 this.port = port; 21 } 22 23 @Override 24 public void run() { 25 // 客户端的配置 26 workerGroup= new NioEventLoopGroup(); 27 try { 28 Bootstrap bootstrap = new Bootstrap(); 29 bootstrap.group(workerGroup) 30 .channel(NioSocketChannel.class) 31 .option(ChannelOption.TCP_NODELAY, true) 32 .handler(new ChannelInitializer() { 33 @Override 34 protected void initChannel(Channel channel) throws Exception { 35 ChannelPipeline p = channel.pipeline(); 36 //编码格式 37 p.addLast("decoder", new StringDecoder(CharsetUtil.UTF_8)) 38 .addLast("encoder", new StringEncoder(CharsetUtil.UTF_8)) 39 //具体的客户端实现操作类 40 .addLast(new NettyClientHandlerTest(bootstrap, ip, port)); 41 } 42 }); 43 44 ChannelFuture future = null; 45 /** 46 *防止初次链接不上 每隔十秒重连一次 47 */ 48 while (future == null || !future.isSuccess()) { 49 try { 50 future = bootstrap.connect(ip, port).sync(); 51 } catch (Exception ex) { 52 System.out.println("重连中。。。。"); 53 Thread.sleep(10000); 54 } 55 } 56 57 58 future.channel().closeFuture().sync(); 59 } catch (InterruptedException e) { 60 e.printStackTrace(); 61 } finally { 62 //workerGroup.shutdownGracefully(); 63 } 64 } 65 66 67 68 public static void main(String[] args) { 69 70 //开启单条条线程,每条线程就相当于一个客户端 71 new NettyClientTest("localhost",10002).run(); 72 } 73 }
3、NettyClientHandlerTest.java:配合NettyClient,完成消息的读取操作以及业务处理。
1 import io.netty.bootstrap.Bootstrap; 2 import io.netty.channel.*; 3 import java.net.InetSocketAddress; 4 import java.util.concurrent.TimeUnit; 5 6 7 8 public class NettyClientHandlerTest extends ChannelInboundHandlerAdapter{ 9 10 /** 11 * 12 */ 13 private final Bootstrap bootstrap; 14 15 /** 16 * 交互channel 17 */ 18 private static Channel channel; 19 20 /** 21 * 服务端ip 重连时使用 22 */ 23 private String ip; 24 25 /** 26 * 服务端端口 27 */ 28 private int port; 29 30 31 /** 32 * 断线重连等待时间 /S 33 */ 34 private final static int reconnectDelay = 10; 35 36 public NettyClientHandlerTest(Bootstrap bootstrap, String ip, int port) { 37 this.bootstrap = bootstrap; 38 this.ip = ip; 39 this.port = port; 40 } 41 42 /** 43 * 客户端连接服务器后被调用 44 * @param ctx 45 */ 46 @Override 47 public void channelActive(ChannelHandlerContext ctx) { 48 channel = ctx.channel(); 49 ctx.fireChannelActive(); 50 channelWrite(); 51 } 52 53 /** 54 * @param ctx 55 * @DESCRIPTION: 服务端端终止连接 后触发此函数 56 * @return: void 57 */ 58 @Override 59 public void channelInactive(ChannelHandlerContext ctx) { 60 61 ctx.fireChannelInactive(); 62 System.out.println("服务端终止了服务"); 63 try { 64 super.channelInactive(ctx); 65 } catch (Exception e) { 66 e.printStackTrace(); 67 } 68 //断开连接后实现重连机制 69 ctx.channel().eventLoop().schedule(() -> doConnect(), reconnectDelay, TimeUnit.SECONDS); 70 } 71 72 /** 73 * 每隔十秒重连一次 74 */ 75 private void doConnect() { 76 ChannelFuture future = bootstrap.connect(new InetSocketAddress(ip, port)); 77 future.addListener(new ChannelFutureListener() { 78 public void operationComplete(ChannelFuture f) throws Exception { 79 if (f.isSuccess()) { 80 System.out.println("Started Tcp Client: "); 81 } else { 82 System.out.println("Started Tcp Client Failed: "); 83 f.channel().eventLoop().schedule(() -> doConnect(), reconnectDelay, TimeUnit.SECONDS); 84 } 85 } 86 }); 87 } 88 89 /** 90 * 从服务器接收到数据后调用 91 * @param ctx 92 * @param msg 93 */ 94 @Override 95 public void channelRead(ChannelHandlerContext ctx, Object msg) { 96 97 System.out.println("回写数据:" + msg); 98 } 99 100 101 /** 102 * 发生异常时被调用 103 * @param ctx 104 * @param cause 105 */ 106 @Override 107 public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { 108 109 //cause.printStackTrace(); 110 System.out.println("服务端发生异常【" + cause.getMessage() + "】"); 111 ctx.close(); 112 } 113 114 /** 115 * 新启一个线程 轮询发送数据 116 * @DESCRIPTION: 客户端给服务端发送消息 117 * @return: void 118 */ 119 public void channelWrite() { 120 new Thread(new DataSendTest(channel)).start(); 121 } 122 }
4、DataSendTest.java:数据发送处理
1 import io.netty.buffer.ByteBuf; 2 import io.netty.buffer.Unpooled; 3 import io.netty.channel.Channel; 4 5 6 public class DataSendTest implements Runnable{ 7 8 /** 9 * 与服务端交互的通道 10 */ 11 private Channel channel; 12 13 public DataSendTest(Channel channel){ 14 this.channel = channel; 15 } 16 17 /** 18 * 轮询发送数据 19 */ 20 @Override 21 public void run() { 22 while (true) { 23 try{ 24 //channel通道关闭时 不发送数据 25 if (!channel.isActive()) { 26 break; 27 } 28 byte[] bytes = new byte[]{10,12,13}; 29 ByteBuf byteBuf = Unpooled.wrappedBuffer(bytes); 30 31 channel.write(byteBuf); 32 channel.flush(); 33 34 Thread.sleep(1000); 35 } catch (Exception ex) { 36 37 } 38 } 39 } 40 }