首先《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. grunt--自动化任务快速上手

    这篇文章将带领你用Grunt来提速和优化网站开发的流程.首先我们会简短介绍Grunt的功能,然后我们直接上手,介绍如何用Grunt的不同插件来替你完成网站项目开发中的很多繁冗工作. 接着我们会创建一个 ...

  2. make -j 多核并行编译 导致笔记本过热 自动关机保护

    中午在装着CentOS的笔记本上把 Oneinstack 跑起来然后去上班了,本来等着下班回来用的,回来之后发现是关机状态,环境也没有装好. 查看日志,找不到相关信息,甚至还以为是被入侵了.又试了几遍 ...

  3. IOS网络请求中文转码

    -(void)get { NSString *urlStr = @"http://120.25.226.186:32812/login2?username=小码哥&pwd=520it ...

  4. Maven之(五)Maven仓库

    本地仓库 Maven一个很突出的功能就是jar包管理,一旦工程需要依赖哪些jar包,只需要在Maven的pom.xml配置一下,该jar包就会自动引入工程目录.初次听来会觉得很神奇,下面我们来探究一下 ...

  5. mysql中You can't specify target table for update in FROM clause

    使用mysql在删除表中重复记录 delete from user where username in (select user name form(select username from user ...

  6. 给Unity3d添加一个漂亮的标题栏

    我们在做好一个小Unity3d APP,我们一般都会兴致勃勃的导出一个exe,尝试着玩我们的app.感觉还不错,有板有眼的了.然而事与愿违,我们APP里面的内容挺漂亮的,但是它的标题栏是windows ...

  7. 设计模式 -- 代理模式 (Proxy Pattern)

    定义: 为其他对象提供一种代理以控制对这个对象的访问: 角色: 1,抽象主题类,(接口或者抽象类),抽象真实主题和代理的共有方法(如下Subject类): 2,具体实现的主题类,继承或者实现抽象主题类 ...

  8. hdu1028

    #include<stdio.h>#include<string.h>const int MAXN=130;int dp[MAXN][MAXN];//dp[i][j]表示 i ...

  9. 关于FlagsAttribute

    最近在看C#本质论,有介绍FlagsAttribute的特性,看了下源码,发现只是一个简单的特性class和一个构造函数. 调试了一下.NET的源码,发现在console.writeline(***) ...

  10. web端和手机端测试有什么不同

    面试中经常被问到web端测试和手机端测试有什么相同点和区别呢?现在总结一下这个问题,如有不对敬请指正 web端和手机端测试有什么区别 1.相同点 不管是web测试还是手机App测试,都离不开测试的相关 ...