真正实现Netty私有协议开发
首先《Netty权威指南》私有协议开发那一章的样例代码是编译不通过的(但是这丝毫不影响本书的价值)
处理方案可以参考:http://www.itnose.net/detail/6112870.html
另外这一章的私有协议开发案例也过于理想化,为什么这么说呢?如果说服务端或客户端有一方基于历史原因是用其他语言实现的呢,比如C,Java和C的int类型字节长度是不一样的
那LineBasedFrameDecoder就用不上了,让我们看一个实际的私有协议案例:

这个协议在C/++程序员看来是个再正常不过的了,尤其注意协议对长度字段是采用字符串方式描述的(最多支持9999),如果用Netty来实现,又该如何处理呢?
public class NettyMessage {
    private Header header;
    private Object body;
    //检验和
    private byte crcCode;
    public byte getCrcCode() {
        return crcCode;
    }
    public void setCrcCode(byte crcCode) {
        this.crcCode = crcCode;
    }
    public Header getHeader() {
        return header;
    }
    public void setHeader(Header header) {
        this.header = header;
    }
    public Object getBody() {
        return body;
    }
    public void setBody(Object body) {
        this.body = body;
    }
    public String toString(){
        return ToStringBuilder.reflectionToString(this);
    }
}
public class Header {
    //固定头
    private byte startTag;
    //命令码,4位
    private byte[] cmdCode;
    //版本 2位
    private byte[] version;
    private int length;
    public byte[] getVersion() {
        return version;
    }
    public void setVersion(byte[] version) {
        this.version = version;
    }
    public byte[] getCmdCode() {
        return cmdCode;
    }
    public void setCmdCode(byte[] cmdCode) {
        this.cmdCode = cmdCode;
    }
    public byte getStartTag() {
        return startTag;
    }
    public void setStartTag(byte startTag) {
        this.startTag = startTag;
    }
    public int getLength() {
        return length;
    }
    public void setLength(int length) {
        this.length = length;
    }
    public String toString(){
        return ToStringBuilder.reflectionToString(this);
    }
}
public class MessageEncoder extends MessageToByteEncoder<NettyMessage>{
	@Override
	protected void encode(ChannelHandlerContext ctx, NettyMessage msg, ByteBuf out) throws Exception {
		try{
			if(msg == null || msg.getHeader() == null){
				throw new Exception("The encode message is null");
			}
			out.writeByte(msg.getHeader().getStartTag());
			out.writeBytes(msg.getHeader().getCmdCode());
			//占位
			byte[] lengthBytes = new byte[]{0, 0, 0, 0};
			out.writeBytes(lengthBytes);
			out.writeBytes(msg.getHeader().getVersion());
			String body = (String)msg.getBody();
			int length = 0;
			if(body != null){
				byte[] bodyBytes = body.getBytes();
				out.writeBytes(bodyBytes);
				length = bodyBytes.length;
				if(Constants.CRCCODE_DEFAULT != msg.getCrcCode()){
					msg.setCrcCode(CRC8.calcCrc8(bodyBytes));
				}
			}
			//长度从int转换为byte[4]
			byte l1 = getIndexToByte(length, 3);
			byte l2 = getIndexToByte(length, 2);
			byte l3 = getIndexToByte(length, 1);
			byte l4 = getIndexToByte(length, 0);
			lengthBytes = new byte[]{l1, l2, l3, l4};
			out.setBytes(5, lengthBytes);
			out.writeByte(msg.getCrcCode());
		}catch(Exception e){
			e.printStackTrace();
			throw e;
		}
	}
	public static byte getIndexToByte(int i, int index){
		if(index == 0){
			return (byte)(i % 10);
		}else{
			int num = (int)Math.pow(10, index);
			return (byte)((i / num) % 10);
		}
	}
}
public class MessageDecoder extends ByteToMessageDecoder {
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        try{
            if(in.readableBytes() < 12){
                return;
            }
            in.markReaderIndex();
            NettyMessage message = new NettyMessage();
            Header header = new Header();
            header.setStartTag(in.readByte());
            byte[] cmdCode = new byte[4];
            in.readBytes(cmdCode);
            header.setCmdCode(cmdCode);
            //长度从byte[4]转int
            byte[] lengthBytes = new byte[4];
            in.readBytes(lengthBytes);
            int length = toInt(lengthBytes);
            header.setLength(length);
            if(length < 0 || length > 10240){//过长消息或不合法消息
                throw new IllegalArgumentException("wrong message length");
            }
            byte[] version = new byte[2];
            in.readBytes(version);
            header.setVersion(version);
            if(header.getLength() > 0){
                if(in.readableBytes() < length + 1){
                    in.resetReaderIndex();
                    return;
                }
                byte[] bodyBytes = new byte[header.getLength()];
                in.readBytes(bodyBytes);
                message.setBody(new String(bodyBytes));
            }
            message.setCrcCode(in.readByte());
            message.setHeader(header);
            out.add(message);
        }catch(Exception e){
            e.printStackTrace();
            throw e;
        }
    }
    public static int toInt(byte[] bytes){
        int value = 0;
        for(int i=0; i<bytes.length; i++){
            int num = (int)Math.pow(10, bytes.length - 1 - i);
            value += num * bytes[i];
        }
        return value;
    }
}
服务端代码:
public class NettyServer implements Runnable{
    private static final Logger logger = LoggerFactory.getLogger(NettyServer.class);
    @Autowired
    Config config;
    public void bind(int port) throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 1024)
                .childHandler(new ChildChannelHandler());
            ChannelFuture f = b.bind(port).sync();
            logger.info("Push server started on port " + port);
            f.channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
    public static class ChildChannelHandler extends ChannelInitializer<SocketChannel> {
        @Override
        protected void initChannel(SocketChannel ch) throws Exception {
            ch.pipeline()
            .addLast(new MessageDecoder())
            .addLast(new MessageEncoder())
        }
    }
    @Override
    public void run() {
        try {
            this.bind(config.getServerPort());
        } catch (Exception e) {
            logger.error(e.getMessage());
            System.exit(1);
        }
    }
}
客户端代码:
/**
* 客户端
* @author peng
*/
public class NettyClient { public void connect(String remoteServer, int port) throws Exception {
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(workerGroup)
.channel(NioSocketChannel.class)
.handler(new ChildChannelHandler());
ChannelFuture f = b.connect(remoteServer,port).sync();
f.channel().closeFuture().sync();
} finally {
workerGroup.shutdownGracefully();
}
} public static class ChildChannelHandler extends
ChannelInitializer<SocketChannel> { @Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new MessageDecoder())
.addLast(new MessageEncoder())
}
} public static void main(String[] args){
try {
new NettyClient().connect("127.0.0.1", 9080);
} catch (Exception e) {
e.printStackTrace();
}
}
}
总结:关键在于Encoder和Decoder的编码实现
真正实现Netty私有协议开发的更多相关文章
- netty——私有协议栈开发案例
		
netty--私有协议栈开发案例 摘要: 在学习李林峰老师的Netty权威指南中,觉得第十二章<私有协议栈开发>中的案例代码比较有代表性,讲的也不错,但是代码中个人认为有些简单的错误,个人 ...
 - netty websocket协议开发
		
websocket的好处我们就不用多说了,就是用于解决长连接.服务推送等需要的一种技术. 以下我们来看一个例子: package com.ming.netty.http.websocket; impo ...
 - WebSocket协议开发
		
一直以来,网络在很大程度上都是围绕着HTTP的请求/响应模式而构建的.客户端加载一个网页,然后直到用户点击下一页之前,什么都不会发生.在2005年左右,Ajax开始让网络变得更加动态了.但所有的HTT ...
 - netty(4)高级篇-Websocket协议开发
		
一.HTTP协议的弊端 将HTTP协议的主要弊端总结如下: (1) 半双工协议:可以在客户端和服务端2个方向上传输,但是不能同时传输.同一时刻,只能在一个方向上传输. (2) HTTP消息冗长:相比于 ...
 - netty高级篇(3)-HTTP协议开发
		
一.HTTP协议简介 应用层协议http,发展至今已经是http2.0了,拥有以下特点: (1) CS模式的协议 (2) 简单 - 只需要服务URL,携带必要的请求参数或者消息体 (3) 灵活 - 任 ...
 - Netty实现简单私有协议
		
本文参考<Netty权威指南> 私有协议实现的功能: 1.基于Netty的NIO通信框架,提供高性能异步通信能力 2.提供消息的编码解码框架,实现POJO的序列化和反序列化 3.提供基于I ...
 - netty 私有协议栈
		
通信协议从广义上区分,可以分为公有协议和私有协议.由于私有协议的灵活性,它往往会在某个公司或者组织内部使用,按需定制,也因为如此,升级起来会非常方便,灵活性好.绝大多数的私有协议传输层都基于TCP/I ...
 - 通过私有协议Chrome浏览器页面打开本地程序
		
近期方有这样的要求:这两个系统,根据一组Chrome开展,根据一组IE开展,需要Chrome添加一个链接,然后进入IE该系统的开发.这,需要Chrome跳转到创建一个链接IE浏览器指定的页面.同时也实 ...
 - EasyDarwin支持GB28181协议开发
		
本文转自:http://blog.csdn.net/gavin1010/article/details/77926853 EasyGB28181服务器开发 背景 当前的安防行业,除了私有协议,普遍使用 ...
 
随机推荐
- HTML <dl> 标签
			
<html><body><h2>一个定义列表:</h2><dl> <dt>计算机</dt> <dd&g ...
 - 700多个PHP版本随时切换,PHPWAMP共生模式与多档位综合教程。
			
最近有学生向我咨询如何同时建立多个不同PHP版本站点,并自定义任意版本,软件是否可以多开,PHPWAMP如何设置才能与其他的环境同时使用等问题,本文将一一解决. 简单介绍一下PHPWAMP 你们应该会 ...
 - BTE 增强
			
BTE的设计思路还是比较简单,和BADI有点类似.在标准程序中留有OPEN_FI的出口(以函数OPEN_FI_PERFORM_event id_type的形式存在),然后提供一个可配置的TABLE,可 ...
 - webpack学习笔记—webpack安装、基本配置
			
文章结构: 什么是webpack? 安装webpack 'webpack基本配置 一.什么是webpack? 在学习react时发现大部分文章都是react和webpack结合使用的,所以在学reac ...
 - 排序 之 快排、归并、插入 - <时间复杂度>----掌握思想和过程
			
俗话说:天下武功无坚不破,唯快不破.对于算法当然也是要使用时间最短.占用空间最小的算法来实现了. 注意:我代码里面打的备注仅供参考,建议不要背模板(因为没有固定的模板),可以写一个数列按着代码跑两圈或 ...
 - Zookeeper单机版安装(CentOS 7环境下)
			
一.环境操作系统和软件版本介绍 1.环境操作系统为CentOS Linux release 7.2.1511 (Core) 可用cat /etc/redhat-release查询 2.软件版本 Zoo ...
 - 【IE6的疯狂之八】链接伪类(:hover)CSS背景图片有闪动BUG
			
IE6下链接伪类(:hover)CSS背景图片有闪动BUG,主要原因ie会再一次请求这张图片,或者说图片没被缓存. 例如: CSS代码 a:hover{background:url(imagepath ...
 - 凭借5G研究优势,诺基亚将携手菲律宾将其应用于VR/AR领域
			
目前,很多人都在抱怨网速不行,影响视频的流畅播放,未来这些问题可以通过5G解决.近日,诺基亚和PLDT的全资子公司Smart首次在菲律宾一个"现场"网络演示上实现了5G速度,该网络 ...
 - haproxy(1)
			
参考文档: http://cbonte.github.io/haproxy-dconv/1.5/configuration.html 一.Haproxy 软件负载均衡一般通过两种方式来实现:基于操作系 ...
 - Struts2 注解零配置方法(convention插件使用)
			
最近接触到一个新的项目,是做一个使用S2SH的电子商务商城的二次开发.之前使用过S2SH,在此之前的项目中,Struts2 使用的是XML配置而这个项目是使用注解.在这个项目中,注解还不需要使用Act ...