public abstract class ByteToMessageDecoder extends ChannelInboundHandlerAdapter {
...
//Called once data should be decoded from the given ByteBuf.
//This method will call #decode(ChannelHandlerContext, ByteBuf, List) as long as decoding should take place.
//@param ctx,the ChannelHandlerContext which this ByteToMessageDecoder belongs to
//@param in,the ByteBuf from which to read data
//@param out,the List to which decoded messages should be added
protected void callDecode(ChannelHandlerContext ctx, ByteBuf in, List
//A decoder that splits the received ByteBufs by the fixed number of bytes.
//For example, if you received the following four fragmented packets:
//+---+----+------+----+
//| A | BC | DEFG | HI |
//+---+----+------+----+
//A FixedLengthFrameDecoder (3) will decode them into the following three packets with the fixed length:
//+-----+-----+-----+
//| ABC | DEF | GHI |
//+-----+-----+-----+
public class FixedLengthFrameDecoder extends ByteToMessageDecoder {
private final int frameLength;
//Creates a new instance.
public FixedLengthFrameDecoder(int frameLength) {
if (frameLength <= 0) {
throw new IllegalArgumentException("frameLength must be a positive integer: " + frameLength);
}
this.frameLength = frameLength;
}
@Override
protected final void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception {
Object decoded = decode(ctx, in);
if (decoded != null) {
out.add(decoded);
}
}
//Create a frame out of the ByteBuf and return it.
//@param ctx,the ChannelHandlerContext which this ByteToMessageDecoder belongs to
//@param in,the ByteBuf from which to read data
//@return frame,the ByteBuf which represent the frame or null if no frame could be created.
protected Object decode(@SuppressWarnings("UnusedParameters") ChannelHandlerContext ctx, ByteBuf in) throws Exception {
if (in.readableBytes() < frameLength) {
return null;
} else {
return in.readRetainedSlice(frameLength);
}
}
}
//A decoder that splits the received {@link ByteBuf}s on line endings.
//Both "\n" and "\r\n" are handled.
//For a more general delimiter-based decoder, see DelimiterBasedFrameDecoder.
public class LineBasedFrameDecoder extends ByteToMessageDecoder {
//Maximum length of a frame we're willing to decode.
private final int maxLength;
//Whether or not to throw an exception as soon as we exceed maxLength.
private final boolean failFast;
private final boolean stripDelimiter;
//True if we're discarding input because we're already over maxLength.
private boolean discarding;
private int discardedBytes;
public LineBasedFrameDecoder(final int maxLength) {
this(maxLength, true, false);
}
public LineBasedFrameDecoder(final int maxLength, final boolean stripDelimiter, final boolean failFast) {
this.maxLength = maxLength;
this.failFast = failFast;
this.stripDelimiter = stripDelimiter;
}
@Override
protected final void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception {
Object decoded = decode(ctx, in);
if (decoded != null) {
out.add(decoded);
}
}
//Create a frame out of the ByteBuf and return it.
//@param ctx,the ChannelHandlerContext which this ByteToMessageDecoder belongs to
//@param buffer,the ByteBuf from which to read data
//@return frame,the ByteBuf which represent the frame or null if no frame could be created.
protected Object decode(ChannelHandlerContext ctx, ByteBuf buffer) throws Exception {
final int eol = findEndOfLine(buffer);
if (!discarding) {//非丢弃模式
if (eol >= 0) {//找到行分隔符
//新建一个帧,也就是ByteBuf frame
final ByteBuf frame;
//计算需要解码的数据包的长度
final int length = eol - buffer.readerIndex();
//计算分隔符的长度
final int delimLength = buffer.getByte(eol) == '\r'? 2 : 1;
//判断需要拆包的长度是否大于该拆包器允许的最大长度
if (length > maxLength) {
//如果大于,则丢弃这段数据,返回null
buffer.readerIndex(eol + delimLength);
fail(ctx, length);
return null;
}
//将一个完整的数据包取出
if (stripDelimiter) {
frame = buffer.readRetainedSlice(length);
buffer.skipBytes(delimLength);
} else {
//如果stripDelimiter在构造方法中被设置为false,则数据包含分隔符
frame = buffer.readRetainedSlice(length + delimLength);
}
return frame;
} else {//未找到行分隔符
//首先取得当前字节容器的可读字节数
final int length = buffer.readableBytes();
//然后判断是否超出允许的最大长度
if (length > maxLength) {
//如果已超过最大长度,则进入丢弃模式,设置discarding为true
discardedBytes = length;
buffer.readerIndex(buffer.writerIndex());
discarding = true;
if (failFast) {
fail(ctx, "over " + discardedBytes);
}
}
//如果没超过最大长度,则直接返回null,字节容器的数据没有改变
return null;
}
} else {//丢弃模式
if (eol >= 0) {//找到行分隔符
final int length = discardedBytes + eol - buffer.readerIndex();
//计算出分隔符的长度
final int delimLength = buffer.getByte(eol) == '\r'? 2 : 1;
//把分隔符之前的数据全部丢弃,移动字节容器的readerIndex指针
buffer.readerIndex(eol + delimLength);
discardedBytes = 0;
//经过这么一次丢弃后,后面就有可能是正常的数据包
//于是设置discarding为false,这样下次解码数据包时就会进入正常的解码流程
discarding = false;
if (!failFast) {
fail(ctx, length);
}
} else {//未找到行分隔符
//当前还处于丢弃模式,没有找到行分隔符意味着当前一个完整的数据包还没丢弃完
//所以当前数据继续丢弃,移动字节容器的readerIndex指针
discardedBytes += buffer.readableBytes();
buffer.readerIndex(buffer.writerIndex());
}
return null;
}
}
private void fail(final ChannelHandlerContext ctx, int length) {
fail(ctx, String.valueOf(length));
}
private void fail(final ChannelHandlerContext ctx, String length) {
ctx.fireExceptionCaught(new TooLongFrameException("frame length (" + length + ") exceeds the allowed maximum (" + maxLength + ')'));
}
//Returns the index in the buffer of the end of line found.
//Returns -1 if no end of line was found in the buffer.
private static int findEndOfLine(final ByteBuf buffer) {
int i = buffer.forEachByte(ByteProcessor.FIND_LF);
if (i > 0 && buffer.getByte(i - 1) == '\r') {
i--;
}
return i;
}
}
//A decoder that splits the received ByteBufs by one or more delimiters.
public class DelimiterBasedFrameDecoder extends ByteToMessageDecoder {
private final ByteBuf[] delimiters;
private final int maxFrameLength;
private final boolean stripDelimiter;
private final boolean failFast;
private boolean discardingTooLongFrame;
private int tooLongFrameLength;
private final LineBasedFrameDecoder lineBasedDecoder;
...
//Creates a new instance.
//@param maxFrameLength,the maximum length of the decoded frame.
//A TooLongFrameException is thrown if the length of the frame exceeds this value.
//@param stripDelimiter,whether the decoded frame should strip out the delimiter or not
//@param failFast,If true, a TooLongFrameException is thrown as soon as the decoder
//notices the length of the frame will exceed maxFrameLength regardless of
//whether the entire frame has been read.
//If false, a TooLongFrameException is thrown after the entire frame that exceeds maxFrameLength has been read.
//@param delimiters the delimiters
public DelimiterBasedFrameDecoder(int maxFrameLength, boolean stripDelimiter, boolean failFast, ByteBuf... delimiters) {
validateMaxFrameLength(maxFrameLength);
if (delimiters == null) {
throw new NullPointerException("delimiters");
}
if (delimiters.length == 0) {
throw new IllegalArgumentException("empty delimiters");
}
if (isLineBased(delimiters) && !isSubclass()) {
lineBasedDecoder = new LineBasedFrameDecoder(maxFrameLength, stripDelimiter, failFast);
this.delimiters = null;
} else {
this.delimiters = new ByteBuf[delimiters.length];
for (int i = 0; i < delimiters.length; i ++) {
ByteBuf d = delimiters[i];
validateDelimiter(d);
this.delimiters[i] = d.slice(d.readerIndex(), d.readableBytes());
}
lineBasedDecoder = null;
}
this.maxFrameLength = maxFrameLength;
this.stripDelimiter = stripDelimiter;
this.failFast = failFast;
}
//Returns true if the delimiters are "\n" and "\r\n".
private static boolean isLineBased(final ByteBuf[] delimiters) {
if (delimiters.length != 2) {
return false;
}
ByteBuf a = delimiters[0];
ByteBuf b = delimiters[1];
if (a.capacity() < b.capacity()) {
a = delimiters[1];
b = delimiters[0];
}
return a.capacity() == 2 && b.capacity() == 1
&& a.getByte(0) == '\r' && a.getByte(1) == '\n'
&& b.getByte(0) == '\n';
}
//Return true if the current instance is a subclass of DelimiterBasedFrameDecoder
private boolean isSubclass() {
return getClass() != DelimiterBasedFrameDecoder.class;
}
@Override
protected final void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception {
Object decoded = decode(ctx, in);
if (decoded != null) {
out.add(decoded);
}
}
//Create a frame out of the {@link ByteBuf} and return it.
//@param ctx,the ChannelHandlerContext which this ByteToMessageDecoder belongs to
//@param buffer,the ByteBuf from which to read data
//@return frame,the ByteBuf which represent the frame or null if no frame could be created.
protected Object decode(ChannelHandlerContext ctx, ByteBuf buffer) throws Exception {
if (lineBasedDecoder != null) {
return lineBasedDecoder.decode(ctx, buffer);
}
//Try all delimiters and choose the delimiter which yields the shortest frame.
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;
}
}
if (minDelim != null) {
int minDelimLength = minDelim.capacity();
ByteBuf frame;
if (discardingTooLongFrame) {
//We've just finished discarding a very large frame.
//Go back to the initial state.
discardingTooLongFrame = false;
buffer.skipBytes(minFrameLength + minDelimLength);
int tooLongFrameLength = this.tooLongFrameLength;
this.tooLongFrameLength = 0;
if (!failFast) {
fail(tooLongFrameLength);
}
return null;
}
if (minFrameLength > maxFrameLength) {
//Discard read frame.
buffer.skipBytes(minFrameLength + minDelimLength);
fail(minFrameLength);
return null;
}
if (stripDelimiter) {
frame = buffer.readRetainedSlice(minFrameLength);
buffer.skipBytes(minDelimLength);
} else {
frame = buffer.readRetainedSlice(minFrameLength + minDelimLength);
}
return frame;
} else {
if (!discardingTooLongFrame) {
if (buffer.readableBytes() > maxFrameLength) {
//Discard the content of the buffer until a delimiter is found.
tooLongFrameLength = buffer.readableBytes();
buffer.skipBytes(buffer.readableBytes());
discardingTooLongFrame = true;
if (failFast) {
fail(tooLongFrameLength);
}
}
} else {
//Still discarding the buffer since a delimiter is not found.
tooLongFrameLength += buffer.readableBytes();
buffer.skipBytes(buffer.readableBytes());
}
return null;
}
}
private void fail(long frameLength) {
if (frameLength > 0) {
throw new TooLongFrameException("frame length exceeds " + maxFrameLength + ": " + frameLength + " - discarded");
} else {
throw new TooLongFrameException("frame length exceeds " + maxFrameLength + " - discarding");
}
}
//Returns the number of bytes between the readerIndex of the haystack and the first needle found in the haystack.
//-1 is returned if no needle is found in the haystack.
private static int indexOf(ByteBuf haystack, ByteBuf needle) {
for (int i = haystack.readerIndex(); i < haystack.writerIndex(); i ++) {
int haystackIndex = i;
int needleIndex;
for (needleIndex = 0; needleIndex < needle.capacity(); needleIndex ++) {
if (haystack.getByte(haystackIndex) != needle.getByte(needleIndex)) {
break;
} else {
haystackIndex ++;
if (haystackIndex == haystack.writerIndex() && needleIndex != needle.capacity() - 1) {
return -1;
}
}
}
if (needleIndex == needle.capacity()) {
//Found the needle from the haystack!
return i - haystack.readerIndex();
}
}
return -1;
}
private static void validateDelimiter(ByteBuf delimiter) {
if (delimiter == null) {
throw new NullPointerException("delimiter");
}
if (!delimiter.isReadable()) {
throw new IllegalArgumentException("empty delimiter");
}
}
private static void validateMaxFrameLength(int maxFrameLength) {
if (maxFrameLength <= 0) {
throw new IllegalArgumentException("maxFrameLength must be a positive integer: " + maxFrameLength);
}
}
...
}
(4)基于长度域解码器
主要的逻辑步骤如下:
一.丢弃模式的处理
二.获取待拆数据包的大小
三.对数据包进行长度校验
四.跳过指定字节长度
五.抽取数据包
public class LengthFieldBasedFrameDecoder extends ByteToMessageDecoder {
private final ByteOrder byteOrder;//表示字节流表示的数据是大端还是小端,用于长度域的读取
private final int maxFrameLength;//表示数据包的最大长度
private final int lengthFieldOffset;//表示长度域的偏移量
private final int lengthFieldLength;//表示长度域的长度
private final int lengthFieldEndOffset;//表示紧跟长度域字段后面的第一字节在整个数据包中的偏移量
private final int lengthAdjustment;//表示数据包体长度调整大小,长度域只表示数据包体的长度
private final int initialBytesToStrip;//表示拿到完整的数据包之后,向业务解码器传递之前,应该跳过多少字节
private final boolean failFast;//默认为true,否则可能会OOM
private boolean discardingTooLongFrame;
private long tooLongFrameLength;
private long bytesToDiscard;
...
//Creates a new instance.
//@param byteOrder,the ByteOrder of the length field
//@param maxFrameLength,the maximum length of the frame.
//If the length of the frame is greater than this value, 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 true, a TooLongFrameException is thrown as soon as the decoder notices the length of the frame
//will exceed maxFrameLength regardless of whether the entire frame has been read.
//If false, a TooLongFrameException is thrown after the entire frame that exceeds maxFrameLength has been read.
public LengthFieldBasedFrameDecoder(ByteOrder byteOrder, int maxFrameLength, int lengthFieldOffset, int lengthFieldLength, int lengthAdjustment, int initialBytesToStrip, boolean failFast) {
...
this.byteOrder = byteOrder;
this.maxFrameLength = maxFrameLength;
this.lengthFieldOffset = lengthFieldOffset;
this.lengthFieldLength = lengthFieldLength;
this.lengthAdjustment = lengthAdjustment;
lengthFieldEndOffset = lengthFieldOffset + lengthFieldLength;
this.initialBytesToStrip = initialBytesToStrip;
this.failFast = failFast;
}
@Override
protected final void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception {
Object decoded = decode(ctx, in);
if (decoded != null) {
out.add(decoded);
}
}
//Create a frame out of the {@link ByteBuf} and return it.
//@param ctx,the ChannelHandlerContext which this ByteToMessageDecoder belongs to
//@param in,the ByteBuf from which to read data
//@return frame,the ByteBuf which represent the frame or null if no frame could be created.
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 = getUnadjustedFrameLength(in, actualLengthFieldOffset, lengthFieldLength, byteOrder);
//如果拿到的长度为负数,则直接跳过长度域并抛出异常
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) {
//当前可读字节已达到frameLength,直接跳过frameLength字节
//丢弃之后,后面又可能就是一个合法的数据包了
in.skipBytes((int) frameLength);
} else {
//当前可读字节未达到frameLength,说明后面未读到的字节也需要丢弃,进入丢弃模式,先把当前累积的字节全部丢弃
discardingTooLongFrame = true;
//bytesToDiscard表示还需要丢弃多少字节
bytesToDiscard = discard;
in.skipBytes(in.readableBytes());
}
//调用failIfNecessary判断是否需要抛出异常
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);
//步骤四结束
//步骤五开始:抽取数据包
//拿到当前累积数据的读指针
int readerIndex = in.readerIndex();
//拿到待抽取数据包的实际长度进行抽取
int actualFrameLength = frameLengthInt - initialBytesToStrip;
//进行抽取数据
ByteBuf frame = extractFrame(ctx, in, readerIndex, actualFrameLength);
//移动读指针
in.readerIndex(readerIndex + actualFrameLength);
return frame;
}
protected ByteBuf extractFrame(ChannelHandlerContext ctx, ByteBuf buffer, int index, int length) {
return buffer.retainedSlice(index, length);
}
//拿到实际的未调整过的数据包长度
//如果长度域代表的值表达的含义不是正常的int、short等类型,则可以重写这个方法
//比如有的长度域虽然是4字节,比如0x1234,但是它的含义是十进制的,即长度就是十进制的1234
protected long getUnadjustedFrameLength(ByteBuf buf, int offset, int length, ByteOrder order) {
buf = buf.order(order);
long frameLength;
switch (length) {
case 1:
frameLength = buf.getUnsignedByte(offset);
break;
case 2:
frameLength = buf.getUnsignedShort(offset);
break;
case 3:
frameLength = buf.getUnsignedMedium(offset);
break;
case 4:
frameLength = buf.getUnsignedInt(offset);
break;
case 8:
frameLength = buf.getLong(offset);
break;
default:
throw new DecoderException("unsupported lengthFieldLength: " + lengthFieldLength + " (expected: 1, 2, 3, 4, or 8)");
}
return frameLength;
}
private void failIfNecessary(boolean firstDetectionOfTooLongFrame) {
//不需要再丢弃后面的未读字节,就开始重置丢弃状态
if (bytesToDiscard == 0) {
//Reset to the initial state and tell the handlers that the frame was too large.
long tooLongFrameLength = this.tooLongFrameLength;
this.tooLongFrameLength = 0;
discardingTooLongFrame = false;
//如果没有设置快速失败,或者设置了快速失败并且是第一次检测到大包错误,则抛出异常,让Handler处理
if (!failFast || failFast && firstDetectionOfTooLongFrame) {
fail(tooLongFrameLength);
}
} else {
//如果设置了快速失败,并且是第一次检测到打包错误,则抛出异常,让Handler处理
if (failFast && firstDetectionOfTooLongFrame) {
fail(tooLongFrameLength);
}
}
}
protected ByteBuf extractFrame(ChannelHandlerContext ctx, ByteBuf buffer, int index, int length) {
return buffer.retainedSlice(index, length);
}
private void fail(long frameLength) {
if (frameLength > 0) {
throw new TooLongFrameException("Adjusted frame length exceeds " + maxFrameLength + ": " + frameLength + " - discarded");
} else {
throw new TooLongFrameException("Adjusted frame length exceeds " + maxFrameLength + " - discarding");
}
}
...
}
XMLHttpRequest cannot load http://v.xxx.com. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:63342' is therefore not allowed access. test.html:1
1.什么是NoSQL数据库?NoSQL和RDBMS有什么区别?在哪些情况下使用和不使用NoSQL数据库?
NoSQL是非关系型数据库,NoSQL = Not Only SQL。
关系型数据库采用的结构化的数据,NoSQL采用的是键值对的方式存储数据。
在处理非结构化/半结构化的大数据时;在水平方向上进行扩展时;随时应对动态增加的数据项时可以优先考虑使用NoSQL数据库。
在考虑数据库的成熟
ClientWatchManager接口
//接口的唯一方法materialize用于确定那些Watcher需要被通知
//确定Watcher需要三方面的因素1.事件状态 2.事件类型 3.znode的path
public interface ClientWatchManager {
/**
* Return a set of watchers that should
解决mysql导入导出数据乱码问题方法:
1、进入mysql,通过如下命令查看数据库编码方式:
mysql> show variables like 'character_set_%';
+--------------------------+----------------------------------------+
| Variable_name&nbs
Your love is also your weak point.
你的所爱同时也是你的弱点。
If anything in this life is certain, if history has taught us anything, it is
that you can kill anyone.
不顾家的人永远不可能成为一个真正的男人。 &
用phpMyAdmin导入mysql数据库时,我的10M的
数据库不能导入,提示mysql数据库最大只能导入2M。
phpMyAdmin数据库导入出错: You probably tried to upload too large file. Please refer to documentation for ways to workaround this limit.
1、create database school 创建数据库school
2、drop database school 删除数据库school
3、use school 连接到school数据库,使其成为当前数据库
4、create table class(classID int primary key identity not null)
创建一个名为class的表,其有一