• 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 }
  • 相关阅读:
    CSS颜色十六进制值规律
    linux清理内存命令
    一些常用的linux命令
    读《DOOM启示录》随想
    日常分享:关于时间复杂度和空间复杂度的一些优化心得分享(C#)
    .netcore过滤器有以下几种类型
    RabbitMQ十:重要方法简述(参数)
    git 配置 ssh
    log4net学习笔记
    redis下载与安装
  • 原文地址:https://www.cnblogs.com/sunshine052697/p/10119752.html
Copyright © 2020-2023  润新知