Netty сегодня используется во всех видах приложений по всему Интернету для обработки тысяч (если не миллионов) чатов, многопользовательских игр, включая Minecraft , Twitter и многие другие приложения. Тем не менее, это не сделало это слишком далеко в голову корпоративных программистов, разрабатывающих бизнес-приложения.
Я считаю, что Netty может представить новую волну функциональности, которой другие решения просто не могут соответствовать из-за своей полностью двунаправленной передачи текста и двоичных данных, не относящихся к HTTP, а также благодаря поддержке гораздо большего числа одновременных клиентов, чем традиционный поток-сокет Серверы.
Вы можете знать о мастерстве Netty с WebSockets, но знаете ли вы, что он может функционировать очень хорошо, как традиционный веб-сервер? Благодаря очень продуманному дизайну Netty может обрабатывать практически любой трафик. Он также может обрабатывать несколько типов одновременно, например, WebSockets и HTTP через один и тот же порт одновременно. Комбинируя их вместе, программисты избавляются от таких неприятностей, как CORS (Cross Origin Resource Sharing), которые могут создать уродливую голову, когда браузер пытается отправлять запросы на серверы, с которых он не загружается.
ОШИБКА СЕРВЕРА io.netty.channel.abstractchannel$annotatedconnectexception connection
Сила Нетти
Чтобы дать представление о его способности трансформировать корпоративные приложения, я собрал пример кода, показывающий один из традиционных примеров Интернета, который извлекает цены на акции.
Другие приложения должны будут делать запросы AJAX, опрашивать, иметь кнопки обновления и т. Д. Для обновления цен. WebSockets устраняет необходимость в этом. После создания постоянно открытого двунаправленного соединения и клиент, и сервер могут общаться друг с другом, когда это необходимо, без каких-либо согласований. Таким образом, клиент сообщает серверу, когда какой-либо пользователь изменяет критерии, и сервер обновляет клиент всякий раз, когда соответствующие данные изменяются на основе этих критериев.
- Вы можете найти полностью функциональный код здесь .
Я настроил небольшой протокол на основе JSON для клиента, чтобы сервер знал, что решил пользователь. Чтобы добавить новый символ в список, за которым сервер следит за клиентом, достаточно простого вызова. Вот пример:
Это добавляет символ в список. Следующее обновление с сервера включает текущую цену акций (из REST API Yahoo Finance) для нового символа в своих данных. Столь же легко удалить предмет:
С помощью этих двух команд клиент контролирует список символов, которые сервер наблюдает за каждым пользователем. На стороне сервера в обработчике Netty, единственное, что программист должен сделать для учета нескольких пользователей, это убедиться, что для каждого нового соединения создается новый обработчик, и что статические члены не используются там, где данные не подлежат совместному использованию. , Если с аннотацией не указано иное, Netty предполагает, что обработчики не являются общими.
Как исправить io.netty.channel.abstractchannel$annotatedconnectexception… | Геймхак №1
Давайте посмотрим, как определяются обработчики для конвейера Netty. Это из класса StockTickerServer:
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new ChannelInitializer()
public void initChannel(SocketChannel ch) throws Exception <
ChannelPipeline p = ch.pipeline();
p.addLast( «encoder» , new HttpResponseEncoder());
p.addLast( «decoder» , new HttpRequestDecoder());
p.addLast( «aggregator» , new HttpObjectAggregator(65536));
p.addLast( «handler» , new StockTickerServerHandler());
Порядок здесь очень важен, так как каждый обработчик в конвейере имеет возможность обрабатывать (или не обрабатывать) данные и передавать их следующему обработчику. Обработчик биржевого тикера находится внизу, так как именно он отправляет данные обратно клиенту и поэтому находится в конце конвейера. Создавая новые экземпляры обработчиков, каждое новое соединение получает свои экземпляры каждого обработчика. Если обработчики не сохраняют состояние и поддерживают поток, то вместо этого можно использовать синглтоны для экономии памяти. Ни один из используемых мной обработчиков не является разделяемым, поэтому я не буду показывать пример этого.
Netty как веб-сервер
Несколько приемов используются для того, чтобы Netty обрабатывал HTTP и трафик WebSocket одновременно.
1. StockTickerServerHandler расширяет SimpleChannelInboundHandler
Это говорит Netty, что мы хотим, чтобы весь трафик приходил на этот обработчик. В противном случае мы могли бы использовать SimpleChannelInboundHandler , если мы хотим обрабатывать только HTTP-трафик, или SimpleChannelInboundHandler , если мы хотим обрабатывать только трафик WebSocket.
2. Метод channelRead0 (чтение канала ноль)
protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception <
if (msg instanceof FullHttpRequest) <
this.handleHttpRequest(ctx, (FullHttpRequest)msg);
> else if (msg instanceof WebSocketFrame) <
this.handleWebSocketFrame(ctx, (WebSocketFrame)msg);
Это позволяет нам обрабатывать трафик HTTP и WebSocket в соответствии с каждым протоколом. handleHttpRequest обслуживает HTML, изображения, CSS, JavaScript и весь другой обычный веб-трафик, а handleWebSocketFrame выясняет, что делать с пользовательскими сообщениями, отправляемыми с клиента.
3. Типы пантомимы
Netty не имеет встроенной поддержки обработки MIME-типов, поскольку вызовы WebSocket по сути не нужны.
Я добавил слегка измененную версию Apache MIME-типов и загрузил ее статически. Я синхронизируюсь по загрузке, потому что Netty может создать довольно много обработчиков при запуске для пула, если хочет, и конструктор может выполняться многими обработчиками одновременно. Поскольку поле является статическим, карта может быть загружена много раз, прежде чем она станет ненулевой. Синхронизация на статической блокировке (НЕ текущий экземпляр класса) предотвращает это.
Другие детали
Метод handleWebSocketFrame заботится о различных «известных» типах фреймов, которые определяет протокол WebSocket . После получения полнотекстового фрейма я передаю его создателю созданного мной интерфейса, чтобы указать, как работать с бизнес-логикой.
Этот код живет в StockTickerMessageHandler. Он создает фоновый поток для извлечения биржевых котировок и отправки их клиенту, а также обрабатывает команды, отправляемые клиентом.
Там есть немного грязного кода для обработки сжатых Gzip данных, отправляемых Yahoo, и анализа JSON, возвращаемого службой, а также некоторый код, который использует классы java.util.concurrent, такие как Executor, AtomicBoolean, AtomicReference и CopyOnWriteArrayList, чтобы сохранить Фоновый поток и обработчик Netty не могут наступать друг на друга, так как они делятся информацией о канале и текущем списке символов.
Я также использую Gson, чтобы превратить входящий JSON в POJO, чтобы их было легче обрабатывать. Кроме этого, это просто бизнес конец этого примера.
Примечание об аутентификации
У меня не было времени добавить аутентификацию в этот пример. Если бы я это сделал, я бы использовал Shiro , сверхмощную инфраструктуру аутентификации / авторизации / шифрования, которая работает как с обычными приложениями, так и с веб-приложениями. Поддержка HTTPS также отсутствует, так как это публичное приложение для проверки цен на акции. Вот пример для добавления HTTPS (и WSS) здесь .
Одна вещь, которая очень трудна (если не невозможна) с JavaScript WebSockets – это отправка данных аутентификации вместе с запросом на обновление (то есть вызов нового WebSocket (uri)). По этой причине обычно сначала отправляют сообщение HTTPS POST, как это делается на обычном веб-сайте, и устанавливают токен cookie cookie. Таким образом, при отправке запроса на обновление, cookie автоматически отправляется вместе с ним. При использовании аутентификации не забывайте использовать HTTPS и WSS вместо HTTP и WS для защиты данных. Как только аутентификация установлена, она становится вопросом проверки для аутентифицированного пользователя, где это необходимо, отмечая, что некоторый трафик должен всегда проходить (HTML, изображения и т. Д.).
Вывод
Netty зарекомендовала себя как высокопроизводительный, изменяющий игру способ создания новых приложений. Современные корпоративные приложения могут быть гораздо более интерактивными, чем сейчас, используя возможности, предлагаемые WebSockets. Я надеюсь, что вам понравилось это маленькое приключение в Netty, и, пожалуйста, простите за ужасный браузерный клиент, у меня просто не было времени, чтобы сделать хорошее клиентское приложение Backbone.js для этого примера.
Ссылка: | Netty: сервер другого типа (Socket) от нашего партнера JCG Джона Бордмана в блоге |
Источник: coderlessons.com
Введение в Нетти
В этой статье мы рассмотрим Netty — платформу для асинхронных событийных сетевых приложений.
Основное назначение Netty — создание высокопроизводительных протокольных серверов на базе NIO (или, возможно, NIO.2) с разделением и слабой связью компонентов сети и бизнес-логики. Он может реализовывать широко известный протокол, такой как HTTP, или ваш собственный конкретный протокол.
2. Основные понятия
Netty — это неблокирующая структура. Это приводит к высокой пропускной способности по сравнению с блокировкой ввода-вывода. Understanding non-blocking IO is crucial to understanding Netty’s core components and their relationships.с
2.1. канал
Channel — это основа Java NIO. Он представляет собой открытое соединение, способное на операции ввода-вывода, такие как чтение и запись.
2.2. Будущее
Каждая операция ввода-вывода наChannel в Netty не является блокирующей.
Это означает, что каждая операция возвращается сразу после вызова. В стандартной библиотеке Java есть интерфейсFuture, но он неудобен для целей Netty — мы можем только запроситьFuture о завершении операции или заблокировать текущий поток до тех пор, пока операция не будет выполнена .
Вот почемуNetty has its own ChannelFuture interface. Мы можем передать обратный вызовChannelFuture, который будет вызываться после завершения операции.
2.3. События и обработчики
Netty использует парадигму приложения, управляемого событиями, поэтому конвейер обработки данных представляет собой цепочку событий, проходящих через обработчики. События и обработчики могут быть связаны с входящим и исходящим потоком данных. Входящие события могут быть следующими:
- Активация и деактивация канала
- Чтение событий операции
- Исключительные события
- Пользовательские события
Исходящие события проще и, как правило, связаны с открытием / закрытием соединения и записью / сбросом данных.
Netty-приложения состоят из пары сетевых и прикладных логических событий и их обработчиков. Базовыми интерфейсами для обработчиков событий канала являютсяChannelHandler и его предкиChannelOutboundHandler иChannelInboundHandler.
Netty предоставляет огромную иерархию реализацийChannelHandler.. Стоит отметить адаптеры, которые являются просто пустыми реализациями, например ChannelInboundHandlerAdapter иChannelOutboundHandlerAdapter. Мы могли бы расширить эти адаптеры, когда нам нужно обработать только подмножество всех событий.
Также существует много реализаций конкретных протоколов, таких как HTTP, например. HttpRequestDecoder, HttpResponseEncoder, HttpObjectAggregator. Было бы хорошо познакомиться с ними в Javadoc Netty.
2.4. Кодеры и декодеры
Поскольку мы работаем с сетевым протоколом, нам необходимо выполнить сериализацию и десериализацию данных. С этой целью Netty вводит специальные расширенияChannelInboundHandler дляdecoders, которые способны декодировать входящие данные. Базовый класс большинства декодеров -ByteToMessageDecoder.
Для кодирования исходящих данных Netty имеет расширенияChannelOutboundHandler, называемыеencoders.MessageToByteEncoder — это основа для большинства реализаций кодировщика. Мы можем преобразовать сообщение из последовательности байтов в объект Java и наоборот, с кодировщиками и декодерами.
3. Пример серверного приложения
Давайте создадим проект, представляющий простой сервер протокола, который получает запрос, выполняет вычисления и отправляет ответ.
3.1. зависимости
Прежде всего, нам нужно предоставить зависимость Netty в нашемpom.xml:
io.netty netty-all 4.1.10.Final
Мы можем найти последнюю версию вon Maven Central.
3.2. Модель данных
Класс данных запроса будет иметь следующую структуру:
public class RequestData < private int intValue; private String stringValue; // standard getters and setters >
Предположим, что сервер получает запрос и возвращаетintValue, умноженное на 2. Ответ будет иметь единственное значение типа int:
public class ResponseData < private int intValue; // standard getters and setters >
3.3. Запросить декодер
Теперь нам нужно создать кодеры и декодеры для наших протокольных сообщений.
Следует отметить, чтоNetty works with socket receive buffer представлен не как очередь, а просто как набор байтов. Это означает, что наш входящий обработчик может быть вызван, когда полное сообщение не получено сервером.
We must make sure that we have received the full message before processing, и есть много способов сделать это.
Прежде всего, мы можем создать временныйByteBuf и добавлять к нему все входящие байты, пока не получим требуемое количество байтов:
Приведенный выше пример выглядит немного странно, но помогает нам понять, как работает Netty. Каждый метод нашего обработчика вызывается, когда происходит соответствующее событие. Таким образом, мы инициализируем буфер при добавлении обработчика, заполняем его данными о получении новых байтов и начинаем обрабатывать его, когда мы получаем достаточно данных.
Мы сознательно не использовалиstringValue — такое декодирование было бы излишне сложным. Вот почему Netty предоставляет полезные классы декодеров, которые являются реализациямиChannelInboundHandler:ByteToMessageDecoder иReplayingDecoder..
Как мы уже отмечали выше, мы можем создать конвейер обработки каналов с помощью Netty. Таким образом, мы можем поставить наш декодер в качестве первого обработчика, а обработчик логики обработки может последовать за ним.
Декодер для RequestData показан ниже:
Идея этого декодера довольно проста. Он использует реализациюByteBuf, которая вызывает исключение, когда в буфере недостаточно данных для операции чтения.
Когда исключение перехватывается, буфер перематывается в начало, и декодер ожидает новую порцию данных. Декодирование останавливается, когда списокout не пуст после выполненияdecode.
3.4. Кодер ответа
Помимо декодированияRequestData нам нужно закодировать сообщение. Эта операция проще, потому что у нас есть полные данные сообщения, когда происходит операция записи.
Мы можем записать данные вChannel в нашем основном обработчике или мы можем разделить логику и создать обработчик, расширяющийMessageToByteEncoder, который будет перехватывать операцию записиResponseData:
3.5. Обработка запросов
Поскольку мы выполняли декодирование и кодирование в отдельных обработчиках, нам нужно изменить нашProcessingHandler:
3.6. Начальная загрузка сервера
Теперь давайте соберем все вместе и запустим наш сервер:
Подробная информация о классах, используемых в приведенном выше примере начальной загрузки сервера, может быть найдена в их Javadoc. Самая интересная часть этой строки:
ch.pipeline().addLast( new RequestDecoder(), new ResponseDataEncoder(), new ProcessingHandler());
Здесь мы определяем входящие и исходящие обработчики, которые будут обрабатывать запросы и выводить в правильном порядке.
4. Клиентское приложение
Клиент должен выполнять обратное кодирование и декодирование, поэтому нам нужныRequestDataEncoder иResponseDataDecoder:
Также нам нужно определитьClientHandler, который будет отправлять запрос и получать ответ от сервера:
Теперь давайте загрузим клиента:
Как мы видим, есть много общих черт с начальной загрузкой сервера.
Теперь мы можем запустить основной метод клиента и взглянуть на вывод консоли. Как и ожидалось, мы получилиResponseData сintValue равным 246.
5. Заключение
В этой статье мы кратко познакомились с Netty. Мы показали его основные компоненты, такие какChannel иChannelHandler. Также мы сделали простой неблокирующий протокол-сервер и клиент для него.
Как всегда доступны все образцы кодаover on GitHub.
Источник: www.codeflow.site
Введение в Netty
Узнайте, как настроить небольшой сервер Netty и клиента на Java.
Введение в Netty
1. Введение
В этой статье мы собираемся взглянуть на Netty – асинхронную систему сетевых приложений, управляемых событиями.
Основной целью Netty является создание высокую производительность протокольных серверов на основе NIO (или, возможно, NIO.2) с разделением и свободным соединением компонентов сетевой и бизнес-логики. Он может реализовать широко известный протокол, такой как HTTP, или ваш собственный конкретный протокол.
2. Основные концепции
Netty — это не блокирующая структура. Это приводит к высокой пропускной способности по сравнению с блокированием IO. Понимание не блокируя IO имеет решающее значение для понимания основных компонентов Netty и их отношений.
2.1. Канал
Канал является основой Java NIO. Он представляет собой открытое соединение, способное выполнять io-операции, такие как чтение и письмо.
2.2. Будущее
Каждая операция IO на канал в Netty не блокируется.
Это означает, что каждая операция возвращается сразу после вызова. Существует Будущие интерфейс в стандартной библиотеке Java, но это не удобно для целей Netty – мы можем спросить только Будущие о завершении операции или о блокировке текущего потока до завершения операции.
Вот почему Netty имеет свои собственные ChannelFuture интерфейс . Мы можем передать обратный звонок ChannelFuture которые будут призваны к завершению операции.
2.3. События и обработчики
Netty использует парадигму приложения, движимую событиями, поэтому конвейер обработки данных — это цепочка событий, проходят через обработчиков. События и обработчики могут быть связаны с потоком входящих и исходящих данных. Входящие события могут быть следующими:
- Активация и деактивация канала
- Читать события операции
- События исключения
- События пользователей
Исходящие события проще и, как правило, связаны с открытием/закрытием данных соединения и написания/промывки.
Приложения Netty состоят из нескольких событий логики сетей и приложений и их обработчиков. Базовые интерфейсы обработчиков событий канала КаналХэндлер и его предки ChannelOutboundHandler и ChannelInboundHandler .
Netty обеспечивает огромную иерархию реализаций КаналХэндлер. Стоит отметить адаптеры, которые являются пустыми реализациями, например, ChannelInboundHandlerАдаптер и ChannelOutboundHandlerАдаптер . Мы могли бы расширить эти адаптеры, когда нам нужно обработать только подмножество всех событий.
Кроме того, существует множество реализаций конкретных протоколов, таких, как HTTP, например, HttpRequestDecoder, HttpResponseEncoder, HttpObjectAggregator. Было бы хорошо, чтобы познакомиться с ними в Javadoc Нетти.
2.4. Кодеры и декодеры
Работая с сетевым протоколом, мы должны выполнять сериализацию данных и дезириализацию. Для этого Netty вводит специальные расширения ChannelInboundHandler для декодеры которые способны декодировать входящие данные. Базовый класс большинства декодеров ByteToMessageDecoder.
Для кодирования исходящих данных Netty имеет расширения ChannelOutboundHandler называется Кодеры. СообщениеToByteEncoder является основой для большинства кодера реализации . Мы можем преобразовать сообщение из последовательности byte в java-объект и наоборот с помощью кодеров и декодеров.
3. Пример серверного приложения
Давайте создадим проект, представляющий простой протокольный сервер, который получает запрос, выполняет расчет и отправляет ответ.
3.1. Зависимости
Прежде всего, мы должны обеспечить зависимость Netty в нашей пом.xml :
io.netty netty-all 4.1.10.Final
Мы можем найти последнюю версию в течение на Мавен Центральной .
3.2. Модель данных
Класс данных запросов будет иметь следующую структуру:
public class RequestData < private int intValue; private String stringValue; // standard getters and setters >
Допустим, сервер получает запрос и возвращает intValue умножается на 2. Ответ будет иметь одно int значение:
public class ResponseData < private int intValue; // standard getters and setters >
3.3. Запрос декодера
Теперь нам нужно создать кодеры и декодеры для наших протокольных сообщений.
Следует отметить, что Netty работает с розеткой получать буферные , которая представлена не как очередь, а просто как куча байтов. Это означает, что наш входящий обработчик может быть вызван, когда полное сообщение не получено сервером.
Мы должны убедиться, что мы получили полное сообщение перед и есть много способов сделать это.
Прежде всего, мы можем создать временную ByteBuf и придаток к нему все входящие байты, пока мы не получим необходимое количество байтов:
Пример, показанный выше, выглядит немного странно, но помогает нам понять, как работает Netty. Каждый метод нашего обработчика вызывается, когда происходит соответствующее событие. Таким образом, мы инициализируем буфер при добавлении обработчика, заполняем его данными о получении новых байтов и начинаем обрабатывать его, когда получаем достаточно данных.
Мы сознательно не использовали stringValue – расшифровка таким образом была бы неоправданно сложной. Именно поэтому Netty предоставляет полезные классы декодеров, которые являются реализациями ChannelInboundHandler : ByteToMessageDecoder и Воспроизведениедекодера.
Как мы уже отмечали выше, мы можем создать канал обработки трубопровода с Netty. Таким образом, мы можем поставить наш декодер в качестве первого обработчика и обработчик логики обработки может прийти после него.
Декодер для RequestData отображается следующим:
Идея этого декодера довольно проста. Он использует реализацию ByteBuf который бросает исключение, когда в буфере недостаточно данных для операции чтения.
Когда исключение поймано, буфер перематывается в начало, и декодер ждет новую порцию данных. Декодирование останавливается, когда из список не пуст после декодировать исполнение.
3.4. Ответ Encoder
Кроме того, расшифровка ЗапросДанные нам нужно закодировать сообщение. Эта операция проще, потому что у нас есть полные данные сообщения, когда происходит операция записи.
Мы можем писать данные Канал в нашем главном обработчике или мы можем отделить логику и создать обработчик, расширяющий СообщениеToByteEncoder который будет ловить писать ОтветДанные операция:
3.5. Обработка запросов
Так как мы провели расшифровку и кодирование в отдельных обработчиках, мы должны изменить наши ОбработкаХэндлер :
3.6. Сервер Bootstrap
Теперь давайте ставим все это вместе и запустить наш сервер:
Подробную информацию о классах, используемых в приведенном выше примере загрузки сервера, можно найти в их Javadoc. Самая интересная часть этой строки:
ch.pipeline().addLast( new RequestDecoder(), new ResponseDataEncoder(), new ProcessingHandler());
Здесь мы определяем входящих и исходящих обработчиков, которые будут обрабатывать запросы и выход в правильном порядке.
4. Клиентская заявка
Клиент должен выполнять обратное кодирование и расшифровку, поэтому мы должны иметь ЗапросDataEncoder и ОтветДанныйдекодер :
Кроме того, мы должны определить КлиентХэндлер который отправит запрос и получит ответ с сервера:
Теперь давайте bootstrap клиента:
Как мы видим, Есть много деталей, общих с сервера загрузки.
Теперь мы можем запустить основной метод клиента и взглянуть на выход консоли. Как и ожидалось, мы ОтветДанные с intValue равно 246.
5. Заключение
В этой статье, у нас было быстрое введение в Netty. Мы показали его основные компоненты, такие как Канал и КаналХэндлер . Кроме того, мы сделали простой не блокирующий протокол сервера и клиента для него.
Как всегда, все образцы кода доступны более на GitHub .
Читайте ещё по теме:
- Введение в весенние данные Кассандра
- Введение в GWT
- HTTP/2 в Netty
- HTTP-сервер с Netty
- Введение в WireMock
- Метки introduction, netty, server
Источник: javascopes.com