首先《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私有协议开发的更多相关文章

  1. netty——私有协议栈开发案例

    netty--私有协议栈开发案例 摘要: 在学习李林峰老师的Netty权威指南中,觉得第十二章<私有协议栈开发>中的案例代码比较有代表性,讲的也不错,但是代码中个人认为有些简单的错误,个人 ...

  2. netty websocket协议开发

    websocket的好处我们就不用多说了,就是用于解决长连接.服务推送等需要的一种技术. 以下我们来看一个例子: package com.ming.netty.http.websocket; impo ...

  3. WebSocket协议开发

    一直以来,网络在很大程度上都是围绕着HTTP的请求/响应模式而构建的.客户端加载一个网页,然后直到用户点击下一页之前,什么都不会发生.在2005年左右,Ajax开始让网络变得更加动态了.但所有的HTT ...

  4. netty(4)高级篇-Websocket协议开发

    一.HTTP协议的弊端 将HTTP协议的主要弊端总结如下: (1) 半双工协议:可以在客户端和服务端2个方向上传输,但是不能同时传输.同一时刻,只能在一个方向上传输. (2) HTTP消息冗长:相比于 ...

  5. netty高级篇(3)-HTTP协议开发

    一.HTTP协议简介 应用层协议http,发展至今已经是http2.0了,拥有以下特点: (1) CS模式的协议 (2) 简单 - 只需要服务URL,携带必要的请求参数或者消息体 (3) 灵活 - 任 ...

  6. Netty实现简单私有协议

    本文参考<Netty权威指南> 私有协议实现的功能: 1.基于Netty的NIO通信框架,提供高性能异步通信能力 2.提供消息的编码解码框架,实现POJO的序列化和反序列化 3.提供基于I ...

  7. netty 私有协议栈

    通信协议从广义上区分,可以分为公有协议和私有协议.由于私有协议的灵活性,它往往会在某个公司或者组织内部使用,按需定制,也因为如此,升级起来会非常方便,灵活性好.绝大多数的私有协议传输层都基于TCP/I ...

  8. 通过私有协议Chrome浏览器页面打开本地程序

    近期方有这样的要求:这两个系统,根据一组Chrome开展,根据一组IE开展,需要Chrome添加一个链接,然后进入IE该系统的开发.这,需要Chrome跳转到创建一个链接IE浏览器指定的页面.同时也实 ...

  9. EasyDarwin支持GB28181协议开发

    本文转自:http://blog.csdn.net/gavin1010/article/details/77926853 EasyGB28181服务器开发 背景 当前的安防行业,除了私有协议,普遍使用 ...

随机推荐

  1. 选择Blobs (Evision)

    C++ // Sort by decreasing area Blobs.SortObjectsUsingFeature(OBJ_AREA, OBJ_SORT_DESCENDING); // Enum ...

  2. The Linux Mint 18.1:Eclipse Run The C++ And Python ConfigorationWhen You achieve above step,you can run the c++ and python! (Next OTL ,PYOTL is Project That Write By Ruimin Shen(ability man) )

    # Copyright (c) 2016, 付刘伟 (Liuwei Fu)# All rights reserved.# 转载请注明出处 1.Install The Eclipse,g++ Use T ...

  3. [HMLY]11.iOS函数式编程的实现&&响应式编程概念

    简介 本篇主要回顾一下--iOS函数式编程 && 响应式编程概念 ,如何一步步实现函数式编程的过程,对阅读Masonry && SnapKit源码有一定的帮助. 作为一 ...

  4. C# 连接 Access 数据库

    c#连接Access 数据库需要System.Data, System.Data.OleDb using System.Data using System.Data.OleDb public OleD ...

  5. H5 App页面 绝对定位 软键盘弹出时顶起底部按钮

    做H5 App页面时,有时候,按钮可能会放到页面的最底下,这个时候可能会用到绝对定位(position: absolute),但是,当input 输入框被点击时,弹出的软键盘会顶起底部的按钮,就像这样 ...

  6. jQuery DOM 元素方法 - index() 方法

    元素的 index,相对于选择器 获得元素相对于选择器的 index 位置. 该元素可以通过 DOM 元素或 jQuery 选择器来指定. 语法 $(selector).index(element) ...

  7. 用python3实现linux的sed功能

    sed是一个很好的文件处理工具,本身是一个管道命令,主要是以行为单位进行处理,可以将数据行进行替换.删除.新增.选取等特定工作.现在用python简单实现sed的主要命令,将old_text替换为ne ...

  8. 简单工厂设计模式(Simple Factory Design Pattern)

    [引言]最近在Youtub上面看到一个讲解.net设计模式的视频,其中作者的一个理解让我印象很深刻:所谓的设计模式其实就是运用面向对象编程的思想来解决平时代码中的紧耦合,低扩展的问题.另外一点比较有见 ...

  9. iOS开发系列-九宫格算法-xib

    给大家演示 应用程序下载 小项目,效果图:涉及知识点:懒加载,九宫格算法,字典转模型,自定义UIView ,xib文件的使用 首先把素材拖到Xcode项目中:简单看一下素材文件 此时大家应该首先关注. ...

  10. Func,Action 的介绍

    Func,Action 的介绍 Func是一种委托,这是在3.5里面新增的,2.0里面我们使用委托是用Delegate,Func位于System.Core命名空间下,使用委托可以提升效率,例如在反射中 ...