首先《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. WebADI应用到Office 2016 64-bit

    升级后的用户环境: Windows 2016 bit Office 2016 64 bit IE 11 64 bit 功能定义 功能:CUX_LINE_IMP_ADI 类型:SSWA servlet ...

  2. 安装windows后grub的恢复

    问题: 原本是:双系统(linux和windows),后来换windows版本覆盖了grub2 解决方法: 进入windows后下载并安装EasyBCD并添加grub2的选项,重启看见了熟悉的启动项, ...

  3. D3.js:动态效果

    D3 提供了 4 个方法用于实现图形的过渡: - transition() 启动过渡效果,其前后是图形变化前后的状态(形状.位置.颜色等等),例如: .attr("fill",&q ...

  4. Pos终端中的主密钥、工作密钥、pin密钥、mac密钥

    下面介绍一下加密机中最主要的几种密钥: 1.加密机主密钥(MK) 加密机主密钥(Master Key - MK)是存入在HSM机内的由三个成分合成的一对最上层密钥.在HSM机器以外的地方不会以明文形式 ...

  5. es5 数组

    一. 数组申明 var a = new Array(5)  会生成一个长度为5 每个元素都是undifined的数组 var a = new Array(1,2,3) 跟 var a = [1,2,3 ...

  6. python简易爬虫实现

    目的:爬取昵称 目标网站:糗事百科 依赖的库文件:request.sys.beautifulSoup4.imp.io Python使用版本:3.4 说明:参考http://cn.python-requ ...

  7. CAD打开缓慢问题解决方法

    打开AutoCAD很卡,大概需要1分钟 打开Internet Explorer,点击工具菜单,打开"Internet选项",去勾选"检查发行商的证书是否吊销", ...

  8. Ajax与CustomErrors的尴尬

    在ASP.NET程序中,为了给用户显示友好的错误信息,通常在web.config中进行如下的设置: <customErrors mode="RemoteOnly" defau ...

  9. cdh 安装记录

    安装文件准备 CDH 下载地址:http://archive.cloudera.com/cdh5/parcels/latest/ 下载操作系统对应的版本: 1.CDH-5.3.0-1.cdh5.3.0 ...

  10. 49、word2vec - tensorflow

    Python 3.5.2 (v3.5.2:4def2a2901a5, Jun 25 2016, 22:18:55) [MSC v.1900 64 bit (AMD64)] on win32Type & ...