├── .github └── workflows │ └── maven.yml ├── .gitignore ├── Netty-heartbeat ├── .gitignore ├── pom.xml └── src │ ├── main │ └── java │ │ └── com │ │ └── pancm │ │ └── netty │ │ ├── App.java │ │ ├── client │ │ ├── NettyClient.java │ │ ├── NettyClientFilter.java │ │ ├── NettyClientHandler.java │ │ └── package-info.java │ │ └── server │ │ ├── NettyServer.java │ │ ├── NettyServerFilter.java │ │ ├── NettyServerHandler.java │ │ └── package-info.java │ └── test │ └── java │ └── com │ └── pancm │ └── netty │ └── AppTest.java ├── Netty-hello ├── .gitignore ├── pom.xml └── src │ ├── main │ └── java │ │ └── com │ │ └── pancm │ │ └── netty │ │ ├── App.java │ │ ├── client │ │ ├── NettyClient.java │ │ ├── NettyClientFilter.java │ │ ├── NettyClientHandler.java │ │ └── package-info.java │ │ └── server │ │ ├── NettyServer.java │ │ ├── NettyServerFilter.java │ │ ├── NettyServerHandler.java │ │ └── package-info.java │ └── test │ └── java │ └── com │ └── pancm │ └── netty │ └── AppTest.java ├── Netty-httpServer ├── .gitignore ├── pom.xml └── src │ ├── main │ └── java │ │ └── com │ │ └── pancm │ │ └── netty │ │ ├── App.java │ │ └── server │ │ ├── NettyServer.java │ │ ├── NettyServerFilter.java │ │ ├── NettyServerHandler.java │ │ └── package-info.java │ └── test │ └── java │ └── com │ └── pancm │ └── netty │ └── AppTest.java ├── Netty-protobuf ├── .gitignore ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── pancm │ ├── client │ ├── NettyClient.java │ ├── NettyClientApp.java │ ├── NettyClientFilter.java │ ├── NettyClientHandler.java │ └── package-info.java │ ├── protobuf │ ├── User.proto │ ├── UserInfo.java │ └── package-info.java │ └── server │ ├── NettyServer.java │ ├── NettyServerApp.java │ ├── NettyServerFilter.java │ ├── NettyServerHandler.java │ └── package-info.java ├── Netty-reconnect ├── .gitignore ├── pom.xml └── src │ ├── main │ └── java │ │ └── com │ │ └── pancm │ │ └── netty │ │ ├── App.java │ │ ├── client │ │ ├── NettyClient.java │ │ ├── NettyClientFilter.java │ │ ├── NettyClientHandler.java │ │ └── package-info.java │ │ └── server │ │ ├── NettyServer.java │ │ ├── NettyServerFilter.java │ │ ├── NettyServerHandler.java │ │ └── package-info.java │ └── test │ └── java │ └── com │ └── pancm │ └── netty │ └── AppTest.java ├── Netty-slidingWindow ├── pom.xml ├── src │ └── main │ │ └── java │ │ └── com │ │ └── pancm │ │ └── netty │ │ ├── App.java │ │ ├── client │ │ ├── NettyClient.java │ │ ├── NettyClientFilter.java │ │ ├── NettyClientHandler.java │ │ └── package-info.java │ │ ├── pojo │ │ ├── Message.java │ │ └── package-info.java │ │ └── server │ │ ├── NettyServer.java │ │ ├── NettyServerFilter.java │ │ ├── NettyServerHandler.java │ │ └── package-info.java └── target │ └── classes │ └── META-INF │ ├── MANIFEST.MF │ └── maven │ └── 1.0.0 │ └── Netty-slidingWindow │ ├── pom.properties │ └── pom.xml ├── Netty-unpack ├── .gitignore ├── pom.xml └── src │ ├── main │ └── java │ │ └── com │ │ └── pancm │ │ └── netty │ │ ├── App.java │ │ ├── client │ │ ├── NettyClient.java │ │ ├── NettyClientHandler.java │ │ └── package-info.java │ │ └── server │ │ ├── NettyServer.java │ │ ├── NettyServerHandler.java │ │ └── package-info.java │ └── test │ └── java │ └── com │ └── pancm │ └── netty │ └── AppTest.java └── README.md /.github/workflows/maven.yml: -------------------------------------------------------------------------------- 1 | name: Java CI 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v1 12 | - name: Set up JDK 1.8 13 | uses: actions/setup-java@v1 14 | with: 15 | java-version: 1.8 16 | - name: Build with Maven 17 | run: mvn -B package --file pom.xml 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuwujing/Netty-study/c63add9f463ab11ea4d5980c606f0654bd6f6432/.gitignore -------------------------------------------------------------------------------- /Netty-heartbeat/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /Netty-heartbeat/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | 1.0.0 6 | Netty-heartbeat 7 | 0.0.1-SNAPSHOT 8 | jar 9 | Netty-heartbeat 10 | http://maven.apache.org 11 | 12 | 13 | 14 | UTF-8 15 | 1.7 16 | 4.1.22.Final 17 | 18 | 19 | 20 | 21 | 22 | junit 23 | junit 24 | 3.8.1 25 | test 26 | 27 | 28 | io.netty 29 | netty-all 30 | ${netty.version} 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /Netty-heartbeat/src/main/java/com/pancm/netty/App.java: -------------------------------------------------------------------------------- 1 | package com.pancm.netty; 2 | 3 | /** 4 | * Hello world! 5 | * 6 | */ 7 | public class App 8 | { 9 | public static void main( String[] args ) 10 | { 11 | System.out.println( "Hello World!" ); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Netty-heartbeat/src/main/java/com/pancm/netty/client/NettyClient.java: -------------------------------------------------------------------------------- 1 | package com.pancm.netty.client; 2 | 3 | import io.netty.bootstrap.Bootstrap; 4 | import io.netty.channel.Channel; 5 | import io.netty.channel.EventLoopGroup; 6 | import io.netty.channel.nio.NioEventLoopGroup; 7 | import io.netty.channel.socket.nio.NioSocketChannel; 8 | import java.io.IOException; 9 | /** 10 | * 11 | * Title: NettyClient 12 | * Description: 13 | * Netty客户端 心跳测试 14 | * Version:1.0.0 15 | * @author pancm 16 | * @date 2017年10月8日 17 | */ 18 | public class NettyClient { 19 | 20 | public static String host = "127.0.0.1"; //ip地址 21 | public static int port = 9876; //端口 22 | /// 通过nio方式来接收连接和处理连接 23 | private static EventLoopGroup group = new NioEventLoopGroup(); 24 | private static Bootstrap b = new Bootstrap(); 25 | private static Channel ch; 26 | 27 | /** 28 | * Netty创建全部都是实现自AbstractBootstrap。 29 | * 客户端的是Bootstrap,服务端的则是 ServerBootstrap。 30 | **/ 31 | public static void main(String[] args) throws InterruptedException, IOException { 32 | System.out.println("客户端成功启动..."); 33 | b.group(group); 34 | b.channel(NioSocketChannel.class); 35 | b.handler(new NettyClientFilter()); 36 | // 连接服务端 37 | ch = b.connect(host, port).sync().channel(); 38 | star(); 39 | } 40 | 41 | public static void star() throws IOException{ 42 | String str="Hello Netty"; 43 | ch.writeAndFlush(str); 44 | // ch.writeAndFlush(str+ "\r\n"); 45 | System.out.println("客户端发送数据:"+str); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Netty-heartbeat/src/main/java/com/pancm/netty/client/NettyClientFilter.java: -------------------------------------------------------------------------------- 1 | package com.pancm.netty.client; 2 | 3 | import io.netty.channel.ChannelInitializer; 4 | import io.netty.channel.ChannelPipeline; 5 | import io.netty.channel.socket.SocketChannel; 6 | import io.netty.handler.codec.string.StringDecoder; 7 | import io.netty.handler.codec.string.StringEncoder; 8 | import io.netty.handler.timeout.IdleStateHandler; 9 | 10 | import java.util.concurrent.TimeUnit; 11 | /** 12 | * 13 | * Title: NettyClientFilter 14 | * Description: Netty客户端 过滤器 15 | * Version:1.0.0 16 | * @author pancm 17 | * @date 2017年10月8日 18 | */ 19 | public class NettyClientFilter extends ChannelInitializer { 20 | 21 | @Override 22 | protected void initChannel(SocketChannel ch) throws Exception { 23 | ChannelPipeline ph = ch.pipeline(); 24 | /* 25 | * 解码和编码,应和服务端一致 26 | * */ 27 | // ph.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter())); 28 | //入参说明: 读超时时间、写超时时间、所有类型的超时时间、时间格式 29 | //因为服务端设置的超时时间是5秒,所以设置4秒 30 | ph.addLast( new IdleStateHandler(0, 4, 0, TimeUnit.SECONDS)); 31 | ph.addLast("decoder", new StringDecoder()); 32 | ph.addLast("encoder", new StringEncoder()); 33 | ph.addLast("handler", new NettyClientHandler()); //客户端的逻辑 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Netty-heartbeat/src/main/java/com/pancm/netty/client/NettyClientHandler.java: -------------------------------------------------------------------------------- 1 | package com.pancm.netty.client; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.buffer.Unpooled; 5 | import io.netty.channel.ChannelHandlerContext; 6 | import io.netty.channel.ChannelInboundHandlerAdapter; 7 | import io.netty.handler.timeout.IdleState; 8 | import io.netty.handler.timeout.IdleStateEvent; 9 | import io.netty.util.CharsetUtil; 10 | 11 | import java.util.Date; 12 | 13 | /** 14 | * 15 | * Title: NettyClientHandler 16 | * Description: 客户端业务逻辑实现 17 | * Version:1.0.0 18 | * @author pancm 19 | * @date 2017年10月8日 20 | */ 21 | public class NettyClientHandler extends ChannelInboundHandlerAdapter { 22 | /** 客户端请求的心跳命令 */ 23 | private static final ByteBuf HEARTBEAT_SEQUENCE = Unpooled.unreleasableBuffer(Unpooled.copiedBuffer("hb_request", 24 | CharsetUtil.UTF_8)); 25 | 26 | /** 空闲次数 */ 27 | private int idle_count = 1; 28 | 29 | /** 发送次数 */ 30 | private int count = 1; 31 | 32 | /**循环次数 */ 33 | private int fcount = 1; 34 | 35 | /** 36 | * 建立连接时 37 | */ 38 | @Override 39 | public void channelActive(ChannelHandlerContext ctx) throws Exception { 40 | System.out.println("建立连接时:"+new Date()); 41 | ctx.fireChannelActive(); 42 | } 43 | 44 | /** 45 | * 关闭连接时 46 | */ 47 | @Override 48 | public void channelInactive(ChannelHandlerContext ctx) throws Exception { 49 | System.out.println("关闭连接时:"+new Date()); 50 | } 51 | 52 | /** 53 | * 心跳请求处理 54 | * 每4秒发送一次心跳请求; 55 | * 56 | */ 57 | @Override 58 | public void userEventTriggered(ChannelHandlerContext ctx, Object obj) throws Exception { 59 | System.out.println("循环请求的时间:"+new Date()+",次数"+fcount); 60 | if (obj instanceof IdleStateEvent) { 61 | IdleStateEvent event = (IdleStateEvent) obj; 62 | if (IdleState.WRITER_IDLE.equals(event.state())) { //如果写通道处于空闲状态,就发送心跳命令 63 | if(idle_count <= 3){ //设置发送次数 64 | idle_count++; 65 | ctx.channel().writeAndFlush(HEARTBEAT_SEQUENCE.duplicate()); 66 | }else{ 67 | System.out.println("不再发送心跳请求了!"); 68 | } 69 | fcount++; 70 | } 71 | } 72 | } 73 | 74 | /** 75 | * 业务逻辑处理 76 | */ 77 | @Override 78 | public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 79 | System.out.println("第"+count+"次"+",客户端接受的消息:"+msg); 80 | count++; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /Netty-heartbeat/src/main/java/com/pancm/netty/client/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * Title: package-info 6 | * Description: 7 | * Version:1.0.0 8 | * @author pancm 9 | * @date 2018年1月27日 10 | */ 11 | package com.pancm.netty.client; -------------------------------------------------------------------------------- /Netty-heartbeat/src/main/java/com/pancm/netty/server/NettyServer.java: -------------------------------------------------------------------------------- 1 | package com.pancm.netty.server; 2 | 3 | import io.netty.bootstrap.ServerBootstrap; 4 | import io.netty.channel.ChannelFuture; 5 | import io.netty.channel.EventLoopGroup; 6 | import io.netty.channel.nio.NioEventLoopGroup; 7 | import io.netty.channel.socket.nio.NioServerSocketChannel; 8 | 9 | /** 10 | * 11 | * Title: NettyServer 12 | * Description: Netty服务端 13 | * 心跳测试 14 | * Version:1.0.0 15 | * @author pancm 16 | * @date 2017年10月8日 17 | */ 18 | public class NettyServer { 19 | private static final int port = 9876; //设置服务端端口 20 | private static EventLoopGroup group = new NioEventLoopGroup(); // 通过nio方式来接收连接和处理连接 21 | private static ServerBootstrap b = new ServerBootstrap(); 22 | 23 | /** 24 | * Netty创建全部都是实现自AbstractBootstrap。 25 | * 客户端的是Bootstrap,服务端的则是 ServerBootstrap。 26 | **/ 27 | public static void main(String[] args) throws InterruptedException { 28 | try { 29 | b.group(group); 30 | b.channel(NioServerSocketChannel.class); 31 | b.childHandler(new NettyServerFilter()); //设置过滤器 32 | // 服务器绑定端口监听 33 | ChannelFuture f = b.bind(port).sync(); 34 | System.out.println("服务端启动成功,端口是:"+port); 35 | // 监听服务器关闭监听 36 | f.channel().closeFuture().sync(); 37 | } finally { 38 | group.shutdownGracefully(); //关闭EventLoopGroup,释放掉所有资源包括创建的线程 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Netty-heartbeat/src/main/java/com/pancm/netty/server/NettyServerFilter.java: -------------------------------------------------------------------------------- 1 | package com.pancm.netty.server; 2 | 3 | import io.netty.channel.ChannelInitializer; 4 | import io.netty.channel.ChannelPipeline; 5 | import io.netty.channel.socket.SocketChannel; 6 | import io.netty.handler.codec.string.StringDecoder; 7 | import io.netty.handler.codec.string.StringEncoder; 8 | import io.netty.handler.timeout.IdleStateHandler; 9 | 10 | import java.util.concurrent.TimeUnit; 11 | 12 | /** 13 | * 14 | * Title: HelloServerInitializer 15 | * Description: Netty 服务端过滤器 16 | * Version:1.0.0 17 | * @author pancm 18 | * @date 2017年10月8日 19 | */ 20 | public class NettyServerFilter extends ChannelInitializer { 21 | 22 | @Override 23 | protected void initChannel(SocketChannel ch) throws Exception { 24 | ChannelPipeline ph = ch.pipeline(); 25 | // 以("\n")为结尾分割的 解码器 26 | // ph.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter())); 27 | // 解码和编码,应和客户端一致 28 | //入参说明: 读超时时间、写超时时间、所有类型的超时时间、时间格式 29 | ph.addLast(new IdleStateHandler(5, 0, 0, TimeUnit.SECONDS)); 30 | ph.addLast("decoder", new StringDecoder()); 31 | ph.addLast("encoder", new StringEncoder()); 32 | ph.addLast("handler", new NettyServerHandler());// 服务端业务逻辑 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Netty-heartbeat/src/main/java/com/pancm/netty/server/NettyServerHandler.java: -------------------------------------------------------------------------------- 1 | package com.pancm.netty.server; 2 | 3 | import io.netty.channel.ChannelHandlerContext; 4 | import io.netty.channel.ChannelInboundHandlerAdapter; 5 | import io.netty.handler.timeout.IdleState; 6 | import io.netty.handler.timeout.IdleStateEvent; 7 | 8 | /** 9 | * 10 | * Title: HelloServerHandler 11 | * Description: 服务端业务逻辑 12 | * Version:1.0.0 13 | * @author pancm 14 | * @date 2017年10月8日 15 | */ 16 | public class NettyServerHandler extends ChannelInboundHandlerAdapter { 17 | 18 | /** 空闲次数 */ 19 | private int idle_count =1; 20 | /** 发送次数 */ 21 | private int count = 1; 22 | 23 | /** 24 | * 超时处理 25 | * 如果5秒没有接受客户端的心跳,就触发; 26 | * 如果超过两次,则直接关闭; 27 | */ 28 | @Override 29 | public void userEventTriggered(ChannelHandlerContext ctx, Object obj) throws Exception { 30 | if (obj instanceof IdleStateEvent) { 31 | IdleStateEvent event = (IdleStateEvent) obj; 32 | if (IdleState.READER_IDLE.equals(event.state())) { //如果读通道处于空闲状态,说明没有接收到心跳命令 33 | System.out.println("已经5秒没有接收到客户端的信息了"); 34 | if (idle_count > 2) { 35 | System.out.println("关闭这个不活跃的channel"); 36 | ctx.channel().close(); 37 | } 38 | idle_count++; 39 | } 40 | } else { 41 | super.userEventTriggered(ctx, obj); 42 | } 43 | } 44 | 45 | /** 46 | * 业务逻辑处理 47 | */ 48 | @Override 49 | public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 50 | System.out.println("第"+count+"次"+",服务端接受的消息:"+msg); 51 | String message = (String) msg; 52 | if ("hb_request".equals(message)) { //如果是心跳命令,则发送给客户端;否则什么都不做 53 | ctx.write("服务端成功收到心跳信息"); 54 | ctx.flush(); 55 | } 56 | count++; 57 | } 58 | 59 | /** 60 | * 异常处理 61 | */ 62 | @Override 63 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 64 | cause.printStackTrace(); 65 | ctx.close(); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /Netty-heartbeat/src/main/java/com/pancm/netty/server/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * Title: package-info 6 | * Description: 7 | * Version:1.0.0 8 | * @author pancm 9 | * @date 2018年1月27日 10 | */ 11 | package com.pancm.netty.server; -------------------------------------------------------------------------------- /Netty-heartbeat/src/test/java/com/pancm/netty/AppTest.java: -------------------------------------------------------------------------------- 1 | package com.pancm.netty; 2 | 3 | import junit.framework.Test; 4 | import junit.framework.TestCase; 5 | import junit.framework.TestSuite; 6 | 7 | /** 8 | * Unit test for simple App. 9 | */ 10 | public class AppTest 11 | extends TestCase 12 | { 13 | /** 14 | * Create the test case 15 | * 16 | * @param testName name of the test case 17 | */ 18 | public AppTest( String testName ) 19 | { 20 | super( testName ); 21 | } 22 | 23 | /** 24 | * @return the suite of tests being tested 25 | */ 26 | public static Test suite() 27 | { 28 | return new TestSuite( AppTest.class ); 29 | } 30 | 31 | /** 32 | * Rigourous Test :-) 33 | */ 34 | public void testApp() 35 | { 36 | assertTrue( true ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Netty-hello/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /Netty-hello/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | 1.0.0 6 | Netty-hello 7 | 0.0.1-SNAPSHOT 8 | jar 9 | 10 | Netty-hello 11 | http://maven.apache.org 12 | 13 | 14 | UTF-8 15 | 1.7 16 | 4.1.17.Final 17 | 18 | 19 | 20 | 21 | 22 | junit 23 | junit 24 | 3.8.1 25 | test 26 | 27 | 28 | 29 | io.netty 30 | netty-all 31 | ${netty.version} 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /Netty-hello/src/main/java/com/pancm/netty/App.java: -------------------------------------------------------------------------------- 1 | package com.pancm.netty; 2 | 3 | /** 4 | * Hello world! 5 | * 6 | */ 7 | public class App 8 | { 9 | public static void main( String[] args ) 10 | { 11 | System.out.println( "Hello World!" ); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Netty-hello/src/main/java/com/pancm/netty/client/NettyClient.java: -------------------------------------------------------------------------------- 1 | package com.pancm.netty.client; 2 | 3 | import io.netty.bootstrap.Bootstrap; 4 | import io.netty.channel.Channel; 5 | import io.netty.channel.EventLoopGroup; 6 | import io.netty.channel.nio.NioEventLoopGroup; 7 | import io.netty.channel.socket.nio.NioSocketChannel; 8 | 9 | import java.io.IOException; 10 | /** 11 | * 12 | * Title: NettyClient 13 | * Description: 14 | * Netty客户端 15 | * Version:1.0.0 16 | * @author pancm 17 | * @date 2017-8-31 18 | */ 19 | public class NettyClient { 20 | 21 | public static String host = "127.0.0.1"; //ip地址 22 | public static int port = 6789; //端口 23 | /// 通过nio方式来接收连接和处理连接 24 | private static EventLoopGroup group = new NioEventLoopGroup(); 25 | private static Bootstrap b = new Bootstrap(); 26 | private static Channel ch; 27 | 28 | /** 29 | * Netty创建全部都是实现自AbstractBootstrap。 30 | * 客户端的是Bootstrap,服务端的则是 ServerBootstrap。 31 | **/ 32 | public static void main(String[] args) throws InterruptedException, IOException { 33 | System.out.println("客户端成功启动..."); 34 | b.group(group); 35 | b.channel(NioSocketChannel.class); 36 | b.handler(new NettyClientFilter()); 37 | // 连接服务端 38 | ch = b.connect(host, port).sync().channel(); 39 | star(); 40 | } 41 | 42 | public static void star() throws IOException{ 43 | String str="Hello Netty"; 44 | ch.writeAndFlush(str+ "\r\n"); 45 | System.out.println("客户端发送数据:"+str); 46 | } 47 | 48 | } -------------------------------------------------------------------------------- /Netty-hello/src/main/java/com/pancm/netty/client/NettyClientFilter.java: -------------------------------------------------------------------------------- 1 | package com.pancm.netty.client; 2 | 3 | import io.netty.channel.ChannelInitializer; 4 | import io.netty.channel.ChannelPipeline; 5 | import io.netty.channel.socket.SocketChannel; 6 | import io.netty.handler.codec.DelimiterBasedFrameDecoder; 7 | import io.netty.handler.codec.Delimiters; 8 | import io.netty.handler.codec.string.StringDecoder; 9 | import io.netty.handler.codec.string.StringEncoder; 10 | /** 11 | * 12 | * Title: NettyClientFilter 13 | * Description: 14 | * Netty客户端 过滤器 15 | * Version:1.0.0 16 | * @author pancm 17 | * @date 2017-8-31 18 | */ 19 | public class NettyClientFilter extends ChannelInitializer { 20 | 21 | @Override 22 | protected void initChannel(SocketChannel ch) throws Exception { 23 | ChannelPipeline ph = ch.pipeline(); 24 | /* 25 | * 解码和编码,应和服务端一致 26 | * */ 27 | ph.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter())); 28 | ph.addLast("decoder", new StringDecoder()); 29 | ph.addLast("encoder", new StringEncoder()); 30 | ph.addLast("handler", new NettyClientHandler()); //客户端的逻辑 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Netty-hello/src/main/java/com/pancm/netty/client/NettyClientHandler.java: -------------------------------------------------------------------------------- 1 | package com.pancm.netty.client; 2 | 3 | import io.netty.channel.ChannelHandlerContext; 4 | import io.netty.channel.SimpleChannelInboundHandler; 5 | 6 | /** 7 | * 8 | * Title: NettyClientHandler 9 | * Description: 10 | * 客户端业务逻辑实现 11 | * Version:1.0.0 12 | * @author pancm 13 | * @date 2017-8-31 14 | */ 15 | public class NettyClientHandler extends SimpleChannelInboundHandler { 16 | 17 | @Override 18 | protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception { 19 | System.out.println("客户端接受的消息: " + msg); 20 | } 21 | 22 | // 23 | @Override 24 | public void channelActive(ChannelHandlerContext ctx) throws Exception { 25 | System.out.println("正在连接... "); 26 | super.channelActive(ctx); 27 | } 28 | 29 | @Override 30 | public void channelInactive(ChannelHandlerContext ctx) throws Exception { 31 | System.out.println("连接关闭! "); 32 | super.channelInactive(ctx); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Netty-hello/src/main/java/com/pancm/netty/client/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * Title: package-info 6 | * Description: 7 | * Version:1.0.0 8 | * @author pancm 9 | * @date 2018年1月27日 10 | */ 11 | package com.pancm.netty.client; -------------------------------------------------------------------------------- /Netty-hello/src/main/java/com/pancm/netty/server/NettyServer.java: -------------------------------------------------------------------------------- 1 | package com.pancm.netty.server; 2 | 3 | import io.netty.bootstrap.ServerBootstrap; 4 | import io.netty.channel.ChannelFuture; 5 | import io.netty.channel.EventLoopGroup; 6 | import io.netty.channel.nio.NioEventLoopGroup; 7 | import io.netty.channel.socket.nio.NioServerSocketChannel; 8 | 9 | 10 | /** 11 | * 12 | * Title: NettyServer 13 | * Description: 14 | * Netty服务端 15 | * Version:1.0.0 16 | * @author pancm 17 | * @date 2017-8-31 18 | */ 19 | public class NettyServer { 20 | private static final int port = 6789; //设置服务端端口 21 | private static EventLoopGroup group = new NioEventLoopGroup(); // 通过nio方式来接收连接和处理连接 22 | private static ServerBootstrap b = new ServerBootstrap(); 23 | 24 | /** 25 | * Netty创建全部都是实现自AbstractBootstrap。 26 | * 客户端的是Bootstrap,服务端的则是 ServerBootstrap。 27 | **/ 28 | public static void main(String[] args) throws InterruptedException { 29 | try { 30 | b.group(group); 31 | b.channel(NioServerSocketChannel.class); 32 | b.childHandler(new NettyServerFilter()); //设置过滤器 33 | // 服务器绑定端口监听 34 | ChannelFuture f = b.bind(port).sync(); 35 | System.out.println("服务端启动成功..."); 36 | // 监听服务器关闭监听 37 | f.channel().closeFuture().sync(); 38 | } finally { 39 | group.shutdownGracefully(); ////关闭EventLoopGroup,释放掉所有资源包括创建的线程 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Netty-hello/src/main/java/com/pancm/netty/server/NettyServerFilter.java: -------------------------------------------------------------------------------- 1 | package com.pancm.netty.server; 2 | 3 | import io.netty.channel.ChannelInitializer; 4 | import io.netty.channel.ChannelPipeline; 5 | import io.netty.channel.socket.SocketChannel; 6 | import io.netty.handler.codec.DelimiterBasedFrameDecoder; 7 | import io.netty.handler.codec.Delimiters; 8 | import io.netty.handler.codec.string.StringDecoder; 9 | import io.netty.handler.codec.string.StringEncoder; 10 | 11 | /** 12 | * 13 | * Title: NettyServerFilter 14 | * Description: 15 | * Netty 服务端过滤器 16 | * Version:1.0.0 17 | * @author pancm 18 | * @date 2017-8-31 19 | */ 20 | public class NettyServerFilter extends ChannelInitializer { 21 | 22 | @Override 23 | protected void initChannel(SocketChannel ch) throws Exception { 24 | ChannelPipeline ph = ch.pipeline(); 25 | // 以("\n")为结尾分割的 解码器 26 | ph.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter())); 27 | // 解码和编码,应和客户端一致 28 | ph.addLast("decoder", new StringDecoder()); 29 | ph.addLast("encoder", new StringEncoder()); 30 | ph.addLast("handler", new NettyServerHandler());// 服务端业务逻辑 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Netty-hello/src/main/java/com/pancm/netty/server/NettyServerHandler.java: -------------------------------------------------------------------------------- 1 | package com.pancm.netty.server; 2 | 3 | import java.net.InetAddress; 4 | import java.util.Date; 5 | import io.netty.channel.ChannelHandlerContext; 6 | import io.netty.channel.SimpleChannelInboundHandler; 7 | 8 | /** 9 | * 10 | * Title: HelloServerHandler 11 | * Description: 12 | * 服务端业务逻辑 13 | * Version:1.0.0 14 | * @author pancm 15 | * @date 2017-8-31 16 | */ 17 | public class NettyServerHandler extends SimpleChannelInboundHandler { 18 | /* 19 | * 收到消息时,返回信息 20 | */ 21 | @Override 22 | protected void channelRead0(ChannelHandlerContext ctx, String msg) 23 | throws Exception { 24 | // 收到消息直接打印输出 25 | System.out.println("服务端接受的消息 : " + msg); 26 | if("quit".equals(msg)){//服务端断开的条件 27 | ctx.close(); 28 | } 29 | Date date=new Date(); 30 | // 返回客户端消息 31 | ctx.writeAndFlush(date+"\n"); 32 | } 33 | 34 | /* 35 | * 建立连接时,返回消息 36 | */ 37 | @Override 38 | public void channelActive(ChannelHandlerContext ctx) throws Exception { 39 | System.out.println("连接的客户端地址:" + ctx.channel().remoteAddress()); 40 | ctx.writeAndFlush("客户端"+ InetAddress.getLocalHost().getHostName() + "成功与服务端建立连接! \n"); 41 | super.channelActive(ctx); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Netty-hello/src/main/java/com/pancm/netty/server/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * Title: package-info 6 | * Description: 7 | * Version:1.0.0 8 | * @author pancm 9 | * @date 2018年1月27日 10 | */ 11 | package com.pancm.netty.server; -------------------------------------------------------------------------------- /Netty-hello/src/test/java/com/pancm/netty/AppTest.java: -------------------------------------------------------------------------------- 1 | package com.pancm.netty; 2 | 3 | import junit.framework.Test; 4 | import junit.framework.TestCase; 5 | import junit.framework.TestSuite; 6 | 7 | /** 8 | * Unit test for simple App. 9 | */ 10 | public class AppTest 11 | extends TestCase 12 | { 13 | /** 14 | * Create the test case 15 | * 16 | * @param testName name of the test case 17 | */ 18 | public AppTest( String testName ) 19 | { 20 | super( testName ); 21 | } 22 | 23 | /** 24 | * @return the suite of tests being tested 25 | */ 26 | public static Test suite() 27 | { 28 | return new TestSuite( AppTest.class ); 29 | } 30 | 31 | /** 32 | * Rigourous Test :-) 33 | */ 34 | public void testApp() 35 | { 36 | assertTrue( true ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Netty-httpServer/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /Netty-httpServer/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | 1.0.0 6 | Netty-httpServer 7 | 0.0.1-SNAPSHOT 8 | jar 9 | 10 | Netty-httpServer 11 | http://maven.apache.org 12 | 13 | 14 | UTF-8 15 | 1.7 16 | 4.1.17.Final 17 | 18 | 19 | 20 | 21 | 22 | junit 23 | junit 24 | 3.8.1 25 | test 26 | 27 | 28 | 29 | io.netty 30 | netty-all 31 | ${netty.version} 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /Netty-httpServer/src/main/java/com/pancm/netty/App.java: -------------------------------------------------------------------------------- 1 | package com.pancm.netty; 2 | 3 | /** 4 | * Hello world! 5 | * 6 | */ 7 | public class App 8 | { 9 | public static void main( String[] args ) 10 | { 11 | System.out.println( "Hello World!" ); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Netty-httpServer/src/main/java/com/pancm/netty/server/NettyServer.java: -------------------------------------------------------------------------------- 1 | package com.pancm.netty.server; 2 | 3 | import io.netty.bootstrap.ServerBootstrap; 4 | import io.netty.channel.ChannelFuture; 5 | import io.netty.channel.EventLoopGroup; 6 | import io.netty.channel.nio.NioEventLoopGroup; 7 | import io.netty.channel.socket.nio.NioServerSocketChannel; 8 | 9 | 10 | 11 | /** 12 | * 13 | * Title: NettyServer 14 | * Description: Netty服务端 Http测试 15 | * Version:1.0.0 16 | * @author pancm 17 | * @date 2017年10月26日 18 | */ 19 | public class NettyServer { 20 | private static final int port = 6789; //设置服务端端口 21 | private static EventLoopGroup group = new NioEventLoopGroup(); // 通过nio方式来接收连接和处理连接 22 | private static ServerBootstrap b = new ServerBootstrap(); 23 | 24 | /** 25 | * Netty创建全部都是实现自AbstractBootstrap。 26 | * 客户端的是Bootstrap,服务端的则是 ServerBootstrap。 27 | **/ 28 | public static void main(String[] args) throws InterruptedException { 29 | try { 30 | b.group(group); 31 | b.channel(NioServerSocketChannel.class); 32 | b.childHandler(new NettyServerFilter()); //设置过滤器 33 | // 服务器绑定端口监听 34 | ChannelFuture f = b.bind(port).sync(); 35 | System.out.println("服务端启动成功,端口是:"+port); 36 | // 监听服务器关闭监听 37 | f.channel().closeFuture().sync(); 38 | } finally { 39 | group.shutdownGracefully(); //关闭EventLoopGroup,释放掉所有资源包括创建的线程 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Netty-httpServer/src/main/java/com/pancm/netty/server/NettyServerFilter.java: -------------------------------------------------------------------------------- 1 | package com.pancm.netty.server; 2 | 3 | 4 | import io.netty.channel.ChannelInitializer; 5 | import io.netty.channel.ChannelPipeline; 6 | import io.netty.channel.socket.SocketChannel; 7 | import io.netty.handler.codec.http.HttpObjectAggregator; 8 | import io.netty.handler.codec.http.HttpRequestDecoder; 9 | import io.netty.handler.codec.http.HttpResponseEncoder; 10 | 11 | 12 | /** 13 | * 14 | * Title: NettyServerFilter 15 | * Description: Netty 服务端过滤器 16 | * Version:1.0.0 17 | * @author pancm 18 | * @date 2017年10月26日 19 | */ 20 | public class NettyServerFilter extends ChannelInitializer { 21 | 22 | @Override 23 | protected void initChannel(SocketChannel ch) throws Exception { 24 | ChannelPipeline ph = ch.pipeline(); 25 | //处理http服务的关键handler 26 | ph.addLast("encoder",new HttpResponseEncoder()); 27 | ph.addLast("decoder",new HttpRequestDecoder()); 28 | ph.addLast("aggregator", new HttpObjectAggregator(10*1024*1024)); 29 | ph.addLast("handler", new NettyServerHandler());// 服务端业务逻辑 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Netty-httpServer/src/main/java/com/pancm/netty/server/NettyServerHandler.java: -------------------------------------------------------------------------------- 1 | package com.pancm.netty.server; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.buffer.Unpooled; 5 | import io.netty.channel.ChannelFutureListener; 6 | import io.netty.channel.ChannelHandlerContext; 7 | import io.netty.channel.ChannelInboundHandlerAdapter; 8 | import io.netty.handler.codec.http.DefaultFullHttpResponse; 9 | import io.netty.handler.codec.http.FullHttpRequest; 10 | import io.netty.handler.codec.http.FullHttpResponse; 11 | import io.netty.handler.codec.http.HttpHeaderNames; 12 | import io.netty.handler.codec.http.HttpMethod; 13 | import io.netty.handler.codec.http.HttpResponseStatus; 14 | import io.netty.handler.codec.http.HttpVersion; 15 | import io.netty.util.CharsetUtil; 16 | import java.net.InetAddress; 17 | 18 | /** 19 | * 20 | * Title: NettyServerHandler 21 | * Description: 服务端业务逻辑 22 | * Version:1.0.0 23 | * @author pancm 24 | * @date 2017年10月26日 25 | */ 26 | public class NettyServerHandler extends ChannelInboundHandlerAdapter { 27 | private String result=""; 28 | /* 29 | * 收到消息时,返回信息 30 | */ 31 | @Override 32 | public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 33 | if(! (msg instanceof FullHttpRequest)){ 34 | result="未知请求!"; 35 | send(ctx,result,HttpResponseStatus.BAD_REQUEST); 36 | return; 37 | } 38 | FullHttpRequest httpRequest = (FullHttpRequest)msg; 39 | try{ 40 | String path=httpRequest.uri(); //获取路径 41 | String body = getBody(httpRequest); //获取参数 42 | HttpMethod method=httpRequest.method();//获取请求方法 43 | //如果不是这个路径,就直接返回错误 44 | if(!"/test".equalsIgnoreCase(path)){ 45 | result="非法请求!"; 46 | send(ctx,result,HttpResponseStatus.BAD_REQUEST); 47 | return; 48 | } 49 | System.out.println("接收到:"+method+" 请求"); 50 | //如果是GET请求 51 | if(HttpMethod.GET.equals(method)){ 52 | //接受到的消息,做业务逻辑处理... 53 | System.out.println("body:"+body); 54 | result="GET请求"; 55 | send(ctx,result,HttpResponseStatus.OK); 56 | return; 57 | } 58 | //如果是POST请求 59 | if(HttpMethod.POST.equals(method)){ 60 | //接受到的消息,做业务逻辑处理... 61 | System.out.println("body:"+body); 62 | result="POST请求"; 63 | send(ctx,result,HttpResponseStatus.OK); 64 | return; 65 | } 66 | 67 | //如果是PUT请求 68 | if(HttpMethod.PUT.equals(method)){ 69 | //接受到的消息,做业务逻辑处理... 70 | System.out.println("body:"+body); 71 | result="PUT请求"; 72 | send(ctx,result,HttpResponseStatus.OK); 73 | return; 74 | } 75 | //如果是DELETE请求 76 | if(HttpMethod.DELETE.equals(method)){ 77 | //接受到的消息,做业务逻辑处理... 78 | System.out.println("body:"+body); 79 | result="DELETE请求"; 80 | send(ctx,result,HttpResponseStatus.OK); 81 | return; 82 | } 83 | }catch(Exception e){ 84 | System.out.println("处理请求失败!"); 85 | e.printStackTrace(); 86 | }finally{ 87 | //释放请求 88 | httpRequest.release(); 89 | } 90 | } 91 | 92 | /** 93 | * 获取body参数 94 | * @param request 95 | * @return 96 | */ 97 | private String getBody(FullHttpRequest request){ 98 | ByteBuf buf = request.content(); 99 | return buf.toString(CharsetUtil.UTF_8); 100 | } 101 | 102 | /** 103 | * 发送的返回值 104 | * @param ctx 返回 105 | * @param context 消息 106 | * @param status 状态 107 | */ 108 | private void send(ChannelHandlerContext ctx, String context,HttpResponseStatus status) { 109 | FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, status, Unpooled.copiedBuffer(context, CharsetUtil.UTF_8)); 110 | response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain; charset=UTF-8"); 111 | ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); 112 | } 113 | 114 | /* 115 | * 建立连接时,返回消息 116 | */ 117 | @Override 118 | public void channelActive(ChannelHandlerContext ctx) throws Exception { 119 | System.out.println("连接的客户端地址:" + ctx.channel().remoteAddress()); 120 | ctx.writeAndFlush("客户端"+ InetAddress.getLocalHost().getHostName() + "成功与服务端建立连接! "); 121 | super.channelActive(ctx); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /Netty-httpServer/src/main/java/com/pancm/netty/server/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * Title: package-info 6 | * Description: Http服务测试 7 | * Version:1.0.0 8 | * @author pancm 9 | * @date 2017年10月26日 10 | */ 11 | package com.pancm.netty.server; -------------------------------------------------------------------------------- /Netty-httpServer/src/test/java/com/pancm/netty/AppTest.java: -------------------------------------------------------------------------------- 1 | package com.pancm.netty; 2 | 3 | import junit.framework.Test; 4 | import junit.framework.TestCase; 5 | import junit.framework.TestSuite; 6 | 7 | /** 8 | * Unit test for simple App. 9 | */ 10 | public class AppTest 11 | extends TestCase 12 | { 13 | /** 14 | * Create the test case 15 | * 16 | * @param testName name of the test case 17 | */ 18 | public AppTest( String testName ) 19 | { 20 | super( testName ); 21 | } 22 | 23 | /** 24 | * @return the suite of tests being tested 25 | */ 26 | public static Test suite() 27 | { 28 | return new TestSuite( AppTest.class ); 29 | } 30 | 31 | /** 32 | * Rigourous Test :-) 33 | */ 34 | public void testApp() 35 | { 36 | assertTrue( true ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Netty-protobuf/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | -------------------------------------------------------------------------------- /Netty-protobuf/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | 1.0.0 6 | Netty-protobuf 7 | 0.0.1-SNAPSHOT 8 | jar 9 | 10 | Netty-protobuf 11 | http://maven.apache.org 12 | 13 | 14 | 15 | UTF-8 16 | 1.8 17 | 4.1.22.Final 18 | 3.5.1 19 | 1.8 20 | 1.8 21 | 22 | 23 | 24 | 25 | 26 | 27 | io.netty 28 | netty-all 29 | ${netty.version} 30 | 31 | 32 | 33 | com.google.protobuf 34 | protobuf-java 35 | ${protobuf.version} 36 | 37 | 38 | 39 | junit 40 | junit 41 | 4.12 42 | test 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /Netty-protobuf/src/main/java/com/pancm/client/NettyClient.java: -------------------------------------------------------------------------------- 1 | package com.pancm.client; 2 | 3 | import java.util.concurrent.TimeUnit; 4 | 5 | import io.netty.bootstrap.Bootstrap; 6 | import io.netty.channel.ChannelFuture; 7 | import io.netty.channel.ChannelOption; 8 | import io.netty.channel.EventLoop; 9 | import io.netty.channel.EventLoopGroup; 10 | import io.netty.channel.nio.NioEventLoopGroup; 11 | import io.netty.channel.socket.nio.NioSocketChannel; 12 | 13 | /** 14 | * 15 | * @Title: NettyClient 16 | * @Description: Netty客户端 心跳测试 17 | * @Version:1.0.0 18 | * @author pancm 19 | * @date 2017年10月8日 20 | */ 21 | public class NettyClient { 22 | 23 | public String host = "127.0.0.1"; // ip地址 24 | public int port = 9876; // 端口 25 | // 通过nio方式来接收连接和处理连接 26 | private EventLoopGroup group = new NioEventLoopGroup(); 27 | public static NettyClient nettyClient = new NettyClient(); 28 | 29 | /**唯一标记 */ 30 | private boolean initFalg=true; 31 | 32 | public static void main(String[] args) { 33 | nettyClient.run(); 34 | } 35 | 36 | /** 37 | * Netty创建全部都是实现自AbstractBootstrap。 客户端的是Bootstrap,服务端的则是 ServerBootstrap。 38 | **/ 39 | public void run() { 40 | doConnect(new Bootstrap(), group); 41 | } 42 | 43 | /** 44 | * 重连 45 | */ 46 | public void doConnect(Bootstrap bootstrap, EventLoopGroup eventLoopGroup) { 47 | ChannelFuture f = null; 48 | try { 49 | if (bootstrap != null) { 50 | bootstrap.group(eventLoopGroup); 51 | bootstrap.channel(NioSocketChannel.class); 52 | bootstrap.option(ChannelOption.SO_KEEPALIVE, true); 53 | bootstrap.handler(new NettyClientFilter()); 54 | bootstrap.remoteAddress(host, port); 55 | f = bootstrap.connect().addListener((ChannelFuture futureListener) -> { 56 | final EventLoop eventLoop = futureListener.channel().eventLoop(); 57 | if (!futureListener.isSuccess()) { 58 | System.out.println("与服务端断开连接!在10s之后准备尝试重连!"); 59 | eventLoop.schedule(() -> doConnect(new Bootstrap(), eventLoop), 10, TimeUnit.SECONDS); 60 | } 61 | }); 62 | if(initFalg){ 63 | System.out.println("Netty客户端启动成功!"); 64 | initFalg=false; 65 | } 66 | // 阻塞 67 | f.channel().closeFuture().sync(); 68 | } 69 | } catch (Exception e) { 70 | System.out.println("客户端连接失败!"+e.getMessage()); 71 | } 72 | 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Netty-protobuf/src/main/java/com/pancm/client/NettyClientApp.java: -------------------------------------------------------------------------------- 1 | package com.pancm.client; 2 | 3 | /** 4 | * @Title: NettyClientApp 5 | * @Description: Netty 客户端主程序 6 | * @Version:1.0.0 7 | * @author pancm 8 | * @date 2018年7月11日 9 | */ 10 | public class NettyClientApp { 11 | 12 | /** 13 | * @param args 14 | */ 15 | public static void main(String[] args) { 16 | NettyClient nettyClient = new NettyClient(); 17 | nettyClient.run(); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /Netty-protobuf/src/main/java/com/pancm/client/NettyClientFilter.java: -------------------------------------------------------------------------------- 1 | package com.pancm.client; 2 | 3 | import java.util.concurrent.TimeUnit; 4 | 5 | import com.pancm.protobuf.UserInfo.UserMsg; 6 | 7 | import io.netty.channel.ChannelInitializer; 8 | import io.netty.channel.ChannelPipeline; 9 | import io.netty.channel.socket.SocketChannel; 10 | import io.netty.handler.codec.protobuf.ProtobufDecoder; 11 | import io.netty.handler.codec.protobuf.ProtobufEncoder; 12 | import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder; 13 | import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender; 14 | import io.netty.handler.timeout.IdleStateHandler; 15 | /** 16 | * 17 | * @Title: NettyClientFilter 18 | * @Description: Netty客户端 过滤器 19 | * @Version:1.0.0 20 | * @author pancm 21 | * @date 2017年10月8日 22 | */ 23 | public class NettyClientFilter extends ChannelInitializer { 24 | 25 | @Override 26 | protected void initChannel(SocketChannel ch) throws Exception { 27 | ChannelPipeline ph = ch.pipeline(); 28 | /* 29 | * 解码和编码,应和服务端一致 30 | * */ 31 | //入参说明: 读超时时间、写超时时间、所有类型的超时时间、时间格式 32 | ph.addLast(new IdleStateHandler(0, 4, 0, TimeUnit.SECONDS)); 33 | 34 | //传输的协议 Protobuf 35 | ph.addLast(new ProtobufVarint32FrameDecoder()); 36 | ph.addLast(new ProtobufDecoder(UserMsg.getDefaultInstance())); 37 | ph.addLast(new ProtobufVarint32LengthFieldPrepender()); 38 | ph.addLast(new ProtobufEncoder()); 39 | 40 | //业务逻辑实现类 41 | ph.addLast("nettyClientHandler", new NettyClientHandler()); 42 | 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Netty-protobuf/src/main/java/com/pancm/client/NettyClientHandler.java: -------------------------------------------------------------------------------- 1 | package com.pancm.client; 2 | 3 | import java.util.Date; 4 | 5 | import com.pancm.protobuf.UserInfo; 6 | import com.pancm.protobuf.UserInfo.UserMsg; 7 | 8 | import io.netty.bootstrap.Bootstrap; 9 | import io.netty.channel.ChannelHandlerContext; 10 | import io.netty.channel.ChannelInboundHandlerAdapter; 11 | import io.netty.channel.EventLoop; 12 | import io.netty.handler.timeout.IdleState; 13 | import io.netty.handler.timeout.IdleStateEvent; 14 | import io.netty.util.ReferenceCountUtil; 15 | 16 | /** 17 | * 18 | * @Title: NettyClientHandler 19 | * @Description: 客户端业务逻辑实现 20 | * @Version:1.0.0 21 | * @author pancm 22 | * @date 2017年10月8日 23 | */ 24 | public class NettyClientHandler extends ChannelInboundHandlerAdapter { 25 | 26 | 27 | /** 循环次数 */ 28 | private int fcount = 1; 29 | 30 | /** 31 | * 建立连接时 32 | */ 33 | @Override 34 | public void channelActive(ChannelHandlerContext ctx) throws Exception { 35 | System.out.println("建立连接时:" + new Date()); 36 | ctx.fireChannelActive(); 37 | } 38 | 39 | /** 40 | * 关闭连接时 41 | */ 42 | @Override 43 | public void channelInactive(ChannelHandlerContext ctx) throws Exception { 44 | System.out.println("关闭连接时:" + new Date()); 45 | final EventLoop eventLoop = ctx.channel().eventLoop(); 46 | NettyClient.nettyClient.doConnect(new Bootstrap(), eventLoop); 47 | super.channelInactive(ctx); 48 | } 49 | 50 | /** 51 | * 心跳请求处理 每4秒发送一次心跳请求; 52 | * 53 | */ 54 | @Override 55 | public void userEventTriggered(ChannelHandlerContext ctx, Object obj) throws Exception { 56 | System.out.println("循环请求的时间:" + new Date() + ",次数" + fcount); 57 | if (obj instanceof IdleStateEvent) { 58 | IdleStateEvent event = (IdleStateEvent) obj; 59 | if (IdleState.WRITER_IDLE.equals(event.state())) { // 如果写通道处于空闲状态,就发送心跳命令 60 | UserMsg.Builder userState = UserMsg.newBuilder().setState(2); 61 | ctx.channel().writeAndFlush(userState); 62 | fcount++; 63 | } 64 | } 65 | } 66 | 67 | /** 68 | * 业务逻辑处理 69 | */ 70 | @Override 71 | public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 72 | // 如果不是protobuf类型的数据 73 | if (!(msg instanceof UserMsg)) { 74 | System.out.println("未知数据!" + msg); 75 | return; 76 | } 77 | try { 78 | 79 | // 得到protobuf的数据 80 | UserInfo.UserMsg userMsg = (UserInfo.UserMsg) msg; 81 | // 进行相应的业务处理。。。 82 | // 这里就从简了,只是打印而已 83 | System.out.println( 84 | "客户端接受到的用户信息。编号:" + userMsg.getId() + ",姓名:" + userMsg.getName() + ",年龄:" + userMsg.getAge()); 85 | 86 | // 这里返回一个已经接受到数据的状态 87 | UserMsg.Builder userState = UserMsg.newBuilder().setState(1); 88 | ctx.writeAndFlush(userState); 89 | System.out.println("成功发送给服务端!"); 90 | } catch (Exception e) { 91 | e.printStackTrace(); 92 | } finally { 93 | ReferenceCountUtil.release(msg); 94 | } 95 | } 96 | 97 | } 98 | -------------------------------------------------------------------------------- /Netty-protobuf/src/main/java/com/pancm/client/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * @Title: package-info 3 | * @Description: Netty 客户端 4 | * @Version:1.0.0 5 | * @author pancm 6 | * @date 2018年7月9日 7 | */ 8 | package com.pancm.client; -------------------------------------------------------------------------------- /Netty-protobuf/src/main/java/com/pancm/protobuf/User.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | // 生成的包名 3 | option java_package="com.pancm.protobuf"; 4 | //生成的java名 5 | option java_outer_classname = "UserInfo"; 6 | 7 | message UserMsg { 8 | 9 | // ID 10 | int32 id = 1; 11 | 12 | // 姓名 13 | string name = 2; 14 | 15 | // 年龄 16 | int32 age = 3; 17 | 18 | // 状态 19 | int32 state = 4; 20 | 21 | } 22 | 23 | -------------------------------------------------------------------------------- /Netty-protobuf/src/main/java/com/pancm/protobuf/UserInfo.java: -------------------------------------------------------------------------------- 1 | // Generated by the protocol buffer compiler. DO NOT EDIT! 2 | // source: User.proto 3 | 4 | package com.pancm.protobuf; 5 | 6 | public final class UserInfo { 7 | private UserInfo() {} 8 | public static void registerAllExtensions( 9 | com.google.protobuf.ExtensionRegistryLite registry) { 10 | } 11 | 12 | public static void registerAllExtensions( 13 | com.google.protobuf.ExtensionRegistry registry) { 14 | registerAllExtensions( 15 | (com.google.protobuf.ExtensionRegistryLite) registry); 16 | } 17 | public interface UserMsgOrBuilder extends 18 | // @@protoc_insertion_point(interface_extends:UserMsg) 19 | com.google.protobuf.MessageOrBuilder { 20 | 21 | /** 22 | *
 23 |      * ID  
 24 |      * 
25 | * 26 | * optional int32 id = 1; 27 | */ 28 | int getId(); 29 | 30 | /** 31 | *
 32 |      * 姓名  
 33 |      * 
34 | * 35 | * optional string name = 2; 36 | */ 37 | java.lang.String getName(); 38 | /** 39 | *
 40 |      * 姓名  
 41 |      * 
42 | * 43 | * optional string name = 2; 44 | */ 45 | com.google.protobuf.ByteString 46 | getNameBytes(); 47 | 48 | /** 49 | *
 50 |      * 年龄  
 51 |      * 
52 | * 53 | * optional int32 age = 3; 54 | */ 55 | int getAge(); 56 | 57 | /** 58 | *
 59 |      * 状态 
 60 |      * 
61 | * 62 | * optional int32 state = 4; 63 | */ 64 | int getState(); 65 | } 66 | /** 67 | * Protobuf type {@code UserMsg} 68 | */ 69 | public static final class UserMsg extends 70 | com.google.protobuf.GeneratedMessageV3 implements 71 | // @@protoc_insertion_point(message_implements:UserMsg) 72 | UserMsgOrBuilder { 73 | // Use UserMsg.newBuilder() to construct. 74 | private UserMsg(com.google.protobuf.GeneratedMessageV3.Builder builder) { 75 | super(builder); 76 | } 77 | private UserMsg() { 78 | id_ = 0; 79 | name_ = ""; 80 | age_ = 0; 81 | state_ = 0; 82 | } 83 | 84 | @java.lang.Override 85 | public final com.google.protobuf.UnknownFieldSet 86 | getUnknownFields() { 87 | return com.google.protobuf.UnknownFieldSet.getDefaultInstance(); 88 | } 89 | @SuppressWarnings("unused") 90 | private UserMsg( 91 | com.google.protobuf.CodedInputStream input, 92 | com.google.protobuf.ExtensionRegistryLite extensionRegistry) 93 | throws com.google.protobuf.InvalidProtocolBufferException { 94 | this(); 95 | int mutable_bitField0_ = 0; 96 | try { 97 | boolean done = false; 98 | while (!done) { 99 | int tag = input.readTag(); 100 | switch (tag) { 101 | case 0: 102 | done = true; 103 | break; 104 | default: { 105 | if (!input.skipField(tag)) { 106 | done = true; 107 | } 108 | break; 109 | } 110 | case 8: { 111 | 112 | id_ = input.readInt32(); 113 | break; 114 | } 115 | case 18: { 116 | java.lang.String s = input.readStringRequireUtf8(); 117 | 118 | name_ = s; 119 | break; 120 | } 121 | case 24: { 122 | 123 | age_ = input.readInt32(); 124 | break; 125 | } 126 | case 32: { 127 | 128 | state_ = input.readInt32(); 129 | break; 130 | } 131 | } 132 | } 133 | } catch (com.google.protobuf.InvalidProtocolBufferException e) { 134 | throw e.setUnfinishedMessage(this); 135 | } catch (java.io.IOException e) { 136 | throw new com.google.protobuf.InvalidProtocolBufferException( 137 | e).setUnfinishedMessage(this); 138 | } finally { 139 | makeExtensionsImmutable(); 140 | } 141 | } 142 | public static final com.google.protobuf.Descriptors.Descriptor 143 | getDescriptor() { 144 | return com.pancm.protobuf.UserInfo.internal_static_UserMsg_descriptor; 145 | } 146 | 147 | protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable 148 | internalGetFieldAccessorTable() { 149 | return com.pancm.protobuf.UserInfo.internal_static_UserMsg_fieldAccessorTable 150 | .ensureFieldAccessorsInitialized( 151 | com.pancm.protobuf.UserInfo.UserMsg.class, com.pancm.protobuf.UserInfo.UserMsg.Builder.class); 152 | } 153 | 154 | public static final int ID_FIELD_NUMBER = 1; 155 | private int id_; 156 | /** 157 | *
158 |      * ID  
159 |      * 
160 | * 161 | * optional int32 id = 1; 162 | */ 163 | public int getId() { 164 | return id_; 165 | } 166 | 167 | public static final int NAME_FIELD_NUMBER = 2; 168 | private volatile java.lang.Object name_; 169 | /** 170 | *
171 |      * 姓名  
172 |      * 
173 | * 174 | * optional string name = 2; 175 | */ 176 | public java.lang.String getName() { 177 | java.lang.Object ref = name_; 178 | if (ref instanceof java.lang.String) { 179 | return (java.lang.String) ref; 180 | } else { 181 | com.google.protobuf.ByteString bs = 182 | (com.google.protobuf.ByteString) ref; 183 | java.lang.String s = bs.toStringUtf8(); 184 | name_ = s; 185 | return s; 186 | } 187 | } 188 | /** 189 | *
190 |      * 姓名  
191 |      * 
192 | * 193 | * optional string name = 2; 194 | */ 195 | public com.google.protobuf.ByteString 196 | getNameBytes() { 197 | java.lang.Object ref = name_; 198 | if (ref instanceof java.lang.String) { 199 | com.google.protobuf.ByteString b = 200 | com.google.protobuf.ByteString.copyFromUtf8( 201 | (java.lang.String) ref); 202 | name_ = b; 203 | return b; 204 | } else { 205 | return (com.google.protobuf.ByteString) ref; 206 | } 207 | } 208 | 209 | public static final int AGE_FIELD_NUMBER = 3; 210 | private int age_; 211 | /** 212 | *
213 |      * 年龄  
214 |      * 
215 | * 216 | * optional int32 age = 3; 217 | */ 218 | public int getAge() { 219 | return age_; 220 | } 221 | 222 | public static final int STATE_FIELD_NUMBER = 4; 223 | private int state_; 224 | /** 225 | *
226 |      * 状态 
227 |      * 
228 | * 229 | * optional int32 state = 4; 230 | */ 231 | public int getState() { 232 | return state_; 233 | } 234 | 235 | private byte memoizedIsInitialized = -1; 236 | public final boolean isInitialized() { 237 | byte isInitialized = memoizedIsInitialized; 238 | if (isInitialized == 1) return true; 239 | if (isInitialized == 0) return false; 240 | 241 | memoizedIsInitialized = 1; 242 | return true; 243 | } 244 | 245 | public void writeTo(com.google.protobuf.CodedOutputStream output) 246 | throws java.io.IOException { 247 | if (id_ != 0) { 248 | output.writeInt32(1, id_); 249 | } 250 | if (!getNameBytes().isEmpty()) { 251 | com.google.protobuf.GeneratedMessageV3.writeString(output, 2, name_); 252 | } 253 | if (age_ != 0) { 254 | output.writeInt32(3, age_); 255 | } 256 | if (state_ != 0) { 257 | output.writeInt32(4, state_); 258 | } 259 | } 260 | 261 | public int getSerializedSize() { 262 | int size = memoizedSize; 263 | if (size != -1) return size; 264 | 265 | size = 0; 266 | if (id_ != 0) { 267 | size += com.google.protobuf.CodedOutputStream 268 | .computeInt32Size(1, id_); 269 | } 270 | if (!getNameBytes().isEmpty()) { 271 | size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, name_); 272 | } 273 | if (age_ != 0) { 274 | size += com.google.protobuf.CodedOutputStream 275 | .computeInt32Size(3, age_); 276 | } 277 | if (state_ != 0) { 278 | size += com.google.protobuf.CodedOutputStream 279 | .computeInt32Size(4, state_); 280 | } 281 | memoizedSize = size; 282 | return size; 283 | } 284 | 285 | private static final long serialVersionUID = 0L; 286 | @java.lang.Override 287 | public boolean equals(final java.lang.Object obj) { 288 | if (obj == this) { 289 | return true; 290 | } 291 | if (!(obj instanceof com.pancm.protobuf.UserInfo.UserMsg)) { 292 | return super.equals(obj); 293 | } 294 | com.pancm.protobuf.UserInfo.UserMsg other = (com.pancm.protobuf.UserInfo.UserMsg) obj; 295 | 296 | boolean result = true; 297 | result = result && (getId() 298 | == other.getId()); 299 | result = result && getName() 300 | .equals(other.getName()); 301 | result = result && (getAge() 302 | == other.getAge()); 303 | result = result && (getState() 304 | == other.getState()); 305 | return result; 306 | } 307 | 308 | @SuppressWarnings("unchecked") 309 | @java.lang.Override 310 | public int hashCode() { 311 | if (memoizedHashCode != 0) { 312 | return memoizedHashCode; 313 | } 314 | int hash = 41; 315 | hash = (19 * hash) + getDescriptorForType().hashCode(); 316 | hash = (37 * hash) + ID_FIELD_NUMBER; 317 | hash = (53 * hash) + getId(); 318 | hash = (37 * hash) + NAME_FIELD_NUMBER; 319 | hash = (53 * hash) + getName().hashCode(); 320 | hash = (37 * hash) + AGE_FIELD_NUMBER; 321 | hash = (53 * hash) + getAge(); 322 | hash = (37 * hash) + STATE_FIELD_NUMBER; 323 | hash = (53 * hash) + getState(); 324 | hash = (29 * hash) + unknownFields.hashCode(); 325 | memoizedHashCode = hash; 326 | return hash; 327 | } 328 | 329 | public static com.pancm.protobuf.UserInfo.UserMsg parseFrom( 330 | com.google.protobuf.ByteString data) 331 | throws com.google.protobuf.InvalidProtocolBufferException { 332 | return PARSER.parseFrom(data); 333 | } 334 | public static com.pancm.protobuf.UserInfo.UserMsg parseFrom( 335 | com.google.protobuf.ByteString data, 336 | com.google.protobuf.ExtensionRegistryLite extensionRegistry) 337 | throws com.google.protobuf.InvalidProtocolBufferException { 338 | return PARSER.parseFrom(data, extensionRegistry); 339 | } 340 | public static com.pancm.protobuf.UserInfo.UserMsg parseFrom(byte[] data) 341 | throws com.google.protobuf.InvalidProtocolBufferException { 342 | return PARSER.parseFrom(data); 343 | } 344 | public static com.pancm.protobuf.UserInfo.UserMsg parseFrom( 345 | byte[] data, 346 | com.google.protobuf.ExtensionRegistryLite extensionRegistry) 347 | throws com.google.protobuf.InvalidProtocolBufferException { 348 | return PARSER.parseFrom(data, extensionRegistry); 349 | } 350 | public static com.pancm.protobuf.UserInfo.UserMsg parseFrom(java.io.InputStream input) 351 | throws java.io.IOException { 352 | return com.google.protobuf.GeneratedMessageV3 353 | .parseWithIOException(PARSER, input); 354 | } 355 | public static com.pancm.protobuf.UserInfo.UserMsg parseFrom( 356 | java.io.InputStream input, 357 | com.google.protobuf.ExtensionRegistryLite extensionRegistry) 358 | throws java.io.IOException { 359 | return com.google.protobuf.GeneratedMessageV3 360 | .parseWithIOException(PARSER, input, extensionRegistry); 361 | } 362 | public static com.pancm.protobuf.UserInfo.UserMsg parseDelimitedFrom(java.io.InputStream input) 363 | throws java.io.IOException { 364 | return com.google.protobuf.GeneratedMessageV3 365 | .parseDelimitedWithIOException(PARSER, input); 366 | } 367 | public static com.pancm.protobuf.UserInfo.UserMsg parseDelimitedFrom( 368 | java.io.InputStream input, 369 | com.google.protobuf.ExtensionRegistryLite extensionRegistry) 370 | throws java.io.IOException { 371 | return com.google.protobuf.GeneratedMessageV3 372 | .parseDelimitedWithIOException(PARSER, input, extensionRegistry); 373 | } 374 | public static com.pancm.protobuf.UserInfo.UserMsg parseFrom( 375 | com.google.protobuf.CodedInputStream input) 376 | throws java.io.IOException { 377 | return com.google.protobuf.GeneratedMessageV3 378 | .parseWithIOException(PARSER, input); 379 | } 380 | public static com.pancm.protobuf.UserInfo.UserMsg parseFrom( 381 | com.google.protobuf.CodedInputStream input, 382 | com.google.protobuf.ExtensionRegistryLite extensionRegistry) 383 | throws java.io.IOException { 384 | return com.google.protobuf.GeneratedMessageV3 385 | .parseWithIOException(PARSER, input, extensionRegistry); 386 | } 387 | 388 | public Builder newBuilderForType() { return newBuilder(); } 389 | public static Builder newBuilder() { 390 | return DEFAULT_INSTANCE.toBuilder(); 391 | } 392 | public static Builder newBuilder(com.pancm.protobuf.UserInfo.UserMsg prototype) { 393 | return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); 394 | } 395 | public Builder toBuilder() { 396 | return this == DEFAULT_INSTANCE 397 | ? new Builder() : new Builder().mergeFrom(this); 398 | } 399 | 400 | @java.lang.Override 401 | protected Builder newBuilderForType( 402 | com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { 403 | Builder builder = new Builder(parent); 404 | return builder; 405 | } 406 | /** 407 | * Protobuf type {@code UserMsg} 408 | */ 409 | public static final class Builder extends 410 | com.google.protobuf.GeneratedMessageV3.Builder implements 411 | // @@protoc_insertion_point(builder_implements:UserMsg) 412 | com.pancm.protobuf.UserInfo.UserMsgOrBuilder { 413 | public static final com.google.protobuf.Descriptors.Descriptor 414 | getDescriptor() { 415 | return com.pancm.protobuf.UserInfo.internal_static_UserMsg_descriptor; 416 | } 417 | 418 | protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable 419 | internalGetFieldAccessorTable() { 420 | return com.pancm.protobuf.UserInfo.internal_static_UserMsg_fieldAccessorTable 421 | .ensureFieldAccessorsInitialized( 422 | com.pancm.protobuf.UserInfo.UserMsg.class, com.pancm.protobuf.UserInfo.UserMsg.Builder.class); 423 | } 424 | 425 | // Construct using com.pancm.protobuf.UserInfo.UserMsg.newBuilder() 426 | private Builder() { 427 | maybeForceBuilderInitialization(); 428 | } 429 | 430 | private Builder( 431 | com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { 432 | super(parent); 433 | maybeForceBuilderInitialization(); 434 | } 435 | private void maybeForceBuilderInitialization() { 436 | if (com.google.protobuf.GeneratedMessageV3 437 | .alwaysUseFieldBuilders) { 438 | } 439 | } 440 | public Builder clear() { 441 | super.clear(); 442 | id_ = 0; 443 | 444 | name_ = ""; 445 | 446 | age_ = 0; 447 | 448 | state_ = 0; 449 | 450 | return this; 451 | } 452 | 453 | public com.google.protobuf.Descriptors.Descriptor 454 | getDescriptorForType() { 455 | return com.pancm.protobuf.UserInfo.internal_static_UserMsg_descriptor; 456 | } 457 | 458 | public com.pancm.protobuf.UserInfo.UserMsg getDefaultInstanceForType() { 459 | return com.pancm.protobuf.UserInfo.UserMsg.getDefaultInstance(); 460 | } 461 | 462 | public com.pancm.protobuf.UserInfo.UserMsg build() { 463 | com.pancm.protobuf.UserInfo.UserMsg result = buildPartial(); 464 | if (!result.isInitialized()) { 465 | throw newUninitializedMessageException(result); 466 | } 467 | return result; 468 | } 469 | 470 | public com.pancm.protobuf.UserInfo.UserMsg buildPartial() { 471 | com.pancm.protobuf.UserInfo.UserMsg result = new com.pancm.protobuf.UserInfo.UserMsg(this); 472 | result.id_ = id_; 473 | result.name_ = name_; 474 | result.age_ = age_; 475 | result.state_ = state_; 476 | onBuilt(); 477 | return result; 478 | } 479 | 480 | public Builder clone() { 481 | return (Builder) super.clone(); 482 | } 483 | public Builder setField( 484 | com.google.protobuf.Descriptors.FieldDescriptor field, 485 | Object value) { 486 | return (Builder) super.setField(field, value); 487 | } 488 | public Builder clearField( 489 | com.google.protobuf.Descriptors.FieldDescriptor field) { 490 | return (Builder) super.clearField(field); 491 | } 492 | public Builder clearOneof( 493 | com.google.protobuf.Descriptors.OneofDescriptor oneof) { 494 | return (Builder) super.clearOneof(oneof); 495 | } 496 | public Builder setRepeatedField( 497 | com.google.protobuf.Descriptors.FieldDescriptor field, 498 | int index, Object value) { 499 | return (Builder) super.setRepeatedField(field, index, value); 500 | } 501 | public Builder addRepeatedField( 502 | com.google.protobuf.Descriptors.FieldDescriptor field, 503 | Object value) { 504 | return (Builder) super.addRepeatedField(field, value); 505 | } 506 | public Builder mergeFrom(com.google.protobuf.Message other) { 507 | if (other instanceof com.pancm.protobuf.UserInfo.UserMsg) { 508 | return mergeFrom((com.pancm.protobuf.UserInfo.UserMsg)other); 509 | } else { 510 | super.mergeFrom(other); 511 | return this; 512 | } 513 | } 514 | 515 | public Builder mergeFrom(com.pancm.protobuf.UserInfo.UserMsg other) { 516 | if (other == com.pancm.protobuf.UserInfo.UserMsg.getDefaultInstance()) return this; 517 | if (other.getId() != 0) { 518 | setId(other.getId()); 519 | } 520 | if (!other.getName().isEmpty()) { 521 | name_ = other.name_; 522 | onChanged(); 523 | } 524 | if (other.getAge() != 0) { 525 | setAge(other.getAge()); 526 | } 527 | if (other.getState() != 0) { 528 | setState(other.getState()); 529 | } 530 | onChanged(); 531 | return this; 532 | } 533 | 534 | public final boolean isInitialized() { 535 | return true; 536 | } 537 | 538 | public Builder mergeFrom( 539 | com.google.protobuf.CodedInputStream input, 540 | com.google.protobuf.ExtensionRegistryLite extensionRegistry) 541 | throws java.io.IOException { 542 | com.pancm.protobuf.UserInfo.UserMsg parsedMessage = null; 543 | try { 544 | parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); 545 | } catch (com.google.protobuf.InvalidProtocolBufferException e) { 546 | parsedMessage = (com.pancm.protobuf.UserInfo.UserMsg) e.getUnfinishedMessage(); 547 | throw e.unwrapIOException(); 548 | } finally { 549 | if (parsedMessage != null) { 550 | mergeFrom(parsedMessage); 551 | } 552 | } 553 | return this; 554 | } 555 | 556 | private int id_ ; 557 | /** 558 | *
559 |        * ID  
560 |        * 
561 | * 562 | * optional int32 id = 1; 563 | */ 564 | public int getId() { 565 | return id_; 566 | } 567 | /** 568 | *
569 |        * ID  
570 |        * 
571 | * 572 | * optional int32 id = 1; 573 | */ 574 | public Builder setId(int value) { 575 | 576 | id_ = value; 577 | onChanged(); 578 | return this; 579 | } 580 | /** 581 | *
582 |        * ID  
583 |        * 
584 | * 585 | * optional int32 id = 1; 586 | */ 587 | public Builder clearId() { 588 | 589 | id_ = 0; 590 | onChanged(); 591 | return this; 592 | } 593 | 594 | private java.lang.Object name_ = ""; 595 | /** 596 | *
597 |        * 姓名  
598 |        * 
599 | * 600 | * optional string name = 2; 601 | */ 602 | public java.lang.String getName() { 603 | java.lang.Object ref = name_; 604 | if (!(ref instanceof java.lang.String)) { 605 | com.google.protobuf.ByteString bs = 606 | (com.google.protobuf.ByteString) ref; 607 | java.lang.String s = bs.toStringUtf8(); 608 | name_ = s; 609 | return s; 610 | } else { 611 | return (java.lang.String) ref; 612 | } 613 | } 614 | /** 615 | *
616 |        * 姓名  
617 |        * 
618 | * 619 | * optional string name = 2; 620 | */ 621 | public com.google.protobuf.ByteString 622 | getNameBytes() { 623 | java.lang.Object ref = name_; 624 | if (ref instanceof String) { 625 | com.google.protobuf.ByteString b = 626 | com.google.protobuf.ByteString.copyFromUtf8( 627 | (java.lang.String) ref); 628 | name_ = b; 629 | return b; 630 | } else { 631 | return (com.google.protobuf.ByteString) ref; 632 | } 633 | } 634 | /** 635 | *
636 |        * 姓名  
637 |        * 
638 | * 639 | * optional string name = 2; 640 | */ 641 | public Builder setName( 642 | java.lang.String value) { 643 | if (value == null) { 644 | throw new NullPointerException(); 645 | } 646 | 647 | name_ = value; 648 | onChanged(); 649 | return this; 650 | } 651 | /** 652 | *
653 |        * 姓名  
654 |        * 
655 | * 656 | * optional string name = 2; 657 | */ 658 | public Builder clearName() { 659 | 660 | name_ = getDefaultInstance().getName(); 661 | onChanged(); 662 | return this; 663 | } 664 | /** 665 | *
666 |        * 姓名  
667 |        * 
668 | * 669 | * optional string name = 2; 670 | */ 671 | public Builder setNameBytes( 672 | com.google.protobuf.ByteString value) { 673 | if (value == null) { 674 | throw new NullPointerException(); 675 | } 676 | checkByteStringIsUtf8(value); 677 | 678 | name_ = value; 679 | onChanged(); 680 | return this; 681 | } 682 | 683 | private int age_ ; 684 | /** 685 | *
686 |        * 年龄  
687 |        * 
688 | * 689 | * optional int32 age = 3; 690 | */ 691 | public int getAge() { 692 | return age_; 693 | } 694 | /** 695 | *
696 |        * 年龄  
697 |        * 
698 | * 699 | * optional int32 age = 3; 700 | */ 701 | public Builder setAge(int value) { 702 | 703 | age_ = value; 704 | onChanged(); 705 | return this; 706 | } 707 | /** 708 | *
709 |        * 年龄  
710 |        * 
711 | * 712 | * optional int32 age = 3; 713 | */ 714 | public Builder clearAge() { 715 | 716 | age_ = 0; 717 | onChanged(); 718 | return this; 719 | } 720 | 721 | private int state_ ; 722 | /** 723 | *
724 |        * 状态 
725 |        * 
726 | * 727 | * optional int32 state = 4; 728 | */ 729 | public int getState() { 730 | return state_; 731 | } 732 | /** 733 | *
734 |        * 状态 
735 |        * 
736 | * 737 | * optional int32 state = 4; 738 | */ 739 | public Builder setState(int value) { 740 | 741 | state_ = value; 742 | onChanged(); 743 | return this; 744 | } 745 | /** 746 | *
747 |        * 状态 
748 |        * 
749 | * 750 | * optional int32 state = 4; 751 | */ 752 | public Builder clearState() { 753 | 754 | state_ = 0; 755 | onChanged(); 756 | return this; 757 | } 758 | public final Builder setUnknownFields( 759 | final com.google.protobuf.UnknownFieldSet unknownFields) { 760 | return this; 761 | } 762 | 763 | public final Builder mergeUnknownFields( 764 | final com.google.protobuf.UnknownFieldSet unknownFields) { 765 | return this; 766 | } 767 | 768 | 769 | // @@protoc_insertion_point(builder_scope:UserMsg) 770 | } 771 | 772 | // @@protoc_insertion_point(class_scope:UserMsg) 773 | private static final com.pancm.protobuf.UserInfo.UserMsg DEFAULT_INSTANCE; 774 | static { 775 | DEFAULT_INSTANCE = new com.pancm.protobuf.UserInfo.UserMsg(); 776 | } 777 | 778 | public static com.pancm.protobuf.UserInfo.UserMsg getDefaultInstance() { 779 | return DEFAULT_INSTANCE; 780 | } 781 | 782 | private static final com.google.protobuf.Parser 783 | PARSER = new com.google.protobuf.AbstractParser() { 784 | public UserMsg parsePartialFrom( 785 | com.google.protobuf.CodedInputStream input, 786 | com.google.protobuf.ExtensionRegistryLite extensionRegistry) 787 | throws com.google.protobuf.InvalidProtocolBufferException { 788 | return new UserMsg(input, extensionRegistry); 789 | } 790 | }; 791 | 792 | public static com.google.protobuf.Parser parser() { 793 | return PARSER; 794 | } 795 | 796 | @java.lang.Override 797 | public com.google.protobuf.Parser getParserForType() { 798 | return PARSER; 799 | } 800 | 801 | public com.pancm.protobuf.UserInfo.UserMsg getDefaultInstanceForType() { 802 | return DEFAULT_INSTANCE; 803 | } 804 | 805 | } 806 | 807 | private static final com.google.protobuf.Descriptors.Descriptor 808 | internal_static_UserMsg_descriptor; 809 | private static final 810 | com.google.protobuf.GeneratedMessageV3.FieldAccessorTable 811 | internal_static_UserMsg_fieldAccessorTable; 812 | 813 | public static com.google.protobuf.Descriptors.FileDescriptor 814 | getDescriptor() { 815 | return descriptor; 816 | } 817 | private static com.google.protobuf.Descriptors.FileDescriptor 818 | descriptor; 819 | static { 820 | java.lang.String[] descriptorData = { 821 | "\n\nUser.proto\"?\n\007UserMsg\022\n\n\002id\030\001 \001(\005\022\014\n\004n" + 822 | "ame\030\002 \001(\t\022\013\n\003age\030\003 \001(\005\022\r\n\005state\030\004 \001(\005B\036\n" + 823 | "\022com.pancm.protobufB\010UserInfob\006proto3" 824 | }; 825 | com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = 826 | new com.google.protobuf.Descriptors.FileDescriptor. InternalDescriptorAssigner() { 827 | public com.google.protobuf.ExtensionRegistry assignDescriptors( 828 | com.google.protobuf.Descriptors.FileDescriptor root) { 829 | descriptor = root; 830 | return null; 831 | } 832 | }; 833 | com.google.protobuf.Descriptors.FileDescriptor 834 | .internalBuildGeneratedFileFrom(descriptorData, 835 | new com.google.protobuf.Descriptors.FileDescriptor[] { 836 | }, assigner); 837 | internal_static_UserMsg_descriptor = 838 | getDescriptor().getMessageTypes().get(0); 839 | internal_static_UserMsg_fieldAccessorTable = new 840 | com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( 841 | internal_static_UserMsg_descriptor, 842 | new java.lang.String[] { "Id", "Name", "Age", "State", }); 843 | } 844 | 845 | // @@protoc_insertion_point(outer_class_scope) 846 | } 847 | -------------------------------------------------------------------------------- /Netty-protobuf/src/main/java/com/pancm/protobuf/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * @Title: package-info 3 | * @Description: 4 | * protobuf相关类 5 | * @Version:1.0.0 6 | * @author pancm 7 | * @date 2018年7月11日 8 | */ 9 | package com.pancm.protobuf; -------------------------------------------------------------------------------- /Netty-protobuf/src/main/java/com/pancm/server/NettyServer.java: -------------------------------------------------------------------------------- 1 | package com.pancm.server; 2 | 3 | import io.netty.bootstrap.ServerBootstrap; 4 | import io.netty.channel.ChannelFuture; 5 | import io.netty.channel.EventLoopGroup; 6 | import io.netty.channel.nio.NioEventLoopGroup; 7 | import io.netty.channel.socket.nio.NioServerSocketChannel; 8 | 9 | /** 10 | * 11 | * @Title: NettyServer 12 | * @Description: Netty服务端 13 | * @Version:1.0.0 14 | * @author pancm 15 | * @date 2017年10月8日 16 | */ 17 | public class NettyServer { 18 | private static final int port = 9876; // 设置服务端端口 19 | private static EventLoopGroup boss = new NioEventLoopGroup(); // 通过nio方式来接收连接和处理连接 20 | private static EventLoopGroup work = new NioEventLoopGroup(); // 通过nio方式来接收连接和处理连接 21 | private static ServerBootstrap b = new ServerBootstrap(); 22 | 23 | public void run() { 24 | try { 25 | b.group(boss, work); 26 | b.channel(NioServerSocketChannel.class); 27 | b.childHandler(new NettyServerFilter()); // 设置过滤器 28 | // 服务器绑定端口监听 29 | ChannelFuture f = b.bind(port).sync(); 30 | System.out.println("服务端启动成功,端口是:" + port); 31 | // 监听服务器关闭监听 32 | f.channel().closeFuture().sync(); 33 | } catch (InterruptedException e) { 34 | e.printStackTrace(); 35 | } finally { 36 | // 关闭EventLoopGroup,释放掉所有资源包括创建的线程 37 | work.shutdownGracefully(); 38 | boss.shutdownGracefully(); 39 | } 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /Netty-protobuf/src/main/java/com/pancm/server/NettyServerApp.java: -------------------------------------------------------------------------------- 1 | package com.pancm.server; 2 | 3 | /** 4 | * @Title: NettyClientApp 5 | * @Description: Netty 服务端主程序 6 | * @Version:1.0.0 7 | * @author pancm 8 | * @date 2018年7月11日 9 | */ 10 | public class NettyServerApp { 11 | 12 | /** 13 | * @param args 14 | */ 15 | public static void main(String[] args) { 16 | NettyServer nettyServer=new NettyServer(); 17 | nettyServer.run(); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /Netty-protobuf/src/main/java/com/pancm/server/NettyServerFilter.java: -------------------------------------------------------------------------------- 1 | package com.pancm.server; 2 | 3 | import java.util.concurrent.TimeUnit; 4 | 5 | import com.pancm.protobuf.UserInfo.UserMsg; 6 | 7 | import io.netty.channel.ChannelInitializer; 8 | import io.netty.channel.ChannelPipeline; 9 | import io.netty.channel.socket.SocketChannel; 10 | import io.netty.handler.codec.protobuf.ProtobufDecoder; 11 | import io.netty.handler.codec.protobuf.ProtobufEncoder; 12 | import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder; 13 | import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender; 14 | import io.netty.handler.timeout.IdleStateHandler; 15 | 16 | /** 17 | * 18 | * @Title: HelloServerInitializer 19 | * @Description: Netty 服务端过滤器 20 | * @Version:1.0.0 21 | * @author pancm 22 | * @date 2017年10月8日 23 | */ 24 | public class NettyServerFilter extends ChannelInitializer { 25 | 26 | @Override 27 | protected void initChannel(SocketChannel ch) throws Exception { 28 | ChannelPipeline ph = ch.pipeline(); 29 | 30 | //入参说明: 读超时时间、写超时时间、所有类型的超时时间、时间格式 31 | ph.addLast(new IdleStateHandler(5, 0, 0, TimeUnit.SECONDS)); 32 | // 解码和编码,应和客户端一致 33 | //传输的协议 Protobuf 34 | ph.addLast(new ProtobufVarint32FrameDecoder()); 35 | ph.addLast(new ProtobufDecoder(UserMsg.getDefaultInstance())); 36 | ph.addLast(new ProtobufVarint32LengthFieldPrepender()); 37 | ph.addLast(new ProtobufEncoder()); 38 | 39 | //业务逻辑实现类 40 | ph.addLast("nettyServerHandler", new NettyServerHandler()); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Netty-protobuf/src/main/java/com/pancm/server/NettyServerHandler.java: -------------------------------------------------------------------------------- 1 | package com.pancm.server; 2 | 3 | import com.pancm.protobuf.UserInfo; 4 | import com.pancm.protobuf.UserInfo.UserMsg; 5 | 6 | import io.netty.channel.ChannelHandlerContext; 7 | import io.netty.channel.ChannelInboundHandlerAdapter; 8 | import io.netty.handler.timeout.IdleState; 9 | import io.netty.handler.timeout.IdleStateEvent; 10 | import io.netty.util.ReferenceCountUtil; 11 | 12 | /** 13 | * 14 | * @Title: NettyServerHandler 15 | * @Description: 服务端业务逻辑 16 | * @Version:1.0.0 17 | * @author pancm 18 | * @date 2017年10月8日 19 | */ 20 | public class NettyServerHandler extends ChannelInboundHandlerAdapter { 21 | 22 | /** 空闲次数 */ 23 | private int idle_count = 1; 24 | /** 发送次数 */ 25 | private int count = 1; 26 | 27 | 28 | /** 29 | * 建立连接时,发送一条消息 30 | */ 31 | @Override 32 | public void channelActive(ChannelHandlerContext ctx) throws Exception { 33 | System.out.println("连接的客户端地址:" + ctx.channel().remoteAddress()); 34 | UserInfo.UserMsg userMsg = UserInfo.UserMsg.newBuilder().setId(1).setAge(18).setName("xuwujing").setState(0) 35 | .build(); 36 | ctx.writeAndFlush(userMsg); 37 | super.channelActive(ctx); 38 | } 39 | 40 | /** 41 | * 超时处理 如果5秒没有接受客户端的心跳,就触发; 如果超过两次,则直接关闭; 42 | */ 43 | @Override 44 | public void userEventTriggered(ChannelHandlerContext ctx, Object obj) throws Exception { 45 | if (obj instanceof IdleStateEvent) { 46 | IdleStateEvent event = (IdleStateEvent) obj; 47 | if (IdleState.READER_IDLE.equals(event.state())) { // 如果读通道处于空闲状态,说明没有接收到心跳命令 48 | System.out.println("已经5秒没有接收到客户端的信息了"); 49 | if (idle_count > 1) { 50 | System.out.println("关闭这个不活跃的channel"); 51 | ctx.channel().close(); 52 | } 53 | idle_count++; 54 | } 55 | } else { 56 | super.userEventTriggered(ctx, obj); 57 | } 58 | } 59 | 60 | /** 61 | * 业务逻辑处理 62 | */ 63 | @Override 64 | public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 65 | System.out.println("第" + count + "次" + ",服务端接受的消息:" + msg); 66 | try { 67 | // 如果是protobuf类型的数据 68 | if (msg instanceof UserMsg) { 69 | UserInfo.UserMsg userState = (UserInfo.UserMsg) msg; 70 | if (userState.getState() == 1) { 71 | System.out.println("客户端业务处理成功!"); 72 | } else if(userState.getState() == 2){ 73 | System.out.println("接受到客户端发送的心跳!"); 74 | }else{ 75 | System.out.println("未知命令!"); 76 | } 77 | } else { 78 | System.out.println("未知数据!" + msg); 79 | return; 80 | } 81 | } catch (Exception e) { 82 | e.printStackTrace(); 83 | } finally { 84 | ReferenceCountUtil.release(msg); 85 | } 86 | count++; 87 | } 88 | 89 | /** 90 | * 异常处理 91 | */ 92 | @Override 93 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 94 | cause.printStackTrace(); 95 | ctx.close(); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /Netty-protobuf/src/main/java/com/pancm/server/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * @Title: package-info 3 | * @Description: Netty 服务端 4 | * @Version:1.0.0 5 | * @author pancm 6 | * @date 2018年7月9日 7 | */ 8 | package com.pancm.server; -------------------------------------------------------------------------------- /Netty-reconnect/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /Netty-reconnect/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | 1.0.0 6 | Netty-reconnect 7 | 0.0.1-SNAPSHOT 8 | jar 9 | 10 | Netty-reconnect 11 | http://maven.apache.org 12 | 13 | 14 | UTF-8 15 | 1.7 16 | 4.1.17.Final 17 | 18 | 19 | 20 | 21 | 22 | junit 23 | junit 24 | 3.8.1 25 | test 26 | 27 | 28 | 29 | io.netty 30 | netty-all 31 | ${netty.version} 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /Netty-reconnect/src/main/java/com/pancm/netty/App.java: -------------------------------------------------------------------------------- 1 | package com.pancm.netty; 2 | 3 | /** 4 | * Hello world! 5 | * 6 | */ 7 | public class App 8 | { 9 | public static void main( String[] args ) 10 | { 11 | System.out.println( "Hello World!" ); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Netty-reconnect/src/main/java/com/pancm/netty/client/NettyClient.java: -------------------------------------------------------------------------------- 1 | package com.pancm.netty.client; 2 | 3 | import java.util.concurrent.TimeUnit; 4 | 5 | import io.netty.bootstrap.Bootstrap; 6 | import io.netty.channel.ChannelFuture; 7 | import io.netty.channel.ChannelOption; 8 | import io.netty.channel.EventLoop; 9 | import io.netty.channel.EventLoopGroup; 10 | import io.netty.channel.nio.NioEventLoopGroup; 11 | import io.netty.channel.socket.nio.NioSocketChannel; 12 | 13 | /** 14 | * 15 | * @Title: NettyClient 16 | * @Description: Netty客户端 心跳测试 17 | * @Version:1.0.0 18 | * @author pancm 19 | * @date 2017年10月8日 20 | */ 21 | public class NettyClient { 22 | 23 | public String host = "127.0.0.1"; // ip地址 24 | public int port = 9876; // 端口 25 | // 通过nio方式来接收连接和处理连接 26 | private EventLoopGroup group = new NioEventLoopGroup(); 27 | public static NettyClient nettyClient = new NettyClient(); 28 | 29 | /**唯一标记 */ 30 | private boolean initFalg=true; 31 | 32 | public static void main(String[] args) { 33 | nettyClient.run(); 34 | } 35 | 36 | /** 37 | * Netty创建全部都是实现自AbstractBootstrap。 客户端的是Bootstrap,服务端的则是 ServerBootstrap。 38 | **/ 39 | public void run() { 40 | doConnect(new Bootstrap(), group); 41 | } 42 | 43 | /** 44 | * 重连 45 | */ 46 | public void doConnect(Bootstrap bootstrap, EventLoopGroup eventLoopGroup) { 47 | ChannelFuture f = null; 48 | try { 49 | if (bootstrap != null) { 50 | bootstrap.group(eventLoopGroup); 51 | bootstrap.channel(NioSocketChannel.class); 52 | bootstrap.option(ChannelOption.SO_KEEPALIVE, true); 53 | bootstrap.handler(new NettyClientFilter()); 54 | bootstrap.remoteAddress(host, port); 55 | f = bootstrap.connect().addListener((ChannelFuture futureListener) -> { 56 | final EventLoop eventLoop = futureListener.channel().eventLoop(); 57 | if (!futureListener.isSuccess()) { 58 | System.out.println("与服务端断开连接!在10s之后准备尝试重连!"); 59 | eventLoop.schedule(() -> doConnect(new Bootstrap(), eventLoop), 10, TimeUnit.SECONDS); 60 | } 61 | }); 62 | if(initFalg){ 63 | System.out.println("Netty客户端启动成功!"); 64 | initFalg=false; 65 | } 66 | // 阻塞 67 | f.channel().closeFuture().sync(); 68 | } 69 | } catch (Exception e) { 70 | System.out.println("客户端连接失败!"+e.getMessage()); 71 | } 72 | 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Netty-reconnect/src/main/java/com/pancm/netty/client/NettyClientFilter.java: -------------------------------------------------------------------------------- 1 | package com.pancm.netty.client; 2 | 3 | import io.netty.channel.ChannelInitializer; 4 | import io.netty.channel.ChannelPipeline; 5 | import io.netty.channel.socket.SocketChannel; 6 | import io.netty.handler.codec.string.StringDecoder; 7 | import io.netty.handler.codec.string.StringEncoder; 8 | import io.netty.handler.timeout.IdleStateHandler; 9 | 10 | import java.util.concurrent.TimeUnit; 11 | /** 12 | * 13 | * Title: NettyClientFilter 14 | * Description: Netty客户端 过滤器 15 | * Version:1.0.0 16 | * @author pancm 17 | * @date 2017年10月8日 18 | */ 19 | public class NettyClientFilter extends ChannelInitializer { 20 | 21 | @Override 22 | protected void initChannel(SocketChannel ch) throws Exception { 23 | ChannelPipeline ph = ch.pipeline(); 24 | /* 25 | * 解码和编码,应和服务端一致 26 | * */ 27 | // ph.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter())); 28 | //入参说明: 读超时时间、写超时时间、所有类型的超时时间、时间格式 29 | //因为服务端设置的超时时间是5秒,所以设置4秒 30 | ph.addLast( new IdleStateHandler(0, 4, 0, TimeUnit.SECONDS)); 31 | ph.addLast("decoder", new StringDecoder()); 32 | ph.addLast("encoder", new StringEncoder()); 33 | ph.addLast("handler", new NettyClientHandler()); //客户端的逻辑 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Netty-reconnect/src/main/java/com/pancm/netty/client/NettyClientHandler.java: -------------------------------------------------------------------------------- 1 | package com.pancm.netty.client; 2 | 3 | import io.netty.bootstrap.Bootstrap; 4 | import io.netty.buffer.ByteBuf; 5 | import io.netty.buffer.Unpooled; 6 | import io.netty.channel.ChannelHandlerContext; 7 | import io.netty.channel.ChannelInboundHandlerAdapter; 8 | import io.netty.channel.EventLoop; 9 | import io.netty.handler.timeout.IdleState; 10 | import io.netty.handler.timeout.IdleStateEvent; 11 | import io.netty.util.CharsetUtil; 12 | 13 | import java.util.Date; 14 | 15 | /** 16 | * 17 | * Title: NettyClientHandler 18 | * Description: 客户端业务逻辑实现 19 | * Version:1.0.0 20 | * @author pancm 21 | * @date 2017年10月8日 22 | */ 23 | public class NettyClientHandler extends ChannelInboundHandlerAdapter { 24 | /** 客户端请求的心跳命令 */ 25 | private static final ByteBuf HEARTBEAT_SEQUENCE = Unpooled.unreleasableBuffer(Unpooled.copiedBuffer("hb_request", 26 | CharsetUtil.UTF_8)); 27 | 28 | /** 空闲次数 */ 29 | private int idle_count = 1; 30 | 31 | /** 发送次数 */ 32 | private int count = 1; 33 | 34 | /**循环次数 */ 35 | private int fcount = 1; 36 | 37 | 38 | /** 39 | * 建立连接时 40 | */ 41 | @Override 42 | public void channelActive(ChannelHandlerContext ctx) throws Exception { 43 | System.out.println("建立连接时:"+new Date()); 44 | ctx.fireChannelActive(); 45 | } 46 | 47 | /** 48 | * 关闭连接时 49 | */ 50 | @Override 51 | public void channelInactive(ChannelHandlerContext ctx) throws Exception { 52 | System.out.println("关闭连接时:"+new Date()); 53 | final EventLoop eventLoop = ctx.channel().eventLoop(); 54 | NettyClient.nettyClient.doConnect(new Bootstrap(), eventLoop); 55 | super.channelInactive(ctx); 56 | } 57 | 58 | /** 59 | * 心跳请求处理 60 | * 每4秒发送一次心跳请求; 61 | * 62 | */ 63 | @Override 64 | public void userEventTriggered(ChannelHandlerContext ctx, Object obj) throws Exception { 65 | System.out.println("循环请求的时间:"+new Date()+",次数"+fcount); 66 | if (obj instanceof IdleStateEvent) { 67 | IdleStateEvent event = (IdleStateEvent) obj; 68 | if (IdleState.WRITER_IDLE.equals(event.state())) { //如果写通道处于空闲状态,就发送心跳命令 69 | if(idle_count <= 2){ //设置发送次数 70 | idle_count++; 71 | ctx.channel().writeAndFlush(HEARTBEAT_SEQUENCE.duplicate()); 72 | }else{ 73 | System.out.println("不再发送心跳请求了!"); 74 | } 75 | fcount++; 76 | } 77 | } 78 | } 79 | 80 | /** 81 | * 业务逻辑处理 82 | */ 83 | @Override 84 | public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 85 | System.out.println("第"+count+"次"+",客户端接受的消息:"+msg); 86 | count++; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /Netty-reconnect/src/main/java/com/pancm/netty/client/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * Title: package-info 6 | * Description: 7 | * Version:1.0.0 8 | * @author pancm 9 | * @date 2018年1月27日 10 | */ 11 | package com.pancm.netty.client; -------------------------------------------------------------------------------- /Netty-reconnect/src/main/java/com/pancm/netty/server/NettyServer.java: -------------------------------------------------------------------------------- 1 | package com.pancm.netty.server; 2 | 3 | import io.netty.bootstrap.ServerBootstrap; 4 | import io.netty.channel.ChannelFuture; 5 | import io.netty.channel.EventLoopGroup; 6 | import io.netty.channel.nio.NioEventLoopGroup; 7 | import io.netty.channel.socket.nio.NioServerSocketChannel; 8 | 9 | /** 10 | * 11 | * @Title: NettyServer 12 | * @Description: Netty服务端 13 | * @Version:1.0.0 14 | * @author pancm 15 | * @date 2017年10月8日 16 | */ 17 | public class NettyServer { 18 | private static final int port = 9876; //设置服务端端口 19 | private static EventLoopGroup boss = new NioEventLoopGroup(); // 通过nio方式来接收连接和处理连接 20 | private static EventLoopGroup work = new NioEventLoopGroup(); // 通过nio方式来接收连接和处理连接 21 | private static ServerBootstrap b = new ServerBootstrap(); 22 | 23 | /** 24 | * Netty创建全部都是实现自AbstractBootstrap。 25 | * 客户端的是Bootstrap,服务端的则是 ServerBootstrap。 26 | **/ 27 | public static void main(String[] args){ 28 | try { 29 | b.group(boss,work); 30 | b.channel(NioServerSocketChannel.class); 31 | b.childHandler(new NettyServerFilter()); //设置过滤器 32 | // 服务器绑定端口监听 33 | ChannelFuture f = b.bind(port).sync(); 34 | System.out.println("服务端启动成功,端口是:"+port); 35 | // 监听服务器关闭监听 36 | f.channel().closeFuture().sync(); 37 | }catch(InterruptedException e){ 38 | e.printStackTrace(); 39 | } finally { 40 | //关闭EventLoopGroup,释放掉所有资源包括创建的线程 41 | work.shutdownGracefully(); 42 | boss.shutdownGracefully(); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Netty-reconnect/src/main/java/com/pancm/netty/server/NettyServerFilter.java: -------------------------------------------------------------------------------- 1 | package com.pancm.netty.server; 2 | 3 | import io.netty.channel.ChannelInitializer; 4 | import io.netty.channel.ChannelPipeline; 5 | import io.netty.channel.socket.SocketChannel; 6 | import io.netty.handler.codec.string.StringDecoder; 7 | import io.netty.handler.codec.string.StringEncoder; 8 | import io.netty.handler.timeout.IdleStateHandler; 9 | 10 | import java.util.concurrent.TimeUnit; 11 | 12 | /** 13 | * 14 | * Title: HelloServerInitializer 15 | * Description: Netty 服务端过滤器 16 | * Version:1.0.0 17 | * @author pancm 18 | * @date 2017年10月8日 19 | */ 20 | public class NettyServerFilter extends ChannelInitializer { 21 | 22 | @Override 23 | protected void initChannel(SocketChannel ch) throws Exception { 24 | ChannelPipeline ph = ch.pipeline(); 25 | // 以("\n")为结尾分割的 解码器 26 | // ph.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter())); 27 | // 解码和编码,应和客户端一致 28 | //入参说明: 读超时时间、写超时时间、所有类型的超时时间、时间格式 29 | ph.addLast(new IdleStateHandler(5, 0, 0, TimeUnit.SECONDS)); 30 | ph.addLast("decoder", new StringDecoder()); 31 | ph.addLast("encoder", new StringEncoder()); 32 | ph.addLast("handler", new NettyServerHandler());// 服务端业务逻辑 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Netty-reconnect/src/main/java/com/pancm/netty/server/NettyServerHandler.java: -------------------------------------------------------------------------------- 1 | package com.pancm.netty.server; 2 | 3 | import io.netty.channel.ChannelHandlerContext; 4 | import io.netty.channel.ChannelInboundHandlerAdapter; 5 | import io.netty.handler.timeout.IdleState; 6 | import io.netty.handler.timeout.IdleStateEvent; 7 | 8 | /** 9 | * 10 | * Title: HelloServerHandler 11 | * Description: 服务端业务逻辑 12 | * Version:1.0.0 13 | * @author pancm 14 | * @date 2017年10月8日 15 | */ 16 | public class NettyServerHandler extends ChannelInboundHandlerAdapter { 17 | 18 | /** 空闲次数 */ 19 | private int idle_count =1; 20 | /** 发送次数 */ 21 | private int count = 1; 22 | 23 | /** 24 | * 超时处理 25 | * 如果5秒没有接受客户端的心跳,就触发; 26 | * 如果超过两次,则直接关闭; 27 | */ 28 | @Override 29 | public void userEventTriggered(ChannelHandlerContext ctx, Object obj) throws Exception { 30 | if (obj instanceof IdleStateEvent) { 31 | IdleStateEvent event = (IdleStateEvent) obj; 32 | if (IdleState.READER_IDLE.equals(event.state())) { //如果读通道处于空闲状态,说明没有接收到心跳命令 33 | System.out.println("已经5秒没有接收到客户端的信息了"); 34 | if (idle_count > 1) { 35 | System.out.println("关闭这个不活跃的channel"); 36 | ctx.channel().close(); 37 | } 38 | idle_count++; 39 | } 40 | } else { 41 | super.userEventTriggered(ctx, obj); 42 | } 43 | } 44 | 45 | /** 46 | * 业务逻辑处理 47 | */ 48 | @Override 49 | public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 50 | System.out.println("第"+count+"次"+",服务端接受的消息:"+msg); 51 | String message = (String) msg; 52 | if ("hb_request".equals(message)) { //如果是心跳命令,则发送给客户端;否则什么都不做 53 | ctx.write("服务端成功收到心跳信息"); 54 | ctx.flush(); 55 | } 56 | count++; 57 | } 58 | 59 | /** 60 | * 异常处理 61 | */ 62 | @Override 63 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 64 | cause.printStackTrace(); 65 | ctx.close(); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /Netty-reconnect/src/main/java/com/pancm/netty/server/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * Title: package-info 6 | * Description: 7 | * Version:1.0.0 8 | * @author pancm 9 | * @date 2018年1月27日 10 | */ 11 | package com.pancm.netty.server; -------------------------------------------------------------------------------- /Netty-reconnect/src/test/java/com/pancm/netty/AppTest.java: -------------------------------------------------------------------------------- 1 | package com.pancm.netty; 2 | 3 | import junit.framework.Test; 4 | import junit.framework.TestCase; 5 | import junit.framework.TestSuite; 6 | 7 | /** 8 | * Unit test for simple App. 9 | */ 10 | public class AppTest 11 | extends TestCase 12 | { 13 | /** 14 | * Create the test case 15 | * 16 | * @param testName name of the test case 17 | */ 18 | public AppTest( String testName ) 19 | { 20 | super( testName ); 21 | } 22 | 23 | /** 24 | * @return the suite of tests being tested 25 | */ 26 | public static Test suite() 27 | { 28 | return new TestSuite( AppTest.class ); 29 | } 30 | 31 | /** 32 | * Rigourous Test :-) 33 | */ 34 | public void testApp() 35 | { 36 | assertTrue( true ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Netty-slidingWindow/pom.xml: -------------------------------------------------------------------------------- 1 | 4 | 4.0.0 5 | 6 | 1.0.0 7 | Netty-slidingWindow 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | Netty-slidingWindow 12 | http://maven.apache.org 13 | 14 | 15 | UTF-8 16 | 1.8 17 | 4.1.17.Final 18 | 19 | 20 | 21 | 22 | 23 | junit 24 | junit 25 | 4.13.1 26 | test 27 | 28 | 29 | 30 | io.netty 31 | netty-all 32 | ${netty.version} 33 | 34 | 35 | com.cloudhopper 36 | ch-commons-util 37 | 6.0.4 38 | 39 | 40 | com.alibaba 41 | fastjson 42 | 1.2.54 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /Netty-slidingWindow/src/main/java/com/pancm/netty/App.java: -------------------------------------------------------------------------------- 1 | package com.pancm.netty; 2 | 3 | import com.pancm.netty.client.NettyClient; 4 | import com.pancm.netty.server.NettyServer; 5 | 6 | /** 7 | * Hello world! 8 | * 9 | */ 10 | public class App 11 | { 12 | public static void main( String[] args ) 13 | { 14 | 15 | //启动服务端和客户端 16 | new Thread(() -> new NettyServer().run()).start(); 17 | new Thread(() -> new NettyClient().run()).start(); 18 | 19 | 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Netty-slidingWindow/src/main/java/com/pancm/netty/client/NettyClient.java: -------------------------------------------------------------------------------- 1 | package com.pancm.netty.client; 2 | 3 | import java.util.concurrent.TimeUnit; 4 | 5 | import io.netty.bootstrap.Bootstrap; 6 | import io.netty.channel.ChannelFuture; 7 | import io.netty.channel.ChannelOption; 8 | import io.netty.channel.EventLoop; 9 | import io.netty.channel.EventLoopGroup; 10 | import io.netty.channel.nio.NioEventLoopGroup; 11 | import io.netty.channel.socket.nio.NioSocketChannel; 12 | 13 | /** 14 | * 15 | * @Title: NettyClient 16 | * @Description: Netty客户端 心跳测试 17 | * @Version:1.0.0 18 | * @author pancm 19 | * @date 2017年10月8日 20 | */ 21 | public class NettyClient { 22 | 23 | public String host = "127.0.0.1"; // ip地址 24 | public int port = 9876; // 端口 25 | // 通过nio方式来接收连接和处理连接 26 | private EventLoopGroup group = new NioEventLoopGroup(); 27 | public static NettyClient nettyClient = new NettyClient(); 28 | 29 | /**唯一标记 */ 30 | private boolean initFalg=true; 31 | 32 | public static void main(String[] args) { 33 | nettyClient.run(); 34 | } 35 | 36 | /** 37 | * Netty创建全部都是实现自AbstractBootstrap。 客户端的是Bootstrap,服务端的则是 ServerBootstrap。 38 | **/ 39 | public void run() { 40 | doConnect(new Bootstrap(), group); 41 | } 42 | 43 | /** 44 | * 重连 45 | */ 46 | public void doConnect(Bootstrap bootstrap, EventLoopGroup eventLoopGroup) { 47 | ChannelFuture f = null; 48 | try { 49 | if (bootstrap != null) { 50 | bootstrap.group(eventLoopGroup); 51 | bootstrap.channel(NioSocketChannel.class); 52 | bootstrap.option(ChannelOption.SO_KEEPALIVE, true); 53 | bootstrap.handler(new NettyClientFilter()); 54 | bootstrap.remoteAddress(host, port); 55 | f = bootstrap.connect().addListener((ChannelFuture futureListener) -> { 56 | final EventLoop eventLoop = futureListener.channel().eventLoop(); 57 | if (!futureListener.isSuccess()) { 58 | System.out.println("与服务端断开连接!在10s之后准备尝试重连!"); 59 | eventLoop.schedule(() -> doConnect(new Bootstrap(), eventLoop), 10, TimeUnit.SECONDS); 60 | } 61 | }); 62 | if(initFalg){ 63 | System.out.println("Netty客户端启动成功!"); 64 | initFalg=false; 65 | } 66 | // 阻塞 67 | f.channel().closeFuture().sync(); 68 | } 69 | } catch (Exception e) { 70 | System.out.println("客户端连接失败!"+e.getMessage()); 71 | } 72 | 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Netty-slidingWindow/src/main/java/com/pancm/netty/client/NettyClientFilter.java: -------------------------------------------------------------------------------- 1 | package com.pancm.netty.client; 2 | 3 | import io.netty.channel.ChannelInitializer; 4 | import io.netty.channel.ChannelPipeline; 5 | import io.netty.channel.socket.SocketChannel; 6 | import io.netty.handler.codec.http.HttpObjectAggregator; 7 | import io.netty.handler.codec.string.StringDecoder; 8 | import io.netty.handler.codec.string.StringEncoder; 9 | import io.netty.handler.timeout.IdleStateHandler; 10 | 11 | import java.util.concurrent.TimeUnit; 12 | /** 13 | * 14 | * @Title: NettyClientFilter 15 | * @Description: Netty客户端 过滤器 16 | * @Version:1.0.0 17 | * @author pancm 18 | * @date 2017年10月8日 19 | */ 20 | public class NettyClientFilter extends ChannelInitializer { 21 | 22 | @Override 23 | protected void initChannel(SocketChannel ch) throws Exception { 24 | ChannelPipeline ph = ch.pipeline(); 25 | /* 26 | * 解码和编码,应和服务端一致 27 | * */ 28 | // ph.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter())); 29 | //入参说明: 读超时时间、写超时时间、所有类型的超时时间、时间格式 30 | //因为服务端设置的超时时间是5秒,所以设置4秒 31 | ph.addLast( new IdleStateHandler(0, 4, 0, TimeUnit.SECONDS)); 32 | ph.addLast("decoder", new StringDecoder()); 33 | ph.addLast("encoder", new StringEncoder()); 34 | ph.addLast("aggregator", new HttpObjectAggregator(10*1024*1024)); 35 | ph.addLast("handler", new NettyClientHandler()); //客户端的逻辑 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Netty-slidingWindow/src/main/java/com/pancm/netty/client/NettyClientHandler.java: -------------------------------------------------------------------------------- 1 | package com.pancm.netty.client; 2 | 3 | import java.util.Date; 4 | 5 | import com.pancm.netty.pojo.Message; 6 | 7 | import io.netty.bootstrap.Bootstrap; 8 | import io.netty.channel.ChannelHandlerContext; 9 | import io.netty.channel.ChannelInboundHandlerAdapter; 10 | import io.netty.channel.EventLoop; 11 | import io.netty.handler.timeout.IdleState; 12 | import io.netty.handler.timeout.IdleStateEvent; 13 | 14 | /** 15 | * 16 | * @Title: NettyClientHandler 17 | * @Description: 客户端业务逻辑实现 18 | * @Version:1.0.0 19 | * @author pancm 20 | * @date 2017年10月8日 21 | */ 22 | public class NettyClientHandler extends ChannelInboundHandlerAdapter { 23 | 24 | 25 | 26 | 27 | /** 发送次数 */ 28 | private int count = 1; 29 | 30 | /**循环次数 */ 31 | private int fcount = 1; 32 | 33 | 34 | /** 心跳指令 */ 35 | private final String CMD_HEART = "cmd_heart"; 36 | /** 登录指令 */ 37 | private final String CMD_LOGIN = "cmd_login"; 38 | /** 39 | * 建立连接时 40 | */ 41 | @Override 42 | public void channelActive(ChannelHandlerContext ctx) throws Exception { 43 | System.out.println("建立连接时:"+new Date()); 44 | ctx.fireChannelActive(); 45 | Message message = new Message(); 46 | message.setCmd(CMD_LOGIN); 47 | message.setId(1); 48 | message.setMsg("请求登录!"); 49 | ctx.writeAndFlush(message.toString()); 50 | } 51 | 52 | /** 53 | * 关闭连接时 54 | */ 55 | @Override 56 | public void channelInactive(ChannelHandlerContext ctx) throws Exception { 57 | System.out.println("关闭连接时:"+new Date()); 58 | final EventLoop eventLoop = ctx.channel().eventLoop(); 59 | NettyClient.nettyClient.doConnect(new Bootstrap(), eventLoop); 60 | super.channelInactive(ctx); 61 | } 62 | 63 | /** 64 | * 心跳请求处理 65 | * 每4秒发送一次心跳请求; 66 | * 67 | */ 68 | @Override 69 | public void userEventTriggered(ChannelHandlerContext ctx, Object obj) throws Exception { 70 | System.out.println("循环请求的时间:"+new Date()+",次数"+fcount); 71 | if (obj instanceof IdleStateEvent) { 72 | IdleStateEvent event = (IdleStateEvent) obj; 73 | //如果写通道处于空闲状态,就发送心跳命令 74 | if (IdleState.WRITER_IDLE.equals(event.state())) { 75 | Message message = new Message(); 76 | message.setCmd(CMD_HEART); 77 | ctx.channel().writeAndFlush(message.toString()); 78 | fcount++; 79 | } 80 | } 81 | } 82 | 83 | /** 84 | * 业务逻辑处理 85 | */ 86 | @Override 87 | public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 88 | System.out.println("第"+count+"次"+",客户端接受的消息:"+msg); 89 | count++; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /Netty-slidingWindow/src/main/java/com/pancm/netty/client/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * Title: package-info 6 | * Description: 7 | * Version:1.0.0 8 | * @author pancm 9 | * @date 2018年1月27日 10 | */ 11 | package com.pancm.netty.client; -------------------------------------------------------------------------------- /Netty-slidingWindow/src/main/java/com/pancm/netty/pojo/Message.java: -------------------------------------------------------------------------------- 1 | package com.pancm.netty.pojo; 2 | 3 | import com.alibaba.fastjson.JSONObject; 4 | 5 | /** 6 | * @Title: Message 7 | * @Description: 8 | * @Version:1.0.0 9 | * @author pancm 10 | * @date 2019年1月16日 11 | */ 12 | public class Message { 13 | 14 | private int id; 15 | private String cmd; 16 | private String msg; 17 | public int getId() { 18 | return id; 19 | } 20 | public void setId(int id) { 21 | this.id = id; 22 | } 23 | public String getCmd() { 24 | return cmd; 25 | } 26 | public void setCmd(String cmd) { 27 | this.cmd = cmd; 28 | } 29 | public String getMsg() { 30 | return msg; 31 | } 32 | public void setMsg(String msg) { 33 | this.msg = msg; 34 | } 35 | /** 36 | * 37 | */ 38 | @Override 39 | public String toString() { 40 | return JSONObject.toJSONString(this); 41 | } 42 | 43 | 44 | } 45 | -------------------------------------------------------------------------------- /Netty-slidingWindow/src/main/java/com/pancm/netty/pojo/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * @Title: package-info 3 | * @Description: 4 | * @Version:1.0.0 5 | * @author pancm 6 | * @date 2019年1月16日 7 | */ 8 | package com.pancm.netty.pojo; -------------------------------------------------------------------------------- /Netty-slidingWindow/src/main/java/com/pancm/netty/server/NettyServer.java: -------------------------------------------------------------------------------- 1 | package com.pancm.netty.server; 2 | 3 | import io.netty.bootstrap.ServerBootstrap; 4 | import io.netty.channel.ChannelFuture; 5 | import io.netty.channel.ChannelOption; 6 | import io.netty.channel.EventLoopGroup; 7 | import io.netty.channel.group.ChannelGroup; 8 | import io.netty.channel.group.DefaultChannelGroup; 9 | import io.netty.channel.nio.NioEventLoopGroup; 10 | import io.netty.channel.socket.nio.NioServerSocketChannel; 11 | import io.netty.util.concurrent.DefaultEventExecutor; 12 | import io.netty.util.concurrent.DefaultThreadFactory; 13 | import io.netty.util.concurrent.EventExecutor; 14 | 15 | /** 16 | * 17 | * @Title: NettyServer 18 | * @Description: Netty服务端 滑动窗口 测试 19 | * @Version:1.0.0 20 | * @author pancm 21 | * @date 2019年1月16日 22 | */ 23 | public class NettyServer { 24 | private static final int port = 9876; // 设置服务端端口 25 | // 创建一个boss和work线程 26 | private EventLoopGroup boss = null; 27 | private EventLoopGroup work = null; 28 | private ServerBootstrap b = null; 29 | 30 | // 定义一个通道 31 | private ChannelGroup channels; 32 | private ChannelFuture f; 33 | // 定义通道组的共用定时器任务 34 | private EventExecutor executor = new DefaultEventExecutor(new DefaultThreadFactory("netty-server-threadFactory")); 35 | 36 | 37 | 38 | public NettyServer() { 39 | // 为boss组指定一个线程 40 | boss = new NioEventLoopGroup(1, new DefaultThreadFactory("netty-server-boss")); 41 | // 为work组指定当前系统cup个数乘以2的线程数 42 | work = new NioEventLoopGroup(Runtime.getRuntime().availableProcessors() * 2, 43 | new DefaultThreadFactory("netty-server-work")); 44 | channels = new DefaultChannelGroup(executor); 45 | } 46 | 47 | public void run() { 48 | try { 49 | //初始化 50 | init(); 51 | // 服务器绑定端口监听 52 | f = b.bind(port).sync(); 53 | System.out.println("服务端启动成功,端口是:" + port); 54 | // 监听服务器关闭监听 55 | f.channel().closeFuture().sync(); 56 | } catch (InterruptedException e) { 57 | e.printStackTrace(); 58 | } finally { 59 | destroy(); 60 | } 61 | } 62 | 63 | /** 64 | * 初始化 65 | */ 66 | private void init() { 67 | if (null != b) { 68 | return; 69 | } 70 | b = new ServerBootstrap(); 71 | b.group(boss, work); 72 | b.channel(NioServerSocketChannel.class); 73 | // 74 | int backlog = 128; 75 | //设置缓冲区队列 76 | b.option(ChannelOption.SO_BACKLOG, backlog) 77 | //设置是否可以重用端口 78 | .option(ChannelOption.SO_REUSEADDR, false); 79 | //设置无延时 80 | b.childOption(ChannelOption.TCP_NODELAY, true) 81 | //设置套接字发送缓冲区大小 82 | .childOption(ChannelOption.SO_SNDBUF, 1000 * 1024 * 1024); 83 | // 设置过滤器 84 | b.childHandler(new NettyServerFilter()); 85 | 86 | } 87 | 88 | /* 89 | * 释放资源 90 | */ 91 | public void destroy() { 92 | if (null != channels) { 93 | channels.close().awaitUninterruptibly(); 94 | } 95 | if (null != work) { 96 | work.shutdownGracefully(); 97 | } 98 | if (null != boss) { 99 | boss.shutdownGracefully(); 100 | } 101 | } 102 | 103 | /** 104 | * Netty创建全部都是实现自AbstractBootstrap。 客户端的是Bootstrap,服务端的则是 ServerBootstrap。 105 | **/ 106 | public static void main(String[] args) { 107 | NettyServer nettyServer = new NettyServer(); 108 | nettyServer.run(); 109 | } 110 | 111 | } 112 | -------------------------------------------------------------------------------- /Netty-slidingWindow/src/main/java/com/pancm/netty/server/NettyServerFilter.java: -------------------------------------------------------------------------------- 1 | package com.pancm.netty.server; 2 | 3 | import io.netty.channel.ChannelInitializer; 4 | import io.netty.channel.ChannelPipeline; 5 | import io.netty.channel.socket.SocketChannel; 6 | import io.netty.handler.codec.http.HttpObjectAggregator; 7 | import io.netty.handler.codec.string.StringDecoder; 8 | import io.netty.handler.codec.string.StringEncoder; 9 | import io.netty.handler.timeout.IdleStateHandler; 10 | 11 | import java.util.concurrent.TimeUnit; 12 | 13 | /** 14 | * 15 | * @Title: HelloServerInitializer 16 | * @Description: Netty 服务端过滤器 17 | * @Version:1.0.0 18 | * @author pancm 19 | * @date 2017年10月8日 20 | */ 21 | public class NettyServerFilter extends ChannelInitializer { 22 | 23 | @Override 24 | protected void initChannel(SocketChannel ch) throws Exception { 25 | ChannelPipeline ph = ch.pipeline(); 26 | // 解码和编码,应和客户端一致 27 | //入参说明: 读超时时间、写超时时间、所有类型的超时时间、时间格式 28 | ph.addLast(new IdleStateHandler(5, 0, 0, TimeUnit.SECONDS)); 29 | ph.addLast("decoder", new StringDecoder()); 30 | ph.addLast("encoder", new StringEncoder()); 31 | ph.addLast("aggregator", new HttpObjectAggregator(10*1024*1024)); 32 | ph.addLast("handler", new NettyServerHandler());// 服务端业务逻辑 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Netty-slidingWindow/src/main/java/com/pancm/netty/server/NettyServerHandler.java: -------------------------------------------------------------------------------- 1 | package com.pancm.netty.server; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.cloudhopper.commons.util.windowing.DuplicateKeyException; 5 | import com.cloudhopper.commons.util.windowing.OfferTimeoutException; 6 | import com.cloudhopper.commons.util.windowing.Window; 7 | import com.cloudhopper.commons.util.windowing.WindowFuture; 8 | import com.pancm.netty.pojo.Message; 9 | 10 | import io.netty.channel.ChannelFuture; 11 | import io.netty.channel.ChannelHandlerContext; 12 | import io.netty.channel.ChannelInboundHandlerAdapter; 13 | import io.netty.handler.timeout.IdleState; 14 | import io.netty.handler.timeout.IdleStateEvent; 15 | 16 | /** 17 | * 18 | * @Title: NettyServerHandler 19 | * @Description: 服务端业务逻辑 20 | * @Version:1.0.0 21 | * @author pancm 22 | * @date 2017年10月8日 23 | */ 24 | public class NettyServerHandler extends ChannelInboundHandlerAdapter { 25 | 26 | /** 空闲次数 */ 27 | private int idle_count = 1; 28 | /** 发送次数 */ 29 | private int count = 1; 30 | 31 | /** 心跳指令 */ 32 | private final String CMD_HEART = "cmd_heart"; 33 | /** 登录指令 */ 34 | private final String CMD_LOGIN = "cmd_login"; 35 | /** 成功 */ 36 | private final String CMD_SUC = "ok"; 37 | 38 | boolean flag=true; 39 | 40 | // 滑动窗口 41 | private Window window = new Window(20); 42 | 43 | /** 44 | * 超时处理 如果5秒没有接受客户端的心跳,就触发; 如果超过两次,则直接关闭; 45 | */ 46 | @Override 47 | public void userEventTriggered(ChannelHandlerContext ctx, Object obj) throws Exception { 48 | if (obj instanceof IdleStateEvent) { 49 | IdleStateEvent event = (IdleStateEvent) obj; 50 | if (IdleState.READER_IDLE.equals(event.state())) { // 如果读通道处于空闲状态,说明没有接收到心跳命令 51 | System.out.println("已经5秒没有接收到客户端的信息了"); 52 | if (idle_count > 1) { 53 | System.out.println("关闭这个不活跃的channel"); 54 | ctx.channel().close(); 55 | } 56 | idle_count++; 57 | } 58 | } else { 59 | super.userEventTriggered(ctx, obj); 60 | } 61 | } 62 | 63 | /** 64 | * 业务逻辑处理 65 | */ 66 | @Override 67 | public void channelRead(ChannelHandlerContext ctx, Object obj) throws Exception { 68 | System.out.println("第" + count + "次" + ",服务端接受的消息:" + obj); 69 | Message msg = JSON.parseObject(obj.toString(), Message.class); 70 | String cmd = msg.getCmd(); 71 | // 如果是心跳命令,则发送给客户端 72 | if (CMD_HEART.equals(cmd)) { 73 | msg.setCmd(CMD_SUC); 74 | msg.setMsg("服务端成功收到请求!"); 75 | ctx.writeAndFlush(msg.toString()); 76 | } else if (CMD_LOGIN.equals(cmd)) { 77 | handlerResponse(msg); 78 | msg.setCmd(CMD_SUC); 79 | msg.setMsg("登录成功!"); 80 | ctx.writeAndFlush(msg.toString()); 81 | 82 | } else { 83 | System.out.println("未知命令!" + cmd); 84 | return; 85 | } 86 | if(flag) { 87 | msg.setCmd(CMD_SUC); 88 | msg.setMsg("滑动窗口测试!"); 89 | new Thread(()->handlerRequest(msg,ctx)).start(); 90 | flag=false; 91 | } 92 | count++; 93 | } 94 | 95 | /** 96 | * 异常处理 97 | */ 98 | @Override 99 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 100 | cause.printStackTrace(); 101 | ctx.close(); 102 | } 103 | 104 | /** 105 | * 滑动窗口响应缓存 106 | */ 107 | public void handlerResponse(Message msg) { 108 | int id = msg.getId(); 109 | WindowFuture future = null; 110 | try { 111 | 112 | future = window.complete(id, msg); 113 | } catch (InterruptedException e) { 114 | System.err.println("完成窗口失败!ID:" + id + " 异常:" + e); 115 | return; 116 | } 117 | if (null == future) { 118 | System.err.println("完成窗口在完成方法引用前失败!id:"+id); 119 | return; 120 | } 121 | if (future.isSuccess()) { 122 | System.err.println("等待响应的请求:" + future.getRequest()); 123 | return; 124 | } else { 125 | System.err.println("等待超时的请求:" + future.getRequest()); 126 | return; 127 | } 128 | 129 | } 130 | 131 | /* 132 | * 滑动窗口响应请求 133 | */ 134 | @SuppressWarnings("unchecked") 135 | public Message handlerRequest(Message request, ChannelHandlerContext ctx) { 136 | // 入滑动窗口超时、滑动窗口内超时、客户端调用超时 毫秒 137 | int windowWaitOffset = 30000; 138 | int windowExpiration = 30000; 139 | int invokeOffset = 30000; 140 | int id = request.getId(); 141 | WindowFuture reqFuture = null; 142 | try { 143 | reqFuture = window.offer(id, request, windowWaitOffset, windowExpiration); 144 | } catch (DuplicateKeyException e) { 145 | System.out.println("重复调用!" + e); 146 | return null; 147 | } catch (OfferTimeoutException e) { 148 | System.out.println("滑动窗口请求超时!" + e); 149 | return null; 150 | } catch (InterruptedException e) { 151 | System.out.println("滑动窗口过程中被中断!" + e); 152 | return null; 153 | } 154 | System.out.println("滑动窗口发送的数据:"+request.toString()); 155 | ChannelFuture future = ctx.writeAndFlush(request.toString()); 156 | future.awaitUninterruptibly(); 157 | if (future.isCancelled()) {// 被中断 158 | try { 159 | // 取消该id的数据 160 | window.cancel(id); 161 | } catch (InterruptedException e) { 162 | // IGNORE 163 | } 164 | System.out.println("调用失败,被用户中断!"); 165 | } else if (!future.isSuccess()) {// 失败,遇到异常 166 | try { 167 | window.cancel(id); 168 | } catch (InterruptedException e) { 169 | } 170 | Throwable cause = future.cause(); 171 | System.out.println("无法将数据正确写到Channel,Channel可能被关闭" + cause); 172 | } else {// 正常 173 | try { 174 | reqFuture.await(invokeOffset); 175 | } catch (InterruptedException e) { 176 | System.out.println("调用过程中被用户中断!-->消息可能已经发送到服务端" + e); 177 | } 178 | // 成功返回正确的响应 179 | if (reqFuture.isSuccess()) { 180 | return reqFuture.getResponse(); 181 | } 182 | try { 183 | window.cancel(id); 184 | } catch (InterruptedException e) { 185 | // ignore 186 | } 187 | } 188 | return null; 189 | } 190 | 191 | } 192 | -------------------------------------------------------------------------------- /Netty-slidingWindow/src/main/java/com/pancm/netty/server/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * Title: package-info 6 | * Description: 7 | * Version:1.0.0 8 | * @author pancm 9 | * @date 2018年1月27日 10 | */ 11 | package com.pancm.netty.server; -------------------------------------------------------------------------------- /Netty-slidingWindow/target/classes/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Built-By: Administrator 3 | Build-Jdk: 1.8.0_131 4 | Created-By: Maven Integration for Eclipse 5 | 6 | -------------------------------------------------------------------------------- /Netty-slidingWindow/target/classes/META-INF/maven/1.0.0/Netty-slidingWindow/pom.properties: -------------------------------------------------------------------------------- 1 | #Generated by Maven Integration for Eclipse 2 | #Wed Jan 16 16:41:05 CST 2019 3 | version=0.0.1-SNAPSHOT 4 | groupId=1.0.0 5 | m2e.projectName=Netty-slidingWindow 6 | m2e.projectLocation=D\:\\git\\GitHub\\Netty-study\\Netty-slidingWindow 7 | artifactId=Netty-slidingWindow 8 | -------------------------------------------------------------------------------- /Netty-slidingWindow/target/classes/META-INF/maven/1.0.0/Netty-slidingWindow/pom.xml: -------------------------------------------------------------------------------- 1 | 4 | 4.0.0 5 | 6 | 1.0.0 7 | Netty-slidingWindow 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | Netty-slidingWindow 12 | http://maven.apache.org 13 | 14 | 15 | UTF-8 16 | 1.8 17 | 4.1.17.Final 18 | 19 | 20 | 21 | 22 | 23 | junit 24 | junit 25 | 3.8.1 26 | test 27 | 28 | 29 | 30 | io.netty 31 | netty-all 32 | ${netty.version} 33 | 34 | 35 | com.cloudhopper 36 | ch-commons-util 37 | 6.0.4 38 | 39 | 40 | com.alibaba 41 | fastjson 42 | 1.2.54 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /Netty-unpack/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /Netty-unpack/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | 1.0.0 6 | Netty-unpack 7 | 0.0.1-SNAPSHOT 8 | jar 9 | 10 | Netty-unpack 11 | 12 | http://maven.apache.org 13 | 14 | 15 | UTF-8 16 | 1.7 17 | 4.1.17.Final 18 | 19 | 20 | 21 | 22 | 23 | junit 24 | junit 25 | 3.8.1 26 | test 27 | 28 | 29 | 30 | io.netty 31 | netty-all 32 | ${netty.version} 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /Netty-unpack/src/main/java/com/pancm/netty/App.java: -------------------------------------------------------------------------------- 1 | package com.pancm.netty; 2 | 3 | /** 4 | * Hello world! 5 | * 6 | */ 7 | public class App 8 | { 9 | public static void main( String[] args ) 10 | { 11 | System.out.println( "Hello World!" ); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Netty-unpack/src/main/java/com/pancm/netty/client/NettyClient.java: -------------------------------------------------------------------------------- 1 | package com.pancm.netty.client; 2 | 3 | import io.netty.bootstrap.Bootstrap; 4 | import io.netty.buffer.ByteBuf; 5 | import io.netty.buffer.Unpooled; 6 | import io.netty.channel.Channel; 7 | import io.netty.channel.ChannelInitializer; 8 | import io.netty.channel.ChannelOption; 9 | import io.netty.channel.ChannelPipeline; 10 | import io.netty.channel.EventLoopGroup; 11 | import io.netty.channel.nio.NioEventLoopGroup; 12 | import io.netty.channel.socket.SocketChannel; 13 | import io.netty.channel.socket.nio.NioSocketChannel; 14 | import io.netty.handler.codec.string.StringDecoder; 15 | 16 | import java.io.IOException; 17 | 18 | /** 19 | * 20 | * Title: NettyClient 21 | * Description: Netty客户端 用于测试粘包、拆包 22 | * Version:1.0.0 23 | * @author pancm 24 | * @date 2017年9月20日 25 | */ 26 | public class NettyClient { 27 | public static String host = "127.0.0.1"; //ip地址 28 | public static int port = 2345; //端口 29 | /// 通过nio方式来接收连接和处理连接 30 | private static EventLoopGroup group = new NioEventLoopGroup(); 31 | private static Bootstrap b = new Bootstrap(); 32 | private static Channel ch; 33 | 34 | /** 35 | * Netty创建全部都是实现自AbstractBootstrap。 36 | * 客户端的是Bootstrap,服务端的则是ServerBootstrap。 37 | **/ 38 | public static void main(String[] args) throws InterruptedException, IOException { 39 | b.group(group) 40 | .channel(NioSocketChannel.class) 41 | .option(ChannelOption.TCP_NODELAY,true) 42 | .handler(new ChannelInitializer() { 43 | @Override 44 | public void initChannel(SocketChannel ch) throws Exception { 45 | ChannelPipeline p = ch.pipeline(); 46 | p.addLast(new StringDecoder()); //绑定解码器 47 | p.addLast(new NettyClientHandler()); //绑定自定义业务 48 | } 49 | }); 50 | // 连接服务端 51 | ch = b.connect(host, port).sync().channel(); 52 | System.out.println("客户端成功启动..."); 53 | // star(); 54 | } 55 | 56 | public static void star() throws IOException{ 57 | String str="你好 Netty!"; 58 | byte[] by=str.getBytes(); 59 | ByteBuf message = Unpooled.buffer(by.length); ; 60 | message.writeBytes(by); 61 | ch.writeAndFlush(message); 62 | System.out.println("客户端发送数据:"+str); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Netty-unpack/src/main/java/com/pancm/netty/client/NettyClientHandler.java: -------------------------------------------------------------------------------- 1 | package com.pancm.netty.client; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.buffer.Unpooled; 5 | import io.netty.channel.ChannelHandlerContext; 6 | import io.netty.channel.ChannelInboundHandlerAdapter; 7 | 8 | /** 9 | * 10 | * Title: NettyClientHandler 11 | * Description: Netty客户端业务逻辑处理 12 | * Version:1.0.0 13 | * @author pancm 14 | * @date 2017年9月20日 15 | */ 16 | public class NettyClientHandler extends ChannelInboundHandlerAdapter{ 17 | 18 | private byte[] req; 19 | 20 | private int counter; 21 | 22 | public NettyClientHandler() { 23 | // req = ("书到用时方恨少,事非经过不知难!").getBytes(); 24 | 25 | //用于测试字节解码器 LineBasedFrameDecoder(2048) 26 | req = ("春江潮水连海平,海上明月共潮生。" 27 | +" 滟滟随波千万里,何处春江无月明! " 28 | +" 江流宛转绕芳甸,月照花林皆似霰;" 29 | +" 空里流霜不觉飞,汀上白沙看不见。" 30 | +" 江天一色无纤尘,皎皎空中孤月轮。" 31 | +" 江畔何人初见月?江月何年初照人?" 32 | +" 人生代代无穷已,江月年年望相似。" 33 | +" 不知江月待何人,但见长江送流水。" 34 | +" 白云一片去悠悠,青枫浦上不胜愁。" 35 | +" 谁家今夜扁舟子?何处相思明月楼?" 36 | +" 可怜楼上月徘徊,应照离人妆镜台。" 37 | +" 玉户帘中卷不去,捣衣砧上拂还来。" 38 | +" 此时相望不相闻,愿逐月华流照君。" 39 | +" 鸿雁长飞光不度,鱼龙潜跃水成文。" 40 | +" 昨夜闲潭梦落花,可怜春半不还家。" 41 | +" 江水流春去欲尽,江潭落月复西斜。" 42 | +" 斜月沉沉藏海雾,碣石潇湘无限路。" 43 | +" 不知乘月几人归,落月摇情满江树。" 44 | +" 噫吁嚱,危乎高哉!蜀道之难,难于上青天!蚕丛及鱼凫,开国何茫然!尔来四万八千岁,不与秦塞通人烟。" 45 | +" 西当太白有鸟道,可以横绝峨眉巅。地崩山摧壮士死,然后天梯石栈相钩连。上有六龙回日之高标,下有冲波逆折之回川。" 46 | +" 黄鹤之飞尚不得过,猿猱欲度愁攀援。青泥何盘盘,百步九折萦岩峦。扪参历井仰胁息,以手抚膺坐长叹。" 47 | +" 问君西游何时还?畏途巉岩不可攀。但见悲鸟号古木,雄飞雌从绕林间。又闻子规啼夜月,愁空山。" 48 | +" 蜀道之难,难于上青天,使人听此凋朱颜!连峰去天不盈尺,枯松倒挂倚绝壁。飞湍瀑流争喧豗,砯崖转石万壑雷。" 49 | +" 其险也如此,嗟尔远道之人胡为乎来哉!剑阁峥嵘而崔嵬,一夫当关,万夫莫开。" 50 | +" 所守或匪亲,化为狼与豺。朝避猛虎,夕避长蛇;磨牙吮血,杀人如麻。锦城虽云乐,不如早还家。" 51 | +" 蜀道之难,难于上青天,侧身西望长咨嗟!"+System.getProperty("line.separator")).getBytes(); 52 | 53 | //用于测试 固定字符切分解码器 DelimiterBasedFrameDecoder(1024,Unpooled.copiedBuffer("~_~".getBytes()) 54 | /* req = ("春江潮水连海平,海上明月共潮生。" 55 | +" 滟滟随波千万里,何处春江无月明! " 56 | +" 江流宛转绕芳甸,月照花林皆似霰;" 57 | +" 空里流霜不觉飞,汀上白沙看不见。" 58 | +" 江天一色无纤尘,皎皎空中孤月轮。" 59 | +" 江畔何人初见月?江月何年初照人?" 60 | +" 人生代代无穷已,江月年年望相似。~_~" 61 | +" 不知江月待何人,但见长江送流水。" 62 | +" 白云一片去悠悠,青枫浦上不胜愁。" 63 | +" 谁家今夜扁舟子?何处相思明月楼?" 64 | +" 可怜楼上月徘徊,应照离人妆镜台。" 65 | +" 玉户帘中卷不去,捣衣砧上拂还来。" 66 | +" 此时相望不相闻,愿逐月华流照君。~_~" 67 | +" 鸿雁长飞光不度,鱼龙潜跃水成文。" 68 | +" 昨夜闲潭梦落花,可怜春半不还家。" 69 | +" 江水流春去欲尽,江潭落月复西斜。" 70 | +" 斜月沉沉藏海雾,碣石潇湘无限路。" 71 | +" 不知乘月几人归,落月摇情满江树。~_~" 72 | +" 噫吁嚱,危乎高哉!蜀道之难,难于上青天!蚕丛及鱼凫,开国何茫然!尔来四万八千岁,不与秦塞通人烟。" 73 | +" 西当太白有鸟道,可以横绝峨眉巅。地崩山摧壮士死,然后天梯石栈相钩连。~_~ 上有六龙回日之高标,下有冲波逆折之回川。" 74 | +" 黄鹤之飞尚不得过,猿猱欲度愁攀援。~_~ 青泥何盘盘,百步九折萦岩峦。扪参历井仰胁息,以手抚膺坐长叹。" 75 | +" 问君西游何时还?畏途巉岩不可攀。但见悲鸟号古木,雄飞雌从绕林间。又闻子规啼夜月,愁空山。" 76 | +" 蜀道之难,难于上青天,使人听此凋朱颜!连峰去天不盈尺,枯松倒挂倚绝壁。~_~ 飞湍瀑流争喧豗,砯崖转石万壑雷。" 77 | +" 其险也如此,嗟尔远道之人胡为乎来哉!剑阁峥嵘而崔嵬,一夫当关,万夫莫开。" 78 | +" 所守或匪亲,化为狼与豺。朝避猛虎,夕避长蛇;磨牙吮血,杀人如麻。锦城虽云乐,不如早还家。" 79 | +" 蜀道之难,难于上青天,侧身西望长咨嗟!"+System.getProperty("line.separator")).getBytes(); */ 80 | 81 | 82 | 83 | 84 | /* req = ("AAAAAAAAAAAAAAAA" 85 | +" BBBBBBBBBBBBBBBB " 86 | +" CCCCCCCCCCCCCCCCC" 87 | +" DDDDDDDDDDDDD" 88 | +" EEEEEEEEEEEEEE" 89 | +" FFFFFFFFFFFFFF" 90 | +" GGGGGGGGGGGG ~_~" 91 | +" HHHHHHHHHHHHHHHH" 92 | +" IIIIIIIIIIIIII" 93 | +" JJJJJJJJJJJJJJJJJJJ" 94 | +" KKKKKKKKKKKKKKKKK" 95 | +" LLLLLLLLLLLLLLLLL" 96 | +" MMMMMMMMMMMMMMMMMM ~_~" 97 | +" NNNNNNNNNNNNNNNN" 98 | +" OOOOOOOOOOOOOOOOOOOO" 99 | +" PPPPPPPPPPPPPP" 100 | +" QQQQQQQQQQQQQQQQQQQQ" 101 | +" RRRRRRRRRRRRRR ~_~" 102 | +" SSSSSSSSSSSSSSSSS" 103 | +" TTTTTT ~_~ TTTTTTT"+System.getProperty("line.separator")).getBytes(); */ 104 | 105 | //System.getProperty("line.separator") 结束标记 106 | } 107 | 108 | @Override 109 | public void channelActive(ChannelHandlerContext ctx) throws Exception { 110 | ByteBuf message = null; 111 | //会发生粘包现象 112 | // for (int i = 0; i < 100; i++) { 113 | // message = Unpooled.buffer(req.length); 114 | // message.writeBytes(req); 115 | // ctx.writeAndFlush(message); 116 | // } 117 | message = Unpooled.buffer(req.length); 118 | message.writeBytes(req); 119 | ctx.writeAndFlush(message); 120 | System.out.println("一次发送消息过多,发送拆包现象! "); 121 | } 122 | 123 | @Override 124 | public void channelRead(ChannelHandlerContext ctx, Object msg) 125 | throws Exception { 126 | String buf = (String) msg; 127 | System.out.println("现在 : " + buf + " ; 条数是 : "+ ++counter); 128 | } 129 | 130 | @Override 131 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { 132 | ctx.close(); 133 | } 134 | 135 | 136 | } 137 | -------------------------------------------------------------------------------- /Netty-unpack/src/main/java/com/pancm/netty/client/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * Title: package-info 6 | * Description: 7 | * Version:1.0.0 8 | * @author pancm 9 | * @date 2018年1月27日 10 | */ 11 | package com.pancm.netty.client; -------------------------------------------------------------------------------- /Netty-unpack/src/main/java/com/pancm/netty/server/NettyServer.java: -------------------------------------------------------------------------------- 1 | package com.pancm.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.ChannelOption; 7 | import io.netty.channel.ChannelPipeline; 8 | import io.netty.channel.EventLoopGroup; 9 | import io.netty.channel.nio.NioEventLoopGroup; 10 | import io.netty.channel.socket.SocketChannel; 11 | import io.netty.channel.socket.nio.NioServerSocketChannel; 12 | import io.netty.handler.codec.LineBasedFrameDecoder; 13 | import io.netty.handler.codec.string.StringDecoder; 14 | 15 | import java.net.InetSocketAddress; 16 | 17 | /** 18 | * 19 | * Title: NettyServerDemo2 20 | * Description: Netty服务端 用于测试粘包、拆包 21 | * Version:1.0.0 22 | * @author pancm 23 | * @date 2017年9月20日 24 | */ 25 | public class NettyServer { 26 | private final static int port=2345; 27 | 28 | public void start(){ 29 | EventLoopGroup bossGroup = new NioEventLoopGroup(1); 30 | EventLoopGroup workerGroup = new NioEventLoopGroup(); 31 | try { 32 | ServerBootstrap sbs = new ServerBootstrap().group(bossGroup,workerGroup).channel(NioServerSocketChannel.class).localAddress(new InetSocketAddress(port)) 33 | .childHandler(new ChannelInitializer() { 34 | protected void initChannel(SocketChannel ch) throws Exception { 35 | ChannelPipeline p = ch.pipeline(); 36 | 37 | p.addLast(new LineBasedFrameDecoder(2048)); //字节解码器 ,其中2048是规定一行数据最大的字节数。 用于解决拆包问题 38 | // p.addLast(new FixedLengthFrameDecoder(100)); //定长数据帧的解码器 ,每帧数据100个字节就切分一次。 用于解决粘包问题 39 | // p.addLast(new DelimiterBasedFrameDecoder(1024,Unpooled.copiedBuffer("~_~".getBytes()))); //固定字符切分解码器 ,会以"~_~"为分隔符。 注意此方法要放到StringDecoder()上面 40 | p.addLast(new StringDecoder()); //设置解码器 41 | p.addLast(new NettyServerHandler()); //绑定自定义事物 42 | }; 43 | 44 | }).option(ChannelOption.SO_BACKLOG, 128) 45 | .childOption(ChannelOption.SO_KEEPALIVE, true); 46 | // 绑定端口,开始接收进来的连接 47 | ChannelFuture future = sbs.bind(port).sync(); 48 | 49 | System.out.println("服务端启动成功,端口为 :" + port ); 50 | future.channel().closeFuture().sync(); 51 | } catch (Exception e) { 52 | bossGroup.shutdownGracefully(); //关闭EventLoopGroup,释放掉所有资源包括创建的线程 53 | workerGroup.shutdownGracefully(); //关闭EventLoopGroup,释放掉所有资源包括创建的线程 54 | } 55 | } 56 | 57 | public static void main(String[] args) throws Exception { 58 | new NettyServer().start(); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Netty-unpack/src/main/java/com/pancm/netty/server/NettyServerHandler.java: -------------------------------------------------------------------------------- 1 | package com.pancm.netty.server; 2 | 3 | import io.netty.channel.ChannelHandlerContext; 4 | import io.netty.channel.ChannelInboundHandlerAdapter; 5 | 6 | /** 7 | * 8 | * Title: NettyServerHandlerDemo2 9 | * Description: Netty服务端业务逻辑处理 用于测试粘包、拆包 10 | * Version:1.0.0 11 | * @author pancm 12 | * @date 2017年9月20日 13 | */ 14 | public class NettyServerHandler extends ChannelInboundHandlerAdapter{ 15 | 16 | 17 | private int counter; 18 | 19 | @Override 20 | public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 21 | 22 | String body = (String)msg; 23 | System.out.println("接受的数据是: " + body + ";条数是: " + ++counter); 24 | } 25 | 26 | 27 | @Override 28 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 29 | cause.printStackTrace(); 30 | ctx.close(); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /Netty-unpack/src/main/java/com/pancm/netty/server/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * Title: package-info 6 | * Description: 7 | * Version:1.0.0 8 | * @author pancm 9 | * @date 2018年1月27日 10 | */ 11 | package com.pancm.netty.server; -------------------------------------------------------------------------------- /Netty-unpack/src/test/java/com/pancm/netty/AppTest.java: -------------------------------------------------------------------------------- 1 | package com.pancm.netty; 2 | 3 | import junit.framework.Test; 4 | import junit.framework.TestCase; 5 | import junit.framework.TestSuite; 6 | 7 | /** 8 | * Unit test for simple App. 9 | */ 10 | public class AppTest 11 | extends TestCase 12 | { 13 | /** 14 | * Create the test case 15 | * 16 | * @param testName name of the test case 17 | */ 18 | public AppTest( String testName ) 19 | { 20 | super( testName ); 21 | } 22 | 23 | /** 24 | * @return the suite of tests being tested 25 | */ 26 | public static Test suite() 27 | { 28 | return new TestSuite( AppTest.class ); 29 | } 30 | 31 | /** 32 | * Rigourous Test :-) 33 | */ 34 | public void testApp() 35 | { 36 | assertTrue( true ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Netty的相关工程 2 | 3 | - [Netty-hello](https://github.com/xuwujing/Netty/tree/master/Netty-hello) :Netty 的 HelloWord 工程。客户端和服务端通信的相关代码。 4 | 5 | - [Netty-heartbeat](https://github.com/xuwujing/Netty/tree/master/Netty-heartbeat):Netty的心跳机制示例工程。 6 | 7 | - [Netty-unpack](https://github.com/xuwujing/Netty/tree/master/Netty-unpack):Netty的粘包和拆包处理方法。 8 | 9 | - [Netty-httpServer](https://github.com/xuwujing/Netty/tree/master/Netty-httpServer):Netty Http 服务的实现。 10 | 11 | - [Netty-reconnect](https://github.com/xuwujing/Netty-study/tree/master/Netty-reconnect): Netty Client 重连机制的实现。 12 | 13 | - [Netty-protobuf](https://github.com/xuwujing/Netty-study/tree/master/Netty-protobuf): Netty 使用protobuf 协议进行数据数据传输。 14 | 15 | - [Netty-slidingWindow](https://github.com/xuwujing/Netty-study/tree/master/Netty-slidingWindow): Netty 结合滑动窗口使用示例。 16 | 17 | 18 | ## Netty的相关博客 19 | 20 | - [Netty 客户端与服务端通信](http://blog.csdn.net/qazwsxpcm/article/details/77750865) 21 | - [Netty 客户端与服务端心跳](http://blog.csdn.net/qazwsxpcm/article/details/78174437) 22 | - [Netty 粘包和拆包](http://blog.csdn.net/qazwsxpcm/article/details/78265120) 23 | - [Netty HTTP服务](http://blog.csdn.net/qazwsxpcm/article/details/78364023) 24 | - [Netty-SpringBott-Protobuf 服务](https://blog.csdn.net/qazwsxpcm/article/details/81069833) 25 | 26 | 27 | 28 | 29 | --------------------------------------------------------------------------------