Это 17-й день моего участия в августовском испытании обновлений. Узнайте подробности события:Испытание августовского обновления
Введение
В прошлой статье мы говорили о том, как настроить энкодер и декодер в netty, но реализация кастомизации достаточно сложна.В общем, если нет особой необходимости, все надеются, что чем проще, тем лучше, сложность в том, чтобы найти сегментация в ByteBuf Point, разделите ByteBuf на блоки, которые можно обрабатывать один за другим. Сегодня в этой статье рассказывается о механизме обработки сегментации, который поставляется с netty.
Frame detection
В предыдущей главе мы упомянули, что необходимо средство для различения разных данных в ByteBuf, то есть для нахождения точки разделения разных данных в ByteBuf. Если ByteBuf сначала разделить на независимые ByteBuf, будет намного проще обрабатывать независимые ByteBuf.
Netty предоставляет 4 кодировщика точек разделения, которые мы можем назвать обнаружением кадров: DelimiterBasedFrameDecoder, FixedLengthFrameDecoder, LengthFieldBasedFrameDecoder и LineBasedFrameDecoder.
Все эти классы являются подклассами ByteToMessageDecoder, и мы будем представлять их один за другим.
DelimiterBasedFrameDecoder
Первый — DelimiterBasedFrameDecoder, по названию видно, что это декодер, который делит bytebuf по разделителю. Что такое разделитель?
В netty есть класс Delimiters, который определяет разделительные символы.В основном есть два разделителя, nulDelimiter и lineDelimiter:
public static ByteBuf[] nulDelimiter() {
return new ByteBuf[] {
Unpooled.wrappedBuffer(new byte[] { 0 }) };
}
public static ByteBuf[] lineDelimiter() {
return new ByteBuf[] {
Unpooled.wrappedBuffer(new byte[] { '\r', '\n' }),
Unpooled.wrappedBuffer(new byte[] { '\n' }),
};
}
nullDelimiter используется для обработки 0x00, в основном используется для обработки сокета Flash XML или других подобных протоколов.
lineDelimiter используется для обработки возврата каретки и перевода строки, в основном при обработке текстовых файлов.
Для DelimiterBasedFrameDecoder, если есть несколько разделителей, он выберет тот, который разбивает ByteBuf наименьший.Например, если мы используем DelimiterBasedFrameDecoder(Delimiters.lineDelimiter()), поскольку на самом деле в lineDelimiter есть два метода разделения, нажмите Enter + перевод строки или перевод строки, если выполняются следующие условия:
+--------------+
| ABC\nDEF\r\n |
+--------------+
DelimiterBasedFrameDecoder выберет кратчайший результат сегментации, то есть указанный выше контент будет разделен на:
+-----+-----+
| ABC | DEF |
+-----+-----+
вместо
+----------+
| ABC\nDEF |
+----------+
FixedLengthFrameDecoder
Этот класс делит ByteBuf на фиксированные длины, такие как следующие 4 байта полученной информации:
+---+----+------+----+
| A | BC | DEFG | HI |
+---+----+------+----+
Если используется FixedLengthFrameDecoder(3), указанный выше ByteBuf будет разделен на следующие части:
+-----+-----+-----+
| ABC | DEF | GHI |
+-----+-----+-----+
LengthFieldBasedFrameDecoder
Этот класс является более гибким и может извлекать последующий массив байтов в соответствии с полем длины в данных. LengthFieldBasedFrameDecoder очень гибкий, он имеет 4 свойства для управления ими: lengthFieldOffset, lengthFieldLength, lengthAdjustment и initialBytesToStrip.
lengthFieldOffset — начальная позиция поля длины, lengthFieldLength — длина самого поля длины, lengthAdjustment — настройка длины целевых данных, а initialBytesToStrip — количество байтов, которые необходимо удалить в процессе расшифровки. Не могу понять? Неважно, давайте возьмем несколько примеров.
Сначала рассмотрим самый простой:
lengthFieldOffset = 0
lengthFieldLength = 2
lengthAdjustment = 0
initialBytesToStrip = 0
BEFORE DECODE (14 bytes) AFTER DECODE (14 bytes)
+--------+----------------+ +--------+----------------+
| Length | Actual Content |----->| Length | Actual Content |
| 0x000C | "HELLO, WORLD" | | 0x000C | "HELLO, WORLD" |
+--------+----------------+ +--------+----------------+
Приведенные выше настройки указывают, что длина начинается с бита 0 и составляет 2 байта. Где Ox00C=12, что также является длиной «HELLO, WORLD».
Если вам не нужно поле «Длина», вы можете удалить длину, установив initialBytesToStrip:
lengthFieldOffset = 0
lengthFieldLength = 2
lengthAdjustment = 0
initialBytesToStrip = 2 (= length 字段的长度)
BEFORE DECODE (14 bytes) AFTER DECODE (12 bytes)
+--------+----------------+ +----------------+
| Length | Actual Content |----->| Actual Content |
| 0x000C | "HELLO, WORLD" | | "HELLO, WORLD" |
+--------+----------------+ +----------------+
lengthAdjustment заключается в корректировке значения поля Length, так как в некоторых случаях поле Length может содержать длину всех данных, то есть Length+content, поэтому его нужно корректировать при парсинге, например, в следующем примере , фактическая длина на самом деле 0x0C, но входящее значение равно 0x0E, поэтому длину поля Length необходимо вычесть на 2, то есть lengthAdjustment устанавливается равным -2.
lengthFieldOffset = 0
lengthFieldLength = 2
lengthAdjustment = -2 (= Length字段的长度)
initialBytesToStrip = 0
BEFORE DECODE (14 bytes) AFTER DECODE (14 bytes)
+--------+----------------+ +--------+----------------+
| Length | Actual Content |----->| Length | Actual Content |
| 0x000E | "HELLO, WORLD" | | 0x000E | "HELLO, WORLD" |
+--------+----------------+ +--------+----------------+
LineBasedFrameDecoder
LineBasedFrameDecoder специально обрабатывает окончания строк в текстовых файлах. То есть "\n" и "\r\n", он очень похож на DelimiterBasedFrameDecoder, но DelimiterBasedFrameDecoder более общий.
Суммировать
С помощью указанных выше четырех устройств обнаружения кадров вы можете сначала добавить эти обнаружения кадров в конвейер, а затем добавить собственный обработчик, чтобы вам не нужно было учитывать длину чтения ByteBuf в пользовательском обработчике.
Например, в StringDecoder, если использовался LineBasedFrameDecoder, то в методе декодирования можно предположить, что входящий ByteBuf представляет собой строку строк, тогда его можно использовать прямо так:
protected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception {
out.add(msg.toString(charset));
}
Разве это не просто?
Эта статья была включена вwoohoo.floydpress.com/15-Нетти-нет…
Самая популярная интерпретация, самая глубокая галантерея, самые краткие уроки и множество трюков, о которых вы не знаете, ждут вас!
Добро пожаловать, чтобы обратить внимание на мой официальный аккаунт: «Программируйте эти вещи», разбирайтесь в технологиях, лучше поймите себя!