├── .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 |
--------------------------------------------------------------------------------