Netty私有协议栈 读书笔记

1、数据结构定义

  1)netty消息:NettyMessage

    

 1 package com.cherry.netty.demo.protocolstack.pojo;
 2 
 3 import com.cherry.netty.utils.JsonUtil;
 4 
 5 public final class NettyMessage {
 6     private Header header;
 7     private Object body;
 8     public final Header getHeader() {
 9         return header;
10     }
11     public final void setHeader(Header header) {
12         this.header = header;
13     }
14     public final Object getBody() {
15         return body;
16     }
17     public final void setBody(Object body) {
18         this.body = body;
19     }
20     @Override
21     public String toString() {
22         return "NettyMessage[header="+JsonUtil.toJson(header)+"]";
23     }
24     
25     
26 
27 }

 


  2)消息头:Header

 1 package com.cherry.netty.demo.protocolstack.pojo;
 2 
 3 import java.util.HashMap;
 4 import java.util.Map;
 5 
 6 import com.cherry.netty.utils.JsonUtil;
 7 
 8 public final class Header {
 9     private int crcCode = 0Xabef0101;
10     private int length;
11     private long sessionID;
12     private byte type;
13     private byte priority;
14     private Map<String, Object> attachment = new HashMap<String,Object>();
15     public final int getCrcCode() {
16         return crcCode;
17     }
18     public final void setCrcCode(int crcCode) {
19         this.crcCode = crcCode;
20     }
21     public final int getLength() {
22         return length;
23     }
24     public final void setLength(int length) {
25         this.length = length;
26     }
27     public final long getSessionID() {
28         return sessionID;
29     }
30     public final void setSessionID(long sessionID) {
31         this.sessionID = sessionID;
32     }
33     public final byte getType() {
34         return type;
35     }
36     public final void setType(byte type) {
37         this.type = type;
38     }
39     public final byte getPriority() {
40         return priority;
41     }
42     public final void setPriority(byte priority) {
43         this.priority = priority;
44     }
45     public final Map<String, Object> getAttachment() {
46         return attachment;
47     }
48     public final void setAttachment(Map<String, Object> attachment) {
49         this.attachment = attachment;
50     }
51     @Override
52     public String toString() {
53         return "Header:"+JsonUtil.toJson(this);
54     }
55     
56     
57     
58 }

 


另补充MessageType、NettyConstant

 1 package com.cherry.netty.demo.protocolstack.pojo;
 2 
 3 public enum MessageType {
 4     LOGIN_REQ((byte) 1), LOGIN_RESP((byte) 2), HEARTBEAT_REQ((byte) 3), HEARTBEAT_RESP((byte) 4),;
 5 
 6     public byte value;
 7 
 8     MessageType(byte v) {
 9         this.value = v;
10     }
11 
12     public byte value() {
13         return value;
14     }
15 
16 }
 1 package com.cherry.netty.demo.protocolstack.pojo;
 2 
 3 
 4 public final class NettyConstant {
 5 
 6     public static String LOCALIP = "127.0.0.1";
 7     public static Integer LOCAL_PORT = 9090;
 8     public static String REMOTEIP = "127.0.0.1";
 9     public static Integer REMOTE_PORT = 8080;
10 
11 }

 

 

 2、消息编解码

① pom.xml文件。学习期间 org.jboss.marshalling的2.0.6.Final创建channel会异常。

WARN io.netty.channel.ChannelInitializer - Failed to initialize a channel. Closing: [id: 0xd6032f4c]
java.util.ServiceConfigurationError: org.jboss.marshalling.ProviderDescriptor: Provider org.jboss.marshalling.serial.SerialProviderDescriptor not found

将jboss-marshalling和jboss-marshalling-serial的版本号更新为小于2.0.6的即可。

  1 <?xml version="1.0"?>
  2 <project
  3     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
  4     xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  5     <modelVersion>4.0.0</modelVersion>
  6     <parent>
  7         <groupId>com.example</groupId>
  8         <artifactId>netty</artifactId>
  9         <version>0.0.1-SNAPSHOT</version>
 10     </parent>
 11     <groupId>com.example</groupId>
 12     <artifactId>netty-demo</artifactId>
 13     <version>0.0.1-SNAPSHOT</version>
 14     <name>netty-demo</name>
 15     <url>http://maven.apache.org</url>
 16 
 17     <packaging>jar</packaging>
 18     <properties>
 19         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 20     </properties>
 21     <dependencies>
 22         <dependency>
 23             <groupId>junit</groupId>
 24             <artifactId>junit</artifactId>
 25             <scope>test</scope>
 26         </dependency>
 27         <dependency>
 28             <groupId>org.springframework.boot</groupId>
 29             <artifactId>spring-boot-starter-web</artifactId>
 30         </dependency>
 31 
 32         <dependency>
 33             <groupId>org.springframework.boot</groupId>
 34             <artifactId>spring-boot-starter-tomcat</artifactId>
 35             <scope>provided</scope>
 36         </dependency>
 37         <dependency>
 38             <groupId>org.springframework.boot</groupId>
 39             <artifactId>spring-boot-starter-test</artifactId>
 40             <scope>test</scope>
 41         </dependency>
 42 
 43         <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-log4j12 -->
 44         <dependency>
 45             <groupId>org.slf4j</groupId>
 46             <artifactId>slf4j-log4j12</artifactId>
 47             <scope>test</scope>
 48         </dependency>
 49 
 50         <dependency>
 51             <groupId>net.sf.json-lib</groupId>
 52             <artifactId>json-lib</artifactId>
 53             <version>2.4</version>
 54             <classifier>jdk15</classifier>
 55         </dependency>
 56 
 57         <!-- https://mvnrepository.com/artifact/io.netty/netty-all -->
 58         <dependency>
 59             <groupId>io.netty</groupId>
 60             <artifactId>netty-all</artifactId>
 61             <version>5.0.0.Alpha2</version>
 62         </dependency>
 63 
 64 
 65         <!-- https://mvnrepository.com/artifact/com.google.protobuf/protobuf-java -->
 66         <dependency>
 67             <groupId>com.google.protobuf</groupId>
 68             <artifactId>protobuf-java</artifactId>
 69             <version>3.6.1</version>
 70         </dependency>
 71 
 72         <!-- https://mvnrepository.com/artifact/org.jibx/jibx-run -->
 73         <dependency>
 74             <groupId>org.jibx</groupId>
 75             <artifactId>jibx-run</artifactId>
 76             <version>1.3.1</version>
 77         </dependency>
 78 
 79         <!-- https://mvnrepository.com/artifact/org.jibx/jibx-tools -->
 80         <dependency>
 81             <groupId>org.jibx</groupId>
 82             <artifactId>jibx-tools</artifactId>
 83             <version>1.3.1</version>
 84         </dependency>
 85 
 86         <!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
 87         <dependency>
 88             <groupId>com.google.code.gson</groupId>
 89             <artifactId>gson</artifactId>
 90             <version>2.8.5</version>
 91         </dependency>
 92 
 93 
 94         <!-- https://mvnrepository.com/artifact/org.jboss.marshalling/jboss-marshalling -->
 95         <dependency>
 96             <groupId>org.jboss.marshalling</groupId>
 97             <artifactId>jboss-marshalling</artifactId>
 98             <!-- <version>1.4.10.Final</version> -->
 99              <version>2.0.3.Final</version>
100         </dependency>
101         
102          <dependency>
103             <groupId>org.jboss.marshalling</groupId>
104             <artifactId>jboss-marshalling-serial</artifactId>
105             <!-- <version>1.4.10.Final</version> -->
106             <version>2.0.3.Final</version>
107         </dependency>
108 
109 
110 
111     </dependencies>
112 
113     <build>
114         <pluginManagement>
115             <plugins>
116                 <plugin>
117                     <!-- 生成jibx class信息 -->
118                     <groupId>org.jibx</groupId>
119                     <artifactId>jibx-maven-plugin</artifactId>
120                     <version>1.3.1</version>
121                     <configuration>
122                         <schemaBindingDirectory>${basedir}/target/classes/jibx</schemaBindingDirectory>
123                         <includeSchemaBindings>
124                             <includeSchemaBindings>*binding.xml</includeSchemaBindings>
125                         </includeSchemaBindings>
126                         <verbose>true</verbose>
127                     </configuration>
128                     <executions>
129                         <execution>
130                             <id>jibx-bind</id>
131                             <!-- 把jibx绑定到了comile编译阶段 -->
132                             <phase>compile</phase>
133                             <goals>
134                                 <goal>bind</goal>
135                             </goals>
136                         </execution>
137                     </executions>
138                 </plugin>
139             </plugins>
140         </pluginManagement>
141     </build>
142 
143 </project>

 

 

②MarshallingCodeCFactory

 1 package com.cherry.netty.demo.protocolstack.utils;
 2 
 3 import java.io.IOException;
 4 
 5 import org.jboss.marshalling.Marshaller;
 6 import org.jboss.marshalling.MarshallerFactory;
 7 import org.jboss.marshalling.Marshalling;
 8 import org.jboss.marshalling.MarshallingConfiguration;
 9 import org.jboss.marshalling.Unmarshaller;
10 
11 public final class MarshallingCodeCFactory {
12     
13     public static Marshaller buildMarshalling() throws IOException {
14         final MarshallerFactory marshallerFactory = Marshalling.getProvidedMarshallerFactory("serial");
15         final MarshallingConfiguration configuration = new MarshallingConfiguration();
16         configuration.setVersion(5);
17         Marshaller marshaller = marshallerFactory.createMarshaller(configuration);
18         return marshaller;
19     }
20 
21     
22     public static Unmarshaller buildUnMarshalling() throws IOException {
23         final MarshallerFactory marshallerFactory = Marshalling.getProvidedMarshallerFactory("serial");
24         final MarshallingConfiguration configuration = new MarshallingConfiguration();
25         configuration.setVersion(5);
26         final Unmarshaller unmarshaller = marshallerFactory.createUnmarshaller(configuration);
27         return unmarshaller;
28     }
29 
30 }

 

 

③NettyMessageEncoder、MarshallingEncoder、ChannelBufferByteOutput

 1 package com.cherry.netty.demo.protocolstack.encode;
 2 
 3 import java.io.IOException;
 4 import java.util.Map;
 5 
 6 import com.cherry.netty.demo.protocolstack.pojo.NettyMessage;
 7 
 8 import io.netty.buffer.ByteBuf;
 9 import io.netty.channel.ChannelHandlerContext;
10 import io.netty.handler.codec.MessageToByteEncoder;
11 
12 public final class NettyMessageEncoder extends MessageToByteEncoder<NettyMessage> {
13      MarshallingEncoder marshallingEncoder;
14 
15         public NettyMessageEncoder() throws IOException {
16             this.marshallingEncoder = new MarshallingEncoder();
17         }
18 
19         @SuppressWarnings("unused")
20         @Override
21         protected void encode(ChannelHandlerContext ctx, NettyMessage msg, ByteBuf sendBuf) throws Exception {
22             if (null == msg || null == msg.getHeader()) {
23                 throw new Exception("The encode message is null");
24             }
25             sendBuf.writeInt(msg.getHeader().getCrcCode());
26             sendBuf.writeInt(msg.getHeader().getLength());
27             sendBuf.writeLong(msg.getHeader().getSessionID());
28             sendBuf.writeByte(msg.getHeader().getType());
29             sendBuf.writeByte(msg.getHeader().getPriority());
30             sendBuf.writeInt(msg.getHeader().getAttachment().size());
31 
32             String key = null;
33             byte[] keyArray = null;
34             Object value = null;
35             for (Map.Entry<String, Object> param : msg.getHeader().getAttachment()
36                     .entrySet()) {
37                 key = param.getKey();
38                 keyArray = key.getBytes("UTF-8");
39                 sendBuf.writeInt(keyArray.length);
40                 sendBuf.writeBytes(keyArray);
41                 value = param.getValue();
42             }
43             key = null;
44             keyArray = null;
45             value = null;
46 
47             if (msg.getBody() != null) {
48                 marshallingEncoder.encode(msg.getBody(), sendBuf);
49             } else{
50                 sendBuf.writeInt(0);
51             }
         // 此处需要特别注意
52 sendBuf.setInt(4, sendBuf.readableBytes() - 8); 53 } 54 }

 

 

 1 package com.cherry.netty.demo.protocolstack.encode;
 2 
 3 
 4 
 5 
 6 import java.io.IOException;
 7 
 8 import org.jboss.marshalling.Marshaller;
 9 
10 import com.cherry.netty.demo.protocolstack.utils.MarshallingCodeCFactory;
11 
12 import io.netty.buffer.ByteBuf;
13 
14 public class MarshallingEncoder {
15     
16     private static final byte[] LENGTH_PLACEHOLDER = new byte[4];
17     
18     Marshaller marshaller;
19     
20     
21     public MarshallingEncoder() throws IOException {
22         marshaller = MarshallingCodeCFactory.buildMarshalling();
23     }
24 
25 
26     protected void encode(Object msg, ByteBuf out) throws IOException {
27         try {
28             int lengthPos = out.writerIndex();
29             out.writeBytes(LENGTH_PLACEHOLDER);
30             ChannelBufferByteOutput output = new ChannelBufferByteOutput(out);
31             marshaller.start(output);
32             marshaller.writeObject(msg);
33             marshaller.finish();
34             out.setInt(lengthPos, out.writerIndex() - lengthPos - 4);
35         } finally {
36             marshaller.close();
37         }
38     }
39 
40 }

 

 

 1 package com.cherry.netty.demo.protocolstack.encode;
 2 
 3 import io.netty.buffer.ByteBuf;
 4 import org.jboss.marshalling.ByteOutput;
 5 
 6 import java.io.IOException;
 7 
 8 class ChannelBufferByteOutput implements ByteOutput {
 9 
10     private final ByteBuf buffer;
11 
12     public ChannelBufferByteOutput(ByteBuf buffer) {
13         this.buffer = buffer;
14     }
15 
16     @Override
17     public void close() throws IOException {
18     }
19 
20     @Override
21     public void flush() throws IOException {
22     }
23 
24     @Override
25     public void write(int b) throws IOException {
26         buffer.writeByte(b);
27     }
28 
29     @Override
30     public void write(byte[] bytes) throws IOException {
31         buffer.writeBytes(bytes);
32     }
33 
34     @Override
35     public void write(byte[] bytes, int srcIndex, int length) throws IOException {
36         buffer.writeBytes(bytes, srcIndex, length);
37     }
38 
39     
40     ByteBuf getBuffer() {
41         return buffer;
42     }
43 }

 

 

 

④NettyMessageDecoder、MarshallingDecoder、ChannelBufferByteInput

 1 package com.cherry.netty.demo.protocolstack.decode;
 2 
 3 import java.io.IOException;
 4 import java.util.HashMap;
 5 import java.util.Map;
 6 
 7 import com.cherry.netty.demo.protocolstack.pojo.Header;
 8 import com.cherry.netty.demo.protocolstack.pojo.NettyMessage;
 9 
10 import io.netty.buffer.ByteBuf;
11 import io.netty.channel.ChannelHandlerContext;
12 import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
13 
14 public class NettyMessageDecoder extends LengthFieldBasedFrameDecoder {
15     MarshallingDecoder marshallingDecoder;
16 
17     public NettyMessageDecoder(int maxFrameLength, int lengthFieldOffset,
18                                int lengthFieldLength) throws IOException {
19         super(maxFrameLength, lengthFieldOffset, lengthFieldLength);
20         marshallingDecoder = new MarshallingDecoder();
21     }
22 
23     @Override
24     protected Object decode(ChannelHandlerContext ctx, ByteBuf in)
25             throws Exception {
26         ByteBuf frame = (ByteBuf) super.decode(ctx, in);
27         if (frame == null) {
28             return null;
29         }
30 
31         NettyMessage message = new NettyMessage();
32         Header header = new Header();
33         header.setCrcCode(frame.readInt());
34         header.setLength(frame.readInt());
35         header.setSessionID(frame.readLong());
36         header.setType(frame.readByte());
37         header.setPriority(frame.readByte());
38 
39         int size = frame.readInt();
40         if (size > 0) {
41             Map<String, Object> attch = new HashMap<String, Object>(size);
42             int keySize = 0;
43             byte[] keyArray = null;
44             String key = null;
45             for (int i = 0; i < size; i++) {
46                 keySize = frame.readInt();
47                 keyArray = new byte[keySize];
48                 frame.readBytes(keyArray);
49                 key = new String(keyArray, "UTF-8");
50                 attch.put(key, marshallingDecoder.decode(frame));
51             }
52             keyArray = null;
53             key = null;
54             header.setAttachment(attch);
55         }
56         if (frame.readableBytes() > 4) {
57             message.setBody(marshallingDecoder.decode(frame));
58         }
59         message.setHeader(header);
60         return message;
61     }
62 }

 

 

 1 package com.cherry.netty.demo.protocolstack.decode;
 2 
 3 
 4 import java.io.IOException;
 5 
 6 import org.jboss.marshalling.ByteInput;
 7 import org.jboss.marshalling.Unmarshaller;
 8 
 9 import com.cherry.netty.demo.protocolstack.utils.MarshallingCodeCFactory;
10 
11 import io.netty.buffer.ByteBuf;
12 
13 public class MarshallingDecoder {
14 
15     private final Unmarshaller unmarshaller;
16     
17     
18     
19     public MarshallingDecoder() throws IOException {
20         unmarshaller = MarshallingCodeCFactory.buildUnMarshalling();
21     }
22 
23     protected Object decode(ByteBuf in) throws IOException, ClassNotFoundException {
24         int objectSize = in.readInt();
25         ByteBuf buf = in.slice(in.readerIndex(), objectSize);
26         ByteInput input = new ChannelBufferByteInput(buf);
27         try {
28             unmarshaller.start(input);
29             Object obj = unmarshaller.readObject();
30             unmarshaller.finish();
31             in.readerIndex(in.readerIndex() + objectSize);
32             return obj;
33         } finally {
34             unmarshaller.close();
35         }
36     }
37 
38 }

 

 1 package com.cherry.netty.demo.protocolstack.decode;
 2 
 3 import io.netty.buffer.ByteBuf;
 4 import org.jboss.marshalling.ByteInput;
 5 
 6 import java.io.IOException;
 7 
 8 
 9 class ChannelBufferByteInput implements ByteInput {
10 
11     private final ByteBuf buffer;
12 
13     public ChannelBufferByteInput(ByteBuf buffer) {
14         this.buffer = buffer;
15     }
16 
17     @Override
18     public void close() throws IOException {
19         // nothing to do
20     }
21 
22     @Override
23     public int available() throws IOException {
24         return buffer.readableBytes();
25     }
26 
27     @Override
28     public int read() throws IOException {
29         if (buffer.isReadable()) {
30             return buffer.readByte() & 0xff;
31         }
32         return -1;
33     }
34 
35     @Override
36     public int read(byte[] array) throws IOException {
37         return read(array, 0, array.length);
38     }
39 
40     @Override
41     public int read(byte[] dst, int dstIndex, int length) throws IOException {
42         int available = available();
43         if (available == 0) {
44             return -1;
45         }
46 
47         length = Math.min(available, length);
48         buffer.readBytes(dst, dstIndex, length);
49         return length;
50     }
51 
52     @Override
53     public long skip(long bytes) throws IOException {
54         int readable = buffer.readableBytes();
55         if (readable < bytes) {
56             bytes = readable;
57         }
58         buffer.readerIndex((int) (buffer.readerIndex() + bytes));
59         return bytes;
60     }
61 
62 }

 

 

 

 

3、握手和安全认证

  

 1 package com.cherry.netty.demo.protocolstack.loginhandler;
 2 
 3 import org.apache.log4j.Logger;
 4 
 5 import com.cherry.netty.demo.protocolstack.pojo.Header;
 6 import com.cherry.netty.demo.protocolstack.pojo.MessageType;
 7 import com.cherry.netty.demo.protocolstack.pojo.NettyMessage;
 8 
 9 import io.netty.channel.ChannelHandlerAdapter;
10 import io.netty.channel.ChannelHandlerContext;
11 
12 public class LoginAuthReqHandler extends ChannelHandlerAdapter {
13     
14     private static final Logger logger = Logger.getLogger(LoginAuthReqHandler.class);
15     
16     @Override
17     public void channelActive(ChannelHandlerContext ctx) throws Exception {
18         ctx.writeAndFlush(buildLoginReq());
19     }
20 
21     
22     @Override
23     public void channelRead(ChannelHandlerContext ctx, Object msg)
24             throws Exception {
25         NettyMessage message = (NettyMessage) msg;
26 
27         if (message.getHeader() != null
28                 && message.getHeader().getType() == MessageType.LOGIN_RESP.value()) {
29             byte loginResult = (byte) message.getBody();
30             if (loginResult != (byte) 0) {
31                 ctx.close();
32             } else {
33                 logger.info("Login is ok : " + message);
34                 ctx.fireChannelRead(msg);
35             }
36         } else
37             ctx.fireChannelRead(msg);
38     }
39 
40     
41     private NettyMessage buildLoginReq() {
42         NettyMessage message = new NettyMessage();
43         Header header = new Header();
44         header.setType(MessageType.LOGIN_REQ.value());
45         message.setHeader(header);
46         return message;
47     }
48 
49     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
50             throws Exception {
51         ctx.fireExceptionCaught(cause);
52     }
53 
54 }

 

 

 1 package com.cherry.netty.demo.protocolstack.loginhandler;
 2 
 3 import java.net.InetSocketAddress;
 4 import java.util.Map;
 5 import java.util.concurrent.ConcurrentHashMap;
 6 
 7 import org.apache.log4j.Logger;
 8 
 9 import com.cherry.netty.demo.protocolstack.pojo.Header;
10 import com.cherry.netty.demo.protocolstack.pojo.MessageType;
11 import com.cherry.netty.demo.protocolstack.pojo.NettyMessage;
12 
13 import io.netty.channel.ChannelHandlerAdapter;
14 import io.netty.channel.ChannelHandlerContext;
15 
16 public class LoginAuthRespHandler extends ChannelHandlerAdapter {
17 
18     private static final Logger logger = Logger.getLogger(LoginAuthRespHandler.class);
19 
20     private Map<String, Boolean> nodeCheck = new ConcurrentHashMap<String, Boolean>();
21     private String[] whitekList = { "127.0.0.1", "192.168.11.246", "192.168.31.242" };
22 
23     @Override
24     public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
25         NettyMessage message = (NettyMessage) msg;
26 
27         if (message.getHeader() != null && message.getHeader().getType() == MessageType.LOGIN_REQ.value()) {
28             String nodeIndex = ctx.channel().remoteAddress().toString();
29             NettyMessage loginResp = null;
30             // 重复登陆,拒绝
31             if (nodeCheck.containsKey(nodeIndex)) {
32                 loginResp = buildResponse((byte) -1);
33             } else {
34                 InetSocketAddress address = (InetSocketAddress) ctx.channel().remoteAddress();
35                 String ip = address.getAddress().getHostAddress();
36                 boolean isOK = false;
37                 for (String WIP : whitekList) {
38                     if (WIP.equals(ip)) {
39                         isOK = true;
40                         break;
41                     }
42                 }
43                 loginResp = isOK ? buildResponse((byte) 0) : buildResponse((byte) -1);
44                 if (isOK)
45                     nodeCheck.put(nodeIndex, true);
46             }
47             logger.info("The login response is : " + loginResp + " body [" + loginResp.getBody() + "]");
48             ctx.writeAndFlush(loginResp);
49         } else {
50             ctx.fireChannelRead(msg);
51         }
52     }
53 
54     private NettyMessage buildResponse(byte result) {
55         NettyMessage message = new NettyMessage();
56         Header header = new Header();
57         header.setType(MessageType.LOGIN_RESP.value());
58         message.setHeader(header);
59         message.setBody(result);
60         return message;
61     }
62 
63     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
64         cause.printStackTrace();
65         nodeCheck.remove(ctx.channel().remoteAddress().toString());
66         ctx.close();
67         ctx.fireExceptionCaught(cause);
68     }
69 }

 

 

4、心跳检测机制

 1 package com.cherry.netty.demo.protocolstack.hearthandler;
 2 
 3 import java.util.concurrent.TimeUnit;
 4 
 5 import com.cherry.netty.demo.protocolstack.pojo.Header;
 6 import com.cherry.netty.demo.protocolstack.pojo.MessageType;
 7 import com.cherry.netty.demo.protocolstack.pojo.NettyMessage;
 8 
 9 import io.netty.channel.ChannelHandlerAdapter;
10 import io.netty.channel.ChannelHandlerContext;
11 import io.netty.util.concurrent.ScheduledFuture;
12 
13 
14 public class HeartBeatReqHandler extends ChannelHandlerAdapter {
15     
16     private volatile ScheduledFuture<?> heartBeat;
17 
18     @Override
19     public void channelActive(ChannelHandlerContext ctx) throws Exception {
20         // TODO Auto-generated method stub
21         super.channelActive(ctx);
22     }
23 
24     @Override
25     public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
26         // TODO Auto-generated method stub
27         NettyMessage message = (NettyMessage) msg;
28         if(message.getHeader() != null && message.getHeader().getType()==MessageType.LOGIN_RESP.value()){
29             heartBeat = ctx.executor().scheduleAtFixedRate(new HeartBeatReqHandler.HeartBeatTask(ctx), 0, 5000, TimeUnit.MILLISECONDS);
30         }else if(message.getHeader() !=null && message.getHeader().getType()==MessageType.HEARTBEAT_RESP.value()){
31             System.out.println("Client receive server heart beat message:---> "+message);
32         }else{
33             ctx.fireChannelRead(msg);
34         }
35     }
36 
37     private class HeartBeatTask implements Runnable{
38         
39         private final ChannelHandlerContext ctx;
40         
41         public HeartBeatTask(final ChannelHandlerContext ctx) {
42             this.ctx = ctx;
43         }
44 
45         @Override
46         public void run() {
47             NettyMessage heatBeat = buildHeatBeat();
48             System.out.println("Client send heart beat message to server:---> "+heatBeat);
49             ctx.writeAndFlush(heatBeat);
50         }
51 
52         private NettyMessage buildHeatBeat() {
53             NettyMessage message = new NettyMessage();
54             Header header = new Header();
55             header.setType(MessageType.HEARTBEAT_REQ.value());
56             message.setHeader(header);
57             return message;
58         }
59     }
60 
61     @Override
62     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
63         if(heartBeat != null){
64             heartBeat.cancel(true);
65             heartBeat = null;
66         }
67         ctx.fireExceptionCaught(cause);
68     }
69     
70     
71 }

 

 

 1 package com.cherry.netty.demo.protocolstack.hearthandler;
 2 
 3 import com.cherry.netty.demo.protocolstack.pojo.Header;
 4 import com.cherry.netty.demo.protocolstack.pojo.MessageType;
 5 import com.cherry.netty.demo.protocolstack.pojo.NettyMessage;
 6 
 7 import io.netty.channel.ChannelHandlerAdapter;
 8 import io.netty.channel.ChannelHandlerContext;
 9 
10 public class HeartBeatRespHandler extends ChannelHandlerAdapter {
11 
12     @Override
13     public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
14         NettyMessage message = (NettyMessage) msg;
15         if(message.getHeader() != null && message.getHeader().getType()==MessageType.HEARTBEAT_REQ.value()){
16             System.out.println("Server receive client heart beat message:---> "+message);
17             NettyMessage heartBeat = buildHeatBeat();
18             System.out.println("Server send heart beat response message to client:---> "+heartBeat);
19             ctx.writeAndFlush(heartBeat);
20         }else{
21             ctx.fireChannelRead(msg);
22         }
23     }
24 
25     private NettyMessage buildHeatBeat() {
26         NettyMessage message = new NettyMessage();
27         Header header = new Header();
28         header.setType(MessageType.HEARTBEAT_RESP.value());
29         message.setHeader(header);
30         return message;
31     }
32 
33     
34 }

 

 

5、客户端

 1 package com.cherry.netty.demo.protocolstack;
 2 
 3 import java.net.InetSocketAddress;
 4 import java.util.concurrent.Executors;
 5 import java.util.concurrent.ScheduledExecutorService;
 6 import java.util.concurrent.TimeUnit;
 7 
 8 import com.cherry.netty.demo.protocolstack.decode.NettyMessageDecoder;
 9 import com.cherry.netty.demo.protocolstack.encode.NettyMessageEncoder;
10 import com.cherry.netty.demo.protocolstack.hearthandler.HeartBeatReqHandler;
11 import com.cherry.netty.demo.protocolstack.loginhandler.LoginAuthReqHandler;
12 import com.cherry.netty.demo.protocolstack.pojo.NettyConstant;
13 
14 import io.netty.bootstrap.Bootstrap;
15 import io.netty.channel.ChannelFuture;
16 import io.netty.channel.ChannelInitializer;
17 import io.netty.channel.ChannelOption;
18 import io.netty.channel.EventLoopGroup;
19 import io.netty.channel.nio.NioEventLoopGroup;
20 import io.netty.channel.socket.SocketChannel;
21 import io.netty.channel.socket.nio.NioSocketChannel;
22 import io.netty.handler.timeout.ReadTimeoutHandler;
23 
24 public class NettyClient {
25     
26     private ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
27     
28     
29     public void connect(int port,String host) throws InterruptedException{
30         EventLoopGroup group = new NioEventLoopGroup();
31         try {
32             Bootstrap b = new Bootstrap();
33             b.group(group).channel(NioSocketChannel.class)
34             .option(ChannelOption.TCP_NODELAY, true)
35             .handler(new ChannelInitializer<SocketChannel>() {
36 
37                 @Override
38                 protected void initChannel(SocketChannel ch) throws Exception {
39                     ch.pipeline().addLast(new NettyMessageDecoder(1024*1024, 4, 4));
40                     ch.pipeline().addLast("meaageEncoder",new NettyMessageEncoder());
41                     ch.pipeline().addLast("readTimeoutHandler",new ReadTimeoutHandler(50));
42                     ch.pipeline().addLast("loginAuthHandler",new LoginAuthReqHandler());
43                     ch.pipeline().addLast("heartBeatHandler",new HeartBeatReqHandler());
44                     
45                 }
46 
47             });
48             // 发起异步连接操作
49             ChannelFuture future = b.connect(
50                     new InetSocketAddress(host, port), 
51                     new InetSocketAddress(NettyConstant.LOCALIP, NettyConstant.LOCAL_PORT)).sync();
52             System.out.println("Netty client start ok . remoteAddress( "+host+":"+port+"),localAddress("+NettyConstant.LOCALIP+":"+NettyConstant.LOCAL_PORT+")");
53             
54             future.channel().closeFuture().sync();
55             
56         } finally {
57             executor.execute(new Runnable() {
58                 
59                 @Override
60                 public void run() {
61                     try {
62                         TimeUnit.SECONDS.sleep(5);
63                         try {
64                             // 发起重连操作
65                             connect(NettyConstant.REMOTE_PORT, NettyConstant.REMOTEIP);
66                         } catch (Exception e) {
67                             System.out.println("NettyClient 发起重连操作异常");
68                             e.printStackTrace();
69                         }
70                     } catch (InterruptedException e) {
71                         e.printStackTrace();
72                     }
73                 }
74             });
75         }
76     }
77     public static void main(String[] args) throws InterruptedException {
78         new NettyClient().connect(NettyConstant.REMOTE_PORT, NettyConstant.REMOTEIP);
79     }
80 }

 

 

6、服务端

 

 1 package com.cherry.netty.demo.protocolstack;
 2 
 3 import com.cherry.netty.demo.protocolstack.decode.NettyMessageDecoder;
 4 import com.cherry.netty.demo.protocolstack.encode.NettyMessageEncoder;
 5 import com.cherry.netty.demo.protocolstack.hearthandler.HeartBeatRespHandler;
 6 import com.cherry.netty.demo.protocolstack.loginhandler.LoginAuthRespHandler;
 7 import com.cherry.netty.demo.protocolstack.pojo.NettyConstant;
 8 
 9 import io.netty.bootstrap.ServerBootstrap;
10 import io.netty.channel.ChannelFuture;
11 import io.netty.channel.ChannelInitializer;
12 import io.netty.channel.ChannelOption;
13 import io.netty.channel.EventLoopGroup;
14 import io.netty.channel.nio.NioEventLoopGroup;
15 import io.netty.channel.socket.SocketChannel;
16 import io.netty.channel.socket.nio.NioServerSocketChannel;
17 import io.netty.handler.logging.LogLevel;
18 import io.netty.handler.logging.LoggingHandler;
19 import io.netty.handler.timeout.ReadTimeoutHandler;
20 
21 public class NettyServer {
22     
23     public void bind() throws InterruptedException{
24         EventLoopGroup bossGroup = new NioEventLoopGroup();
25         EventLoopGroup workerGroup = new NioEventLoopGroup();
26         ServerBootstrap b = new ServerBootstrap();
27         b.group(bossGroup, workerGroup)
28         .channel(NioServerSocketChannel.class)
29         .option(ChannelOption.SO_BACKLOG, 100)
30         .handler(new LoggingHandler(LogLevel.INFO))
31         .childHandler(new ChannelInitializer<SocketChannel>() {
32 
33             @Override
34             protected void initChannel(SocketChannel ch) throws Exception {
35                 ch.pipeline().addLast(new NettyMessageDecoder(1024*1024, 4, 4));
36                 ch.pipeline().addLast(new NettyMessageEncoder());
37                 ch.pipeline().addLast("readTimeoutHandler",new ReadTimeoutHandler(50));
38                 ch.pipeline().addLast(new LoginAuthRespHandler());
39                 ch.pipeline().addLast("HeartBeatHandler",new HeartBeatRespHandler());
40             }
41         });
42         
43         ChannelFuture future = b.bind(NettyConstant.REMOTEIP,NettyConstant.REMOTE_PORT).sync();
44         System.out.println("Netty server start ok : "+(NettyConstant.REMOTEIP+":"+NettyConstant.REMOTE_PORT));
45 
46         future.channel().closeFuture().sync();
47     }
48     public static void main(String[] args) throws InterruptedException {
49         new NettyServer().bind();
50     }
51 
52 }

 

posted @ 2018-12-14 15:40  sunshine052697  阅读(274)  评论(0编辑  收藏  举报