netty自定义协议

来源:互联网 发布:淘宝公司内部员工管理 编辑:程序博客网 时间:2024/05/17 21:44

《netty权威指南》一书中关于自定义协议开发的源码中有一部分错误导致代码无法运行,加了一点改变可以完美运行了,

package nettyAgreement.decoder;import java.util.HashMap;import java.util.Map;import io.netty.buffer.ByteBuf;import io.netty.channel.ChannelHandlerContext;import io.netty.handler.codec.LengthFieldBasedFrameDecoder;import nettyAgreement.Header;import nettyAgreement.MarshallingCodecFactory;import nettyAgreement.NettyMessage;/** * 消息解码类 * @author <font color="red"><b>Gong.YiYang</b></font> * @Date 2017年7月19日 * @Version  * @Description */public class NettyMessageDecoder extends LengthFieldBasedFrameDecoder {NettyMarshallingDecoder marshallingDecoder;public NettyMessageDecoder(int maxFrameLength, int lengthFieldOffset, int lengthFieldLength) {super(maxFrameLength, lengthFieldOffset, lengthFieldLength);// TODO Auto-generated constructor stubmarshallingDecoder = MarshallingCodecFactory.buMarshallingDecoder();}public NettyMessageDecoder(int maxFrameLength,            int lengthFieldOffset, int lengthFieldLength,            int lengthAdjustment, int initialBytesToStrip) {// TODO Auto-generated constructor stubsuper( maxFrameLength,             lengthFieldOffset,  lengthFieldLength,             lengthAdjustment,  initialBytesToStrip);marshallingDecoder = MarshallingCodecFactory.buMarshallingDecoder();}@Overrideprotected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {// TODO Auto-generated method stubByteBuf frame = (ByteBuf)super.decode(ctx, in);if (frame == null) {return null;}NettyMessage message = new NettyMessage();Header header = new Header();header.setCrcCode(frame.readInt());header.setLength(frame.readInt());header.setSessionID(frame.readLong());header.setType(frame.readByte());header.setPriority(frame.readByte());int size = frame.readInt();if (size>0) {Map<String, Object> attch = new HashMap<String,Object>(size);int keySize = 0;byte[] keyArray = null;String key = null;for (int i = 0; i < size; i++) {keySize = frame.readInt();keyArray = new byte[keySize];frame.readBytes(keyArray);key = new String(keyArray, "UTF-8");attch.put(key, marshallingDecoder.decode(ctx, frame));}keyArray = null;key = null;header.setAttachment(attch);}if (frame.readableBytes() > 4) {message.setBody(marshallingDecoder.decode(ctx, frame));}message.setHeader(header);return message;}}

package nettyAgreement.encoder;import java.util.List;import java.util.Map.Entry;import io.netty.buffer.ByteBuf;import io.netty.buffer.Unpooled;import io.netty.channel.ChannelHandlerContext;import io.netty.handler.codec.MessageToMessageEncoder;import nettyAgreement.MarshallingCodecFactory;import nettyAgreement.NettyMessage;/** * 消息编码 * @author <font color="red"><b>Gong.YiYang</b></font> * @Date 2017年7月19日 * @Version  * @Description */public class NettyMessageEncoder extends MessageToMessageEncoder<NettyMessage>{private NettyMarshallingEncoder marshallingEncoder;public NettyMessageEncoder() {this.marshallingEncoder = MarshallingCodecFactory.buildMarshallingEncoder();}@Overridepublic void encode(ChannelHandlerContext ctx, NettyMessage msg, List<Object> out) throws Exception {// TODO Auto-generated method stubif (msg == null || msg.getHeader() == null) {throw new Exception("This encode message is null");}ByteBuf sendBuffer = Unpooled.buffer();sendBuffer.writeInt(msg.getHeader().getCrcCode());sendBuffer.writeInt(msg.getHeader().getLength());sendBuffer.writeLong(msg.getHeader().getSessionID());sendBuffer.writeByte(msg.getHeader().getType());sendBuffer.writeByte(msg.getHeader().getPriority());sendBuffer.writeInt(msg.getHeader().getAttachment().size());String key = null;byte[] keyArray = null;Object value = null;for (Entry<String, Object> param : msg.getHeader().getAttachment().entrySet()) { key = param.getKey(); keyArray = key.getBytes("UTF-8"); sendBuffer.writeInt(keyArray.length); sendBuffer.writeBytes(keyArray); value = param.getValue(); marshallingEncoder.encode(ctx, value, sendBuffer);}key = null;keyArray = null;value = null;if (msg.getBody() != null) {marshallingEncoder.encode(ctx, msg.getBody(), sendBuffer);}elsesendBuffer.writeInt(0);  // 在第4个字节出写入Buffer的长度  int readableBytes = sendBuffer.readableBytes();  sendBuffer.setInt(4, readableBytes);  // 把Message添加到List传递到下一个Handler   out.add(sendBuffer);  }}

package nettyAgreement;/** * 定义消息头 * @author <font color="red"><b>Gong.YiYang</b></font> * @Date 2017年7月19日 * @Version  * @Description */import java.util.HashMap;import java.util.Map;public final class Header {private int crcCode = 0xabef0101;//长度32,private int length;//消息长度32private long sessionID;//会话ID64private byte type;//消息类型8private byte priority;//消息优先级8private Map<String, Object> attachment = new HashMap<String,Object>();//附件public final int getCrcCode() {return crcCode;}public final void setCrcCode(int crcCode) {this.crcCode = crcCode;}public final int getLength() {return length;}public final void setLength(int length) {this.length = length;}public final long getSessionID() {return sessionID;}public final void setSessionID(long sessionID) {this.sessionID = sessionID;}public final byte getType() {return type;}public final void setType(byte type) {this.type = type;}public final byte getPriority() {return priority;}public final void setPriority(byte priority) {this.priority = priority;}public final Map<String, Object> getAttachment() {return attachment;}public final void setAttachment(Map<String, Object> attachment) {this.attachment = attachment;}@Overridepublic String toString() {return "Header [crcCode=" + crcCode + ", length=" + length + ", sessionID=" + sessionID + ", type=" + type+ ", priority=" + priority + ", attachment=" + attachment + "]";}}

package nettyAgreement;import java.util.concurrent.TimeUnit;import io.netty.channel.ChannelHandlerAdapter;import io.netty.channel.ChannelHandlerContext;import io.netty.util.concurrent.ScheduledFuture;import nettyAgreement.Header;import nettyAgreement.MessageType;import nettyAgreement.NettyMessage;/** * 客户端心跳消息 * @author <font color="red"><b>Gong.YiYang</b></font> * @Date 2017年7月20日 * @Version  * @Description */public class HeartBeatReqHandler extends ChannelHandlerAdapter {private volatile ScheduledFuture<?> heartBeat;@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {// TODO Auto-generated method stubNettyMessage message = (NettyMessage)msg;//握手成功,主动发送心跳消息if (message.getHeader() != null && message.getHeader().getType() == MessageType.LOGIN_RESP.type) {heartBeat = ctx.executor().scheduleAtFixedRate(new HeartBeatReqHandler.HeartBeatTask(ctx), 0, 5000, TimeUnit.MILLISECONDS);}else if (message.getHeader() != null && message.getHeader().getType() == MessageType.HEART_RESP.type) {System.out.println("Client receive server heart beat message : -->"+message);}else ctx.fireChannelRead(msg);}//心跳任务private class HeartBeatTask implements Runnable{private final ChannelHandlerContext ctx;public HeartBeatTask(final ChannelHandlerContext ctx) {this.ctx = ctx;}@Overridepublic void run() {// TODO Auto-generated method stubNettyMessage heartBeat = buildHeartBeat();System.out.println("Client send heart beat message to server : -->"+heartBeat);ctx.writeAndFlush(heartBeat);}private NettyMessage buildHeartBeat(){NettyMessage message = new NettyMessage();Header header = new Header();header.setType(MessageType.HEART_REQ.type);message.setHeader(header);return message;}}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {// TODO Auto-generated method stubif (heartBeat != null) {heartBeat.cancel(true);heartBeat=null;}ctx.fireExceptionCaught(cause);}}

package nettyAgreement;import io.netty.channel.ChannelHandlerAdapter;import io.netty.channel.ChannelHandlerContext;/** * 服务端心跳消息 * @author <font color="red"><b>Gong.YiYang</b></font> * @Date 2017年7月20日 * @Version  * @Description */public class HeartBeatRespHandler extends ChannelHandlerAdapter {@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {// TODO Auto-generated method stubNettyMessage message = (NettyMessage)msg;if (message.getHeader() != null && message.getHeader().getType() == MessageType.HEART_REQ.type) {System.out.println("Receive client beat message : -->"+message);NettyMessage heartBeat = buildHeartBeat();System.out.println("Send heart beat message to client : -->"+heartBeat);ctx.writeAndFlush(heartBeat);}else ctx.fireChannelRead(msg);}private NettyMessage buildHeartBeat(){NettyMessage message = new NettyMessage();Header header = new Header();header.setType(MessageType.HEART_RESP.type);message.setHeader(header);return message;}}

package nettyAgreement;import io.netty.channel.ChannelHandlerAdapter;import io.netty.channel.ChannelHandlerContext;/** * 客户端握手认证 *  * @author <font color="red"><b>Gong.YiYang</b></font> * @Date 2017年7月20日 * @Version * @Description */public class LoginAuthReqHandler extends ChannelHandlerAdapter {@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {// TODO Auto-generated method stubctx.writeAndFlush(buildLoginReq());}@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {// TODO Auto-generated method stubNettyMessage message = (NettyMessage)msg;//如果是握手应答消息,需要判断是否认证成功if (message.getHeader() != null && message.getHeader().getType() == MessageType.LOGIN_RESP.type) {byte loginResult = (byte)message.getBody();if (loginResult != (byte)0) {//握手失败,关闭连接;0表示认证通过,握手成功ctx.close();}else {System.out.println("login is ok :"+message);ctx.fireChannelRead(msg);}}else {ctx.fireChannelRead(msg);}}private NettyMessage buildLoginReq() {// TODO Auto-generated method stubNettyMessage message = new NettyMessage();Header header = new Header();header.setType(MessageType.LOGIN_REQ.type);message.setHeader(header);return message;}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {// TODO Auto-generated method stubctx.fireExceptionCaught(cause);}}

package nettyAgreement;import java.net.InetSocketAddress;import java.util.Map;import java.util.concurrent.ConcurrentHashMap;import io.netty.channel.ChannelHandlerAdapter;import io.netty.channel.ChannelHandlerContext;/** * 服务端握手请求,安全认证 * @author <font color="red"><b>Gong.YiYang</b></font> * @Date 2017年7月20日 * @Version  * @Description */public class LoginAuthRespHandler extends ChannelHandlerAdapter {private Map<String, Boolean> nodeCheck = new ConcurrentHashMap<String,Boolean>();private String[] whiteList = {"127.0.0.1","192.168.1.104"};//白名单@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {// TODO Auto-generated method stubNettyMessage message = (NettyMessage)msg;//如果是握手请求消息处理,其它消息透传if (message.getHeader() != null && message.getHeader().getType() == MessageType.LOGIN_REQ.type) {String nodeIndex = ctx.channel().remoteAddress().toString();//拿到远程地址NettyMessage loginResp = null;//重复登录,拒绝if (nodeCheck.containsKey(nodeIndex)) {loginResp = buildResponse((byte)-1);}else {InetSocketAddress address = (InetSocketAddress)ctx.channel().remoteAddress();String ip = address.getAddress().getHostAddress();boolean isOK = false;for (String Wip : whiteList) {if (Wip.equals(ip)) {isOK = true;break;}}loginResp = isOK ? buildResponse((byte)0) : buildResponse((byte)-1);if (isOK) nodeCheck.put(nodeIndex, true);ConnectList.list.put(ip, ctx);}System.out.println("The login response is:"+loginResp+"body["+loginResp.getBody()+"]");ctx.writeAndFlush(loginResp);}else {ctx.fireChannelRead(msg);}}private NettyMessage buildResponse(byte result) {// TODO Auto-generated method stubNettyMessage message = new NettyMessage();Header header = new Header();header.setType(MessageType.LOGIN_RESP.type);message.setHeader(header);message.setBody(result);return message;}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {// TODO Auto-generated method stubnodeCheck.remove(ctx.channel().remoteAddress().toString());ctx.fireExceptionCaught(cause);}}

package nettyAgreement;/** * 消息类型 * @author <font color="red"><b>Gong.YiYang</b></font> * @Date 2017年7月20日 * @Version  * @Description */public enum MessageType {BUSINESS_REQ((byte)0,"业务请求消息"),BUSINESS_RESP((byte)1,"业务应答消息"),ONE_WAY((byte)2,"业务ONE WAY消息"),LOGIN_REQ((byte)3,"握手请求消息"),LOGIN_RESP((byte)4,"握手应答消息"),HEART_REQ((byte)5,"心跳请求消息"),HEART_RESP((byte)6,"心跳应答消息");public byte type;String describe;private MessageType(byte type, String describe) {this.type = type;this.describe = describe;}}

package nettyAgreement;public class NettyConstant {public static final String REMOTEIP = "127.0.0.1";public static final int PORT = 8080;public static final int LOCAL_PORT = 12088;public static final String LOCALIP = "127.0.0.1";}

package nettyAgreement;/** * 消息定义 * @author <font color="red"><b>Gong.YiYang</b></font> * @Date 2017年7月18日 * @Version  * @Description */public final class NettyMessage {private Header header;//消息头private Object body;//消息体public final Header getHeader() {return header;}public final void setHeader(Header header) {this.header = header;}public final Object getBody() {return body;}public final void setBody(Object body) {this.body = body;}@Overridepublic String toString() {return "NettyMessage [header=" + header + "]";}}

package nettyAgreement.client;/** * 客户端 * @author <font color="red"><b>Gong.YiYang</b></font> * @Date 2017年7月21日 * @Version  * @Description */import java.net.InetSocketAddress;import java.util.concurrent.Executors;import java.util.concurrent.ScheduledExecutorService;import java.util.concurrent.TimeUnit;import io.netty.bootstrap.Bootstrap;import io.netty.channel.ChannelFuture;import io.netty.channel.ChannelInitializer;import io.netty.channel.ChannelOption;import io.netty.channel.EventLoopGroup;import io.netty.channel.nio.NioEventLoopGroup;import io.netty.channel.socket.SocketChannel;import io.netty.channel.socket.nio.NioSocketChannel;import io.netty.handler.timeout.ReadTimeoutHandler;import nettyAgreement.HeartBeatReqHandler;import nettyAgreement.LoginAuthReqHandler;import nettyAgreement.NettyConstant;import nettyAgreement.decoder.NettyMessageDecoder;import nettyAgreement.encoder.NettyMessageEncoder;public class NettyClient {private ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);EventLoopGroup group = new NioEventLoopGroup();public void connect(int port,String host) throws InterruptedException{try {Bootstrap b = new Bootstrap();b.group(group).channel(NioSocketChannel.class).option(ChannelOption.TCP_NODELAY, true).handler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {// TODO Auto-generated method stubch.pipeline().addLast(new NettyMessageDecoder(1024 * 1024, 4, 4,-8,0));ch.pipeline().addLast("MessageEncoder",new NettyMessageEncoder());ch.pipeline().addLast("readTimeOutHandler",new ReadTimeoutHandler(50));ch.pipeline().addLast("LoginAuthHandler",new LoginAuthReqHandler());ch.pipeline().addLast("HeartBeatHandler",new HeartBeatReqHandler());}});//发起异步连接操作ChannelFuture future = b.connect(new InetSocketAddress(host, port), new InetSocketAddress(NettyConstant.LOCALIP, NettyConstant.LOCAL_PORT)).sync();future.channel().closeFuture().sync();}finally {//所有资源释放完成之后,清空资源,再次发起重连操作executor.execute(new Runnable() {@Overridepublic void run() {// TODO Auto-generated method stubtry {TimeUnit.SECONDS.sleep(5);try {connect(NettyConstant.PORT, NettyConstant.REMOTEIP);//发起重连操作} catch (Exception e) {// TODO: handle exceptione.printStackTrace();}} catch (InterruptedException e) {// TODO: handle exceptione.printStackTrace();}}});} }public static void main(String[] args) throws InterruptedException {new NettyClient().connect(NettyConstant.PORT, NettyConstant.REMOTEIP);}}

package nettyAgreement.server;import io.netty.bootstrap.ServerBootstrap;import io.netty.channel.ChannelFuture;import io.netty.channel.ChannelInitializer;import io.netty.channel.ChannelOption;import io.netty.channel.nio.NioEventLoopGroup;import io.netty.channel.socket.SocketChannel;import io.netty.channel.socket.nio.NioServerSocketChannel;import io.netty.handler.logging.LogLevel;import io.netty.handler.logging.LoggingHandler;import io.netty.handler.timeout.ReadTimeoutHandler;import nettyAgreement.HeartBeatRespHandler;import nettyAgreement.LoginAuthRespHandler;import nettyAgreement.NettyConstant;import nettyAgreement.decoder.NettyMessageDecoder;import nettyAgreement.encoder.NettyMessageEncoder;/** * 服务端 * @author <font color="red"><b>Gong.YiYang</b></font> * @Date 2017年7月21日 * @Version  * @Description */public class NettyServer {public void build() throws InterruptedException{NioEventLoopGroup bossGroup = new NioEventLoopGroup();NioEventLoopGroup workGroup = new NioEventLoopGroup();try {ServerBootstrap b = new ServerBootstrap();b.group(bossGroup, workGroup).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 100).handler(new LoggingHandler(LogLevel.INFO)).childHandler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {// TODO Auto-generated method stubch.pipeline().addLast(new NettyMessageDecoder(1024 * 1024, 4, 4,-8,0));ch.pipeline().addLast(new NettyMessageEncoder());ch.pipeline().addLast("readTimeOutHandler",new ReadTimeoutHandler(50));ch.pipeline().addLast(new LoginAuthRespHandler());ch.pipeline().addLast("HeartBeatHandler",new HeartBeatRespHandler());}});//绑定端口,等待同步 ChannelFuture future = b.bind(NettyConstant.PORT).sync();System.out.println("Netty server start ok :"+(NettyConstant.REMOTEIP+":"+NettyConstant.PORT));future.channel().closeFuture().sync();} finally{bossGroup.shutdownGracefully();workGroup.shutdownGracefully();}}public static void main(String[] args) throws InterruptedException {new NettyServer().build();}}


原创粉丝点击