1.LineBasedFrameDecoder
1.先找到结束符索引
private static int findEndOfLine(final ByteBuf buffer) {
final int n = buffer.writerIndex();
for (int i = buffer.readerIndex(); i < n; i ++) {
final byte b = buffer.getByte(i);
if (b == '\n') {
return i;
} else if (b == '\r' && i < n - 1 && buffer.getByte(i + 1) == '\n') {
return i; // \r\n
}
}
return -1; // Not found.
}
2.然后读取数据bytes 转换成对象返回,容错处理暂时不分析 核心代码 if (eol >= 0) {
final ByteBuf frame;
final int length = eol - buffer.readerIndex();
final int delimLength = buffer.getByte(eol) == '\r'? 2 : 1; if (length > maxLength) {
buffer.readerIndex(eol + delimLength);
fail(ctx, length);
return null;
} if (stripDelimiter) {//是否连结束符返回 true 不返回
frame = buffer.readBytes(length);
buffer.skipBytes(delimLength);//跳过结束符数据
} else {
frame = buffer.readBytes(length + delimLength);
} return frame;
}
2.StringDecoder 分析 比较简单,ByteBuf 转换 string
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception {
out.add(msg.toString(charset));
}
3.DelimiterBasedFrameDecoder 自定义结束符解码分析,原理基本跟 LineBasedFrameDecoder 相同
1.找到结束符 ByteBuf 对象,可支持多个
int minFrameLength = Integer.MAX_VALUE;
ByteBuf minDelim = null;
for (ByteBuf delim: delimiters) {
int frameLength = indexOf(buffer, delim);
if (frameLength >= 0 && frameLength < minFrameLength) {
minFrameLength = frameLength;
minDelim = delim;
}
}
2.然后读取数据bytes 转换成对象返回,容错处理暂时不分析 核心代码
if (stripDelimiter) {//是否连结束符返回 true 不返回
frame = buffer.readBytes(minFrameLength);
buffer.skipBytes(minDelimLength);//跳过结束符数据
} else {
frame = buffer.readBytes(minFrameLength + minDelimLength);
} return frame;
4.FixedLengthFrameDecoder 比较简单
protected Object decode(@SuppressWarnings("UnusedParameters") ChannelHandlerContext ctx, ByteBuf in) throws Exception {
if (in.readableBytes() < frameLength) {
return null;
} else {
return in.readBytes(frameLength);
}
}
5.LengthFieldBasedFrameDecoder 在 FixedLengthFrameDecoder 基础上指定偏移读取长度,动态帧长度
1.先看构造方法 /**
* Creates a new instance.
*
* @param byteOrder
* the {@link ByteOrder} of the length field
* @param maxFrameLength
* the maximum length of the frame. If the length of the frame is
* greater than this value, {@link TooLongFrameException} will be
* thrown.
* @param lengthFieldOffset
* the offset of the length field
* @param lengthFieldLength
* the length of the length field
* @param lengthAdjustment
* the compensation value to add to the value of the length field
* @param initialBytesToStrip
* the number of first bytes to strip out from the decoded frame
* @param failFast
* If <tt>true</tt>, a {@link TooLongFrameException} is thrown as
* soon as the decoder notices the length of the frame will exceed
* <tt>maxFrameLength</tt> regardless of whether the entire frame
* has been read. If <tt>false</tt>, a {@link TooLongFrameException}
* is thrown after the entire frame that exceeds <tt>maxFrameLength</tt>
* has been read.
*/
public LengthFieldBasedFrameDecoder(
ByteOrder byteOrder, //传输方式,默认ByteOrder.BIG_ENDIAN
int maxFrameLength, //帧最大长度
int lengthFieldOffset,//数据长度偏移,忽略包头信息
int lengthFieldLength,//数据长度大小
int lengthAdjustment, //附加数据长度 默认0
int initialBytesToStrip,
boolean failFast //true 超过 maxFrameLength 长度会抛异常,看处理写得不清晰
) { this.byteOrder = byteOrder;
this.maxFrameLength = maxFrameLength;
this.lengthFieldOffset = lengthFieldOffset;
this.lengthFieldLength = lengthFieldLength;
this.lengthAdjustment = lengthAdjustment;
lengthFieldEndOffset = lengthFieldOffset + lengthFieldLength;
this.initialBytesToStrip = initialBytesToStrip;
this.failFast = failFast;
}
2.核心分析
protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
if (discardingTooLongFrame) { //是否丢弃处理
long bytesToDiscard = this.bytesToDiscard;
int localBytesToDiscard = (int) Math.min(bytesToDiscard, in.readableBytes());
in.skipBytes(localBytesToDiscard);//跳过丢弃数据
bytesToDiscard -= localBytesToDiscard;
this.bytesToDiscard = bytesToDiscard;//记录索引 failIfNecessary(false);
}
//少于头信息忽略
if (in.readableBytes() < lengthFieldEndOffset) {
return null;
}
//计算实际数据读取索引
int actualLengthFieldOffset = in.readerIndex() + lengthFieldOffset;
//获取数据长度
long frameLength = getFrameLength(in, actualLengthFieldOffset); if (frameLength < 0) {
in.skipBytes(lengthFieldEndOffset);
throw new CorruptedFrameException(
"negative pre-adjustment length field: " + frameLength);
}
// 帧总长度 = 数据长度+附加数据长度+ 偏移总长度
frameLength += lengthAdjustment + lengthFieldEndOffset; if (frameLength < lengthFieldEndOffset) {
in.skipBytes(lengthFieldEndOffset);
throw new CorruptedFrameException(
"Adjusted frame length (" + frameLength + ") is less " +
"than lengthFieldEndOffset: " + lengthFieldEndOffset);
} if (frameLength > maxFrameLength) {
long discard = frameLength - in.readableBytes();
tooLongFrameLength = frameLength; if (discard < 0) {
// buffer contains more bytes then the frameLength so we can discard all now
in.skipBytes((int) frameLength);
} else {
// Enter the discard mode and discard everything received so far.
discardingTooLongFrame = true;
bytesToDiscard = discard;
in.skipBytes(in.readableBytes());
}
failIfNecessary(true);
return null;
} // never overflows because it's less than maxFrameLength
int frameLengthInt = (int) frameLength;
if (in.readableBytes() < frameLengthInt) {
return null;
} if (initialBytesToStrip > frameLengthInt) {
in.skipBytes(frameLengthInt);
throw new CorruptedFrameException(
"Adjusted frame length (" + frameLength + ") is less " +
"than initialBytesToStrip: " + initialBytesToStrip);
}
in.skipBytes(initialBytesToStrip); // extract frame
int readerIndex = in.readerIndex();//当前读索引
int actualFrameLength = frameLengthInt - initialBytesToStrip;//不清楚为什么-initialBytesToStrip
ByteBuf frame = extractFrame(ctx, in, readerIndex, actualFrameLength); //拷贝数据
in.readerIndex(readerIndex + actualFrameLength);//修改读索引
return frame;
} private long getFrameLength(ByteBuf in, int actualLengthFieldOffset) {
in = in.order(byteOrder);
long frameLength;
switch (lengthFieldLength) {
case 1:
frameLength = in.getUnsignedByte(actualLengthFieldOffset);
break;
case 2:
frameLength = in.getUnsignedShort(actualLengthFieldOffset);
break;
case 3:
frameLength = in.getUnsignedMedium(actualLengthFieldOffset);
break;
case 4:
frameLength = in.getUnsignedInt(actualLengthFieldOffset);
break;
case 8:
frameLength = in.getLong(actualLengthFieldOffset);
break;
default:
throw new Error("should not reach here");
}
return frameLength;
}

netty 编/解码处理的更多相关文章

  1. Netty 编解码技术 数据通信和心跳监控案例

    Netty 编解码技术 数据通信和心跳监控案例 多台服务器之间在进行跨进程服务调用时,需要使用特定的编解码技术,对需要进行网络传输的对象做编码和解码操作,以便完成远程调用.Netty提供了完善,易扩展 ...

  2. 【转】Netty系列之Netty编解码框架分析

    http://www.infoq.com/cn/articles/netty-codec-framework-analyse/ 1. 背景 1.1. 编解码技术 通常我们也习惯将编码(Encode)称 ...

  3. Netty系列之Netty编解码框架分析

    1. 背景 1.1. 编解码技术 通常我们也习惯将编码(Encode)称为序列化(serialization),它将对象序列化为字节数组,用于网络传输.数据持久化或者其它用途. 反之,解码(Decod ...

  4. 什么是Netty编解码,Netty编解码器有哪些?Protostuff怎么使用?

    哈喽!大家好,我是小奇,一位热爱分享的程序员 小奇打算以轻松幽默的对话方式来分享一些技术,如果你觉得通过小奇的文章学到了东西,那就给小奇一个赞吧 文章持续更新 一.前言 书接上回,昨天下雨没怎么上街上 ...

  5. Netty编解码技术

    编解码技术,说白了就是java序列化技术,序列化目的就两个,第一进行网络传输,第二对象持久化. 虽然我们可以使用java进行对象序列化,netty去传输,但是java序列化的硬伤比较多,比如java序 ...

  6. Netty编解码技术和UDP实现

    背景 作为网络传输框架,免不了传输对象,对象在传输之前就要序列化,这个序列化的过程就是编码过程.接收到编码后的数据就需要解码,还原传输的数据. 编解码技术就是java序列化技术,序列化的目的有两个,一 ...

  7. Netty学习(九)-Netty编解码技术之Marshalling

    前面我们讲过protobuf的使用,主流的编解码框架其实还有很多种: ①JBoss的Marshalling包 ②google的Protobuf ③基于Protobuf的Kyro ④Apache的Thr ...

  8. Netty学习(七)-Netty编解码技术以及ProtoBuf和Thrift的介绍

    在前几节我们学习过处理粘包和拆包的问题,用到了Netty提供的几个解码器对不同情况的问题进行处理.功能很是强大.我们有没有去想这么强大的功能是如何实现的呢?背后又用到了什么技术?这一节我们就来处理这个 ...

  9. Netty 编解码奥秘

    Netty中编解码 Netty 的解码器有很多种,比如基于长度的,基于分割符的,私有协议的.但是,总体的思路都是一致的. 拆包思路:当数据满足了 解码条件时,将其拆开.放到数组.然后发送到业务 han ...

  10. netty: 编解码之jboss marshalling, 用marshalling进行对象传输

    jboss marshalling是jboss内部的一个序列化框架,速度也十分快,这里netty也提供了支持,使用十分方便. TCP在网络通讯的时候,通常在解决TCP粘包.拆包问题的时候,一般会用以下 ...

随机推荐

  1. AngularJS快速入门指南08:表格

    ng-repeat指令非常适合用来显示表格. 在表格中显示数据 在AngularJS中显示表格非常容易: <div ng-app="myApp" ng-controller= ...

  2. MySQL的几种连接 join/inner join/cross join/逗号/left join/right join/natural join

    转载请注明出处!! 之前数据表连接操作多使用逗号或者join,对几种连接的概念一直浑浑噩噩,最近研究了一波,把这些连接的区别搞明白了.   连接:A xjoin B(主表 操作 关联表)  selec ...

  3. How Tomcat works — 五、tomcat启动(4)

    前面摆了三节的姿势,现在终于要看到最终tomcat监听端口,接收请求了. 目录 Connector Http11Protocol JIoEndpoint 总结 在前面的初始化都完成之后,进行Conne ...

  4. Linux 下Shell 脚本几种基本命令替换区别

    Shell 脚本几种基本命令替换区别 前言:因为工作需要,需要编写 shell script .编写大量 shell script 时,累计了大量经验,也让自己开始迷糊几种函数输出调用的区别.后面和 ...

  5. Android 使WebView支持HTML5 Video(全屏)播放的方法

    http://blog.csdn.net/zrzlj/article/details/8050633  1)需要在AndroidManifest.xml文件中声明需要使用HardwareAcceler ...

  6. 【转】C++11 标准新特性: 右值引用与转移语义

    VS2013出来了,对于C++来说,最大的改变莫过于对于C++11新特性的支持,在网上搜了一下C++11的介绍,发现这篇文章非常不错,分享给大家同时自己作为存档. 原文地址:http://www.ib ...

  7. 解决adb shell input text 中文输入,unicode转utf-8

    https://github.com/senzhk/ADBKeyBoard 上面这个是外国人写的一个输入法,我们把它安装再设置下就ok了 直接下载bin下的ADBKeyBoard.apk文件,或者上面 ...

  8. Nodejs npm安装socket.io报错解决办法

    安装socket.io时,报错,提示需要安装Microsoft visual studio 2005 或 Net framework 2.0 sdk,没有找到vcbuild.exe,解决办法是安装 . ...

  9. JAVA利用enum结合testng做数据驱动示例

    数据驱动是做自动化测试中很重要的一部分,数据源的方案也是百花八门了,比如利用外部文件,直接在@DataProvider中写死等等,我们今天介绍一下利用enum来做数据源,先来看一下enum的写法: p ...

  10. jackson json转实体 允许特殊字符和转义字符 单引号

    //允许出现特殊字符和转义符 mapper.configure(Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true) ; //允许出现单引号 mapper.confi ...