Интерпретация буфера Netty ByteBuf (1)

Netty

Netty В процессе передачи данных конструкция буфера будет использовать конструкцию буфера для повышения эффективности передачи. Хотя Java использовался в программировании NIO, он использовался в процессе использования, и его метод кодирования относительно удобен, и есть определенные недостатки. Таким образом, высокопроизводительный фреймворк Netty получил более мощный и совершенный Bytebuf, а его концепция дизайна также является абсолютной.

Анализ байтового буфера

Прежде чем анализировать ByteBuf, кратко расскажем о работе класса ByteBuffer. Способствует лучшему пониманию ByteBuf.

Операции чтения и записи ByteBuffer совместно используют указатель местоположения, а процесс чтения и записи анализируется с помощью следующих случаев кода:

// 分配一个缓冲区,并指定大小
ByteBuffer buffer = ByteBuffer.allocate(100);
// 设置当前最大缓存区大小限制
buffer.limit(15);
System.out.println(String.format("allocate: pos=%s lim=%s cap=%s", buffer.position(), buffer.limit(), buffer.capacity()));

String content = "ytao公众号";
// 向缓冲区写入数据
buffer.put(content.getBytes());
System.out.println(String.format("put: pos=%s lim=%s cap=%s", buffer.position(), buffer.limit(), buffer.capacity()));

Выводятся три параметра буфера, а именно:

  • позиция чтения и записи позиция указателя
  • Ограничить текущий предельный размер кэша
  • размер буфера емкости

распечатать результат:

Когда мы записываем содержимое, значение указателя чтения и записи равно 13,ytao公众号Английские символы занимают 1 байт, а каждый китайский символ занимает 4 байта, то есть ровно 13, что меньше заданного текущего размера буфера 15.

Далее читаем данные ytao в содержимом:

buffer.flip();
System.out.println(String.format("flip: pos=%s lim=%s cap=%s", buffer.position(), buffer.limit(), buffer.capacity()));

byte[] readBytes = new byte[4];
buffer.get(readBytes);
System.out.println(String.format("get(4): pos=%s lim=%s cap=%s", buffer.position(), buffer.limit(), buffer.capacity()));

String readContent = new String(readBytes);
System.out.println("readContent:"+readContent);

Чтобы прочитать содержимое, вам нужно создать массив байтов для получения и указать размер полученных данных.

После записи данных и последующего чтения содержимого вы должны активно вызыватьByteBuffer#flipилиByteBuffer#clear.

ByteBuffer#flipОн принимает значение позиции указателя после записи данных в качестве текущего размера буфера, а затем сбрасывает позицию указателя на ноль. Буфер для записи данных будет изменен на буфер данных для выборки, то есть первый индекс только что записанных данных будет использоваться как начальный индекс для чтения данных.

ByteBuffer#flipСвязанный исходный код:

ByteBuffer#clearЛимит сбрасывается на значение по умолчанию, тот же размер совпадает с емкостью.

Затем прочитайте остальную часть содержимого:

Для второго чтения используйтеbuffer#remainingчтобы получить размер в байтах, больший или равный остальному содержимому, функция реализована какlimit - position, поэтому текущая область буфера должна находиться в пределах этого диапазона значений.

readBytes = new byte[buffer.remaining()];
buffer.get(readBytes);
System.out.println(String.format("get(remaining): pos=%s lim=%s cap=%s", buffer.position(), buffer.limit(), buffer.capacity()));

распечатать результат:

Во время вышеуказанной операции индекс изменяется, как показано на рисунке:

ByteBuf операции чтения и записи

ByteBuf имеет отдельные указатели чтения и записи, которыеbuf#readerIndexа такжеbuf#writerIndex, текущий размер буфераbuf#capacity.

Здесь буфер разделен на три области по двум указателям и емкости:

  • 0 -> readerIndex — это область буфера чтения, область чтения можно повторно использовать для экономии памяти, значение readerIndex больше или равно 0
  • readerIndex -> WriterIndex — читаемая область буфера, значение writeIndex больше или равно readerIndex
  • WriterIndex -> емкость — это доступная для записи область буфера, а значение емкости больше или равно WriteIndex.

Как показано ниже:

выделить буфер

ByteBuf выделяет буфер, только что заданное начальное значение. По умолчанию 256. Начальное значение не является максимальным значением, как ByteBuffer, максимальное значение ByteBuf равноInteger.MAX_VALUE

ByteBuf buf = Unpooled.buffer(13);
System.out.println(String.format("init: ridx=%s widx=%s cap=%s", buf.readerIndex(), buf.writerIndex(), buf.capacity()));

распечатать результат:

операция записи

Операция записи ByteBuf похожа на операцию ByteBuffer, за исключением того, что указатель записи записывается отдельно.Операция записи ByteBuf поддерживает несколько типов и имеет следующие API:

Напишите тип байтового массива:

String content = "ytao公众号";
buf.writeBytes(content.getBytes());
System.out.println(String.format("write: ridx=%s widx=%s cap=%s", buf.readerIndex(), buf.writerIndex(), buf.capacity()));

распечатать результат:

Индексная диаграмма:

операция чтения

Точно так же операция записи ByteBuf похожа на операцию ByteBuffer, за исключением того, что указатель записи записывается отдельно.Операция чтения ByteBuf поддерживает несколько типов и имеет следующие API:

Считайте четыре байта из текущей позиции readerIndex:

byte[] dst = new byte[4];
buf.readBytes(dst);
System.out.println(new String(dst));
System.out.println(String.format("read(4): ridx=%s widx=%s cap=%s", buf.readerIndex(), buf.writerIndex(), buf.capacity()));

распечатать результат:

Индексная диаграмма:

Динамическое расширение ByteBuf

Используя приведенный выше пример буфера распределения ByteBuffer, добавьте в него содержимое [официальная учетная запись ytao официальная учетная запись] так, чтобы записанное содержимое превышало значение лимита.

ByteBuffer buffer = ByteBuffer.allocate(100);
buffer.limit(15);

String content = "ytao公众号ytao公众号";
buffer.put(content.getBytes());

Результат выполнения ненормальный:

Когда размер байта содержимого превышает предельное значение, переполнение буфера является ненормальным, поэтому мы должны проверять, достаточно ли места в буфере, прежде чем каждый раз записывать данные, что не очень хорошо для кодирования.

Добавьте тот же контент, используя ByteBuf, учитывая тот же начальный размер контейнера.

ByteBuf buf = Unpooled.buffer(15);
String content = "ytao公众号ytao公众号";
buf.writeBytes(content.getBytes());
System.out.println(String.format("write: ridx=%s widx=%s cap=%s", buf.readerIndex(), buf.writerIndex(), buf.capacity()));

Распечатайте результат запуска:

По приведенной выше распечатанной информации видно, что колпачок изменился с набора 15 на 64. Когда размера нашего контейнера будет недостаточно, мы расширим емкость.Далее мы разберем, как это сделать в процессе расширения. . Введите writeBytes внутри:

Проверьте длину написанного контента:

В области записи проверьте:

  • Если записанное содержимое пусто, генерируется исключение недопустимого параметра.
  • Если размер записываемого содержимого меньше или равен размеру доступной для записи области, возвращается текущий буфер, аwritableBytes()Функция - это размер записываемой областиcapacity - writerIndex
  • Если размер записываемого содержимого превышает максимальный размер доступной для записи области, создается исключение индекса за пределами границ.
  • Последнее оставшееся условие состоит в том, что размер записываемого содержимого больше, чем область, доступная для записи, и меньше, чем максимальный размер области, тогда выделяется новая область буфера.

Недостаточно емкости, перераспределите внутреннюю часть буфера с 4M в качестве клапана:

  • Если содержимое для записи имеет размер ровно 4М, то выделяется буфер размером 4М.
  • Если содержимое, которое будет записано, превышает этот вентиль, а сумма значения вентиля и значения вентиля не превышает значение максимальной емкости, выделите буфер из (значение вентиля + значение размера содержимого); если он превышает этот вентиль и сумму значения клапана, а значение клапана больше, чем значение максимальной производительности, выделите буфер максимальной производительности.
  • Если содержимое для записи не превышает пороговое значение и превышает 64, размер выделяемого буфера умножается на 64 до тех пор, пока он не станет равным или больше содержимого для записи.
  • Если содержимое для записи не превышает значение клапана и не превышает 64, размер выделяемого буфера равен 64.

наконец

Среди восьми основных типов буферов, реализованных Netty, в дополнение к типу Boolean, остальные семь имеют свои собственные соответствующие буферы, но на практике мы пытаемся использовать ByteBuf, и он совместим с любым типом. ByteBuf является самым основным и самым важным членом системы Netty.Чтобы лучше понять и использовать Netty, это одно из необходимых условий, чтобы сначала понять и освоить ByteBuf.


личный блог: ytao.top

Обратите внимание на паблик [ytao], больше оригинальных хороших статей

我的公众号

Категории