«Движение в блоге»Оригинальный адрес:короткая книгаИсходное время публикации: 2017-05-05
После изучения Netty в течение определенного периода времени ключевые моменты и опыт обучения резюмируются следующим образом. В этой статье в основном обобщаются знания и базовое использование ChannelHandler и EventLoop. Главы этой статьи отсортированы в соответствии с главами «Netty в Действие".
Следующий контент в основном относится к «сети параллельного программирования»."Нетти в действии" китайская версияИ оригинальная книга «Netty в действии», вспомогательная ссылкаЭфирная Нетти в действиии официальный сайт НеттиNetty 4.1 JavaDoc.
6. ChannelHandler и ChannelPipeline
Нормальный жизненный цикл канала показан на следующем рисунке. При изменении состояния генерируются соответствующие события. Эти события перенаправляются в ChannelHandler в ChannelPipeline для выполнения соответствующих действий.
6.1 ChannelHandler
ChannelHandler имеет два важных субинтерфейса:
- «ChannelInboundHandler», обрабатывающий входные данные и все типы изменений состояния
- «ChannelOutboundHandler» обрабатывает выходные данные и может перехватывать все операции.
6.1.1 ChannelInboundHandler
В следующей таблице перечислены методы интерфейса ChannelInboundHandler. Эти методы вызываются при получении данных или изменении состояния связанного канала.Эти методы тесно связаны с жизненным циклом канала..
метод | описывать |
---|---|
channelRegistered | Вызывается, когда канал зарегистрирован в EventLoop и может обрабатывать ввод-вывод. |
channelUnregistered | Вызывается, когда канал отменяется из его EventLoop и больше не обрабатывает ввод-вывод. |
channelActive | Вызывается, когда канал становится активным; канал подключен/привязан, готов |
channelInactive | Вызывается, когда канал выходит из активного состояния и больше не подключен к удаленному |
channelReadComplete | Вызывается, когда операция чтения на канале завершается |
channelRead | Вызывается при чтении данных из канала |
6.1.2 ChannelOutboundHandler
Исходящие операции и данные обрабатываются ChannelOutBoundHandler. Его методы могут вызываться через Channel, ChannelPipeline и ChannelHandlerContext.Основные методы подинтерфейса ChannelOutboundHandler следующие:
метод | описывать |
---|---|
bind(ChannelHandlerContext,SocketAddress,ChannelPromise) | Запрос на привязку канала к локальному адресу |
connect(ChannelHandlerContext, SocketAddress,SocketAddress,ChannelPromise) | Запрос на подключение канала к удаленному |
disconnect(ChannelHandlerContext, ChannelPromise) | Запрос на отключение канала от удаленного |
close(ChannelHandlerContext,ChannelPromise) | Запрос на закрытие канала |
deregister(ChannelHandlerContext, ChannelPromise) | Запрашивает у канала отмену регистрации в его EventLoop. |
read(ChannelHandlerContext) | Запрос на чтение дополнительных данных из канала |
flush(ChannelHandlerContext) | Запрос на сброс данных очереди на удаленный канал через канал |
write(ChannelHandlerContext,Object, ChannelPromise) | Запрос на запись данных на пульт через Channel |
6.1.3 Класс адаптера ChannelHandler
Два класса адаптера ChannelInboundHandlerAdapter и ChannelOutboundHandlerAdapter обеспечивают базовые реализации ChannelInboundHandler и ChannelOutboundHandler соответственно.Они наследуют методы общего родительского интерфейса ChannelHandler и расширяют абстрактный класс ChannelHandlerAdapter.
-
ChannelHandlerAdapter предоставляет служебный метод isSharable(). Если реализация класса снабжена аннотацией @Sharable, то этот метод вернет значение true, что означает, что объект можно добавить в несколько ChannelPipelines.
-
Методы в ChannelInboundHandlerAdapter и ChannelOutboundHandlerAdapter вызывают эквивалентный метод в связанном ChannelHandlerContext, тем самым перенаправляя событие следующему ChannelHandler в конвейере.
6.1.4 ChannelFuture и ChannelPromise
- ChannelPromise — это подинтерфейс ChannelFuture.
- Принимая во внимание, что ChannelFuture является неизменяемым объектом
- ChannelPromise определяет доступные для записи методы, такие как setSuccess(), setFailure().
6.1.5 Освобождение ресурсов
1. Введите направление «Въезд»Когда класс реализации ChannelInboundHandler переопределяет метод channelRead(), он отвечает за освобождение памяти, связанной с ByteBuf. Вы можете использовать инструменты, предоставляемые Netty:
ReferenceCountUtil.release(「ByteBuf 的对象」)
Проще говоря, вы можете использовать подкласс SimpleChannelInboundHandler , После того как сообщение будет прочитано с помощью ChannelRead0(), ресурсы будут автоматически освобождены, и любые ссылки на сообщение в это время станут недействительными, поэтому эти ссылки нельзя сохранить для последующего использования.
2. Направление выхода "Исходящий"В направлении вывода, при обработке операции записи() и отбрасывании сообщения (без записи в канал), он должен отвечать за освобождение сообщения.
@ChannelHandler.Sharable public
class DiscardOutboundHandler extends ChannelOutboundHandlerAdapter {
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
ReferenceCountUtil.release(msg); //使用 ReferenceCountUtil.release(...) 释放资源
promise.setSuccess(); //通知 ChannelPromise 数据已经被处理
}
Если сообщение «использовано» или отброшено и не отправлено следующему обработчику ChannelOutboundHandler в ChannelPipeline, пользователь несет ответственность за вызов ReferenceCountUtil.release(). Если сообщение достигает реального транспортного уровня, оно будет автоматически выпущено при записи в сокет или при закрытии канала, и пользователю не нужно об этом заботиться.
6.2 Интерфейс ChannelPipeline
-
Каждому вновь созданному каналу будет назначен новый ChannelPipeline. Канал не может заменить или удалить текущий ChannelPipeline. Эта связь фиксируется на протяжении всего срока службы компонента Netty.
-
ChannelPipeline можно рассматривать как серию экземпляров ChannelHandler, которые перехватывают входные и выходные события, проходящие через канал.
-
В зависимости от источника событие может обрабатываться ChannelInboundHandler или ChannelOutboundHandler. Далее, вызывая методы ChannelHandlerContext, событие будет переадресовано следующему обработчику того же типа.
6.2.1 ChannelHandlerContext
-
Через ChannelHandlerContext обработчик может уведомить следующий ChannelHandler в ChannelPipeline и даже динамически изменить ChannelPipeline, к которому принадлежит следующий ChannelHandler.
-
ChannelPipeline в основном состоит из серии обработчиков ChannelHandler. ChannelPipeline предоставляет методы для доставки событий в ChannelPipeline.
-
Некоторые методы ChannelHandlerContext имеют имена, аналогичные именам других классов (Channel и ChannelPipeline), но методы ChannelHandlerContext используют более короткий путь доставки событий. Мы должны использовать это везде, где это возможно, для достижения наилучшей производительности.
-
Если вы вызываете эти методы в экземпляре Channel или ChannelPipeline, их вызовы будут проходить по всему конвейеру. Тот же метод, вызываемый в ChannelHandlerContext, начинается только с текущего ChannelHandler и переходит к следующему ChannelHandler в конвейере, который может обработать событие.
«Ссылка на этот раздел» Глава 6 ChannelHandler и ChannelPipeline
7. EventLoop и EventLoopGroup
7.1 Базовый режим пула потоков Java
- Выберите один из бездействующих потоков в пуле и назначьте отправленную задачу «реализацией Runnable».
- Когда задача завершена, поток возвращается в пул, дождитесь «следующего распределения задач»
7.2 EventLoop «Цикл событий»
- EventLoop всегда управляется одним потоком
- EventLoop может быть назначен для обслуживания нескольких каналов.
- Канал имеет только один EventLoop
Задача (Runnable или Callable) может быть напрямую отправлена в EventLoop для немедленного или отложенного выполнения. В зависимости от конфигурации и доступных ядер ЦП можно создать несколько циклов обработки событий для оптимизации использования ресурсов.
Природа события определяет, как оно будет обработано, оно может передавать данные из сетевого стека в ваше приложение, или наоборот, или делать что-то совсем другое. Но логика обработки событий должна быть универсальной и достаточно гибкой, чтобы обрабатывать все возможные ситуации.
Итак, в Netty 4 все операции ввода-вывода и события обрабатываются потоком, назначенным на EventLoop. Модель потоков, принятая в Netty 4, обрабатывает все, что происходит в EventLoop того же потока.
7.3 EventLoopGroup
- EventLoopGroup отвечает за назначение EventLoop вновь созданному каналу.
- Асинхронная реализация использует только несколько циклов событий, которые являются общими для всех каналов.
- После того, как каналу назначен EventLoop, он будет использовать этот EventLoop на протяжении всего своего жизненного цикла.
EventLoops, которые обслуживают ввод-вывод канала и события, содержатся в EventLoopGroup. Способ создания и назначения EventLoop зависит от реализации транспорта.
Асинхронная реализация использует только несколько циклов событий (и связанных с ними потоков), а в текущей модели Netty эти циклы событий используются всеми каналами. Это позволяет обслуживать множество каналов минимальным количеством потоков вместо того, чтобы назначать один поток на каждый канал.
EventLoopGroup отвечает за назначение EventLoop каждому вновь созданному каналу. В текущей реализации стратегия циклического перебора может удовлетворять сбалансированному распределению, и один и тот же цикл событий также может быть назначен нескольким каналам.
«Ссылка на этот раздел» Глава 7 EventLoop и модель потоков