Серия Netty: предварительное исследование Netty|Вызов августовского обновления

Java Netty

Введение

Мы часто используем браузеры для доступа к веб-страницам для получения соответствующей информации. Вообще говоря, мы используем протоколы HTTP или HTTPS. Эти протоколы по сути являются вводом-выводом. Запрос клиента является входом, а ответ сервера - исходящим. Но в текущей структуре протокола не все наши потребности могут быть полностью удовлетворены. Например, использование HTTP для загрузки больших файлов может потребовать длительного ожидания подключения и т. д. Мы также знаем, что существуют различные методы ввода-вывода, включая синхронный ввод-вывод, асинхронный ввод-вывод, блокирующий ввод-вывод и неблокирующий ввод-вывод. Различные методы ввода-вывода имеют разную производительность, а netty — это инфраструктура NIO, основанная на асинхронном управлении событиями.

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

Введение в нетти

Netty — отличный фреймворк NIO.Первое представление о IO у всех должно быть более сложным, особенно при работе с различными протоколами HTTP, TCP и UDP, его очень сложно использовать. Но netty обеспечивает удобную инкапсуляцию этих протоколов, и программирование ввода-вывода может быть выполнено быстро и лаконично с помощью netty. Netty легко разработать, она хорошо работает и сочетает в себе стабильность и гибкость. Если вы хотите разрабатывать высокопроизводительные сервисы, всегда правильно использовать netty.

Последняя версия netty 4.1.66.Final.Фактически, это самая стабильная официально рекомендуемая версия.У Netty также есть версия 5.x, но официально она не рекомендуется.

Если вы хотите использовать его в своем проекте, вы можете ввести следующий код:

        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>4.1.66.Final</version>
        </dependency>

Ниже мы испытаем прелесть netty на самом простом примере.

первый сервер нетти

Что такое сервер? Программу, которая может предоставлять услуги внешнему миру, можно назвать сервером. Создание сервера — это первый шаг во всех внешних службах.Как использовать netty для создания сервера? Сервер в основном отвечает за обработку запросов от различных серверов.Netty предоставляет класс ChannelInboundHandlerAdapter для обработки таких запросов.Нам нужно только наследовать этот класс.

В NIO каждый канал является каналом связи между клиентом и сервером. ChannelInboundHandlerAdapter определяет некоторые события и ситуации, которые могут возникнуть в этом канале, как показано на следующем рисунке:

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

Здесь мы создаем новый класс FirstServerHandler и переписываем два метода channelRead и exceptionCaught, Первый метод предназначен для чтения сообщений из канала, а второй метод — для обработки исключений.

public class FirstServerHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        // 对消息进行处理
        ByteBuf in = (ByteBuf) msg;
        try {
            log.info("收到消息:{}",in.toString(io.netty.util.CharsetUtil.US_ASCII));
        }finally {
            ReferenceCountUtil.release(msg);
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        // 异常处理
        log.error("出现异常",cause);
        ctx.close();
    }
}

В приведенном выше примере после получения сообщения мы вызываем метод release(), чтобы освободить его, не обрабатывая его. Вызов метода выпуска является обычной практикой после завершения использования сообщения. Приведенный выше код преобразует msg в ByteBuf. Если вы не хотите его преобразовывать, вы можете использовать его напрямую следующим образом:

        try {
            // 消息处理
        } finally {
            ReferenceCountUtil.release(msg);
        }

В методе обработки исключений мы распечатываем информацию об исключении и закрываем контекст исключения.

С помощью Handler нам нужно создать новый класс Server, чтобы использовать Handler для создания каналов и получения сообщений. Далее, давайте взглянем на поток обработки сообщений netty.

В netty обработка ввода-вывода реализована с использованием многопоточного цикла обработки событий. EventLoopGroup в netty — это абстрактный класс этих циклов событий.

Давайте взглянем на структуру классов EventLoopGroup.

Видно, что EventLoopGroup наследуется от EventExecutorGroup, а EventExecutorGroup наследуется от ScheduledExecutorService, поставляемого с JDK.

Таким образом, EventLoopGroup, по сути, является службой пула потоков.Он называется Group, потому что содержит множество циклов EventLoop, а цикл обработки событий можно пройти, вызвав метод next.

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

EventLoopGroup объединяет несколько циклов событий в группу, и с помощью следующего метода можно пройти циклы событий в группе. Кроме того, EventLoopGroup предоставляет несколько методов регистрации для регистрации канала в текущем EventLoop.

Как видно из рисунка выше, возвращаемый результат register является ChannelFuture.Всем известно, что Future можно использовать для получения результата выполнения асинхронных задач.Тот же ChannelFuture также является носителем асинхронного результата, который может блокировать Future вызовом метод синхронизации, пока не будет получен результат выполнения.

Как видите, метод register также может передаваться в объект ChannelPromise.ChannelPromise является одновременно подклассом ChannelFuture и Promise, а Promise является подклассом Future, который является особым Future, который может управлять состоянием Future.

EventLoopGroup имеет реализации многих подклассов, здесь мы используем NioEventLoopGroup, а Nio использует Selector для выбора каналов. Еще одна особенность заключается в том, что NioEventLoopGroup может добавлять дочерние группы EventLoopGroups.

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

Передав эти две группы в ServerBootstrap, можно запустить службу из ServerBootstrap.Соответствующий код выглядит следующим образом:

//建立两个EventloopGroup用来处理连接和消息
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(new FirstServerHandler());
                        }
                    })
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .childOption(ChannelOption.SO_KEEPALIVE, true);

            // 绑定端口并开始接收连接
            ChannelFuture f = b.bind(port).sync();

Созданный нами в начале FirstServerHandler был добавлен в качестве процессора childHandler при инициализации канала.

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

В приведенном выше примере мы также указали несколько параметров ChannelOptions для установки некоторых свойств канала.

Наконец, мы привязываем соответствующий порт и запускаем сервер.

первый клиент для netty

Выше мы написали сервер и запустили его, а теперь нам нужен клиент для взаимодействия с ним.

Если вы не хотите писать код, вы можете напрямую использовать telnet localhost 8000 для взаимодействия с сервером, но здесь мы хотим использовать API-интерфейс netty для создания клиента для взаимодействия с сервером.

Процесс создания сетевого клиента в основном такой же, как и процесс создания сетевого сервера. Во-первых, вам нужно создать обработчик для обработки определенных сообщений Аналогично, здесь мы также наследуем ChannelInboundHandlerAdapter.

В предыдущем разделе упоминалось, что в ChannelInboundHandlerAdapter есть много методов, которые можно переписать в соответствии с потребностями вашего собственного бизнеса.Здесь мы хотим отправить сообщение на сервер, когда канал активен. Затем вам нужно переписать метод channelActive, а также выполнить некоторую обработку исключения, поэтому вам также необходимо переписать метод exceptionCaught. Если вы хотите обрабатывать, когда канал читает сообщение, вы можете переопределить метод channelRead.

Созданный код FirstClientHandler выглядит следующим образом:

@Slf4j
public class FirstClientHandler extends ChannelInboundHandlerAdapter {

    private ByteBuf content;
    private ChannelHandlerContext ctx;

    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        this.ctx = ctx;
        content = ctx.alloc().directBuffer(256).writeBytes("Hello flydean.com".getBytes(StandardCharsets.UTF_8));
        // 发送消息
        sayHello();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        // 异常处理
        log.error("出现异常",cause);
        ctx.close();
    }
    
    private void sayHello() {
        // 向服务器输出消息
        ctx.writeAndFlush(content.retain());
    }
}

В приведенном выше коде мы сначала запрашиваем ByteBuff из ChannelHandlerContext, а затем вызываем его метод writeBytes для записи данных, которые должны быть переданы. Наконец, вызовите метод writeAndFlush ctx для вывода сообщения на сервер.

Следующим шагом будет запуск клиентской службы, на стороне сервера мы построили две NioEventLoopGroups, которые учитывают выбор канала и чтение сообщений в канале. Для клиента этой проблемы не существует, здесь нужна только одна NioEventLoopGroup.

Серверная сторона использует ServerBootstrap для запуска службы, а клиентская сторона использует Bootstrap, бизнес-логика его запуска в основном такая же, как и у запуска сервера:

        EventLoopGroup group = new NioEventLoopGroup();
        try {
            Bootstrap b = new Bootstrap();
            b.group(group)
             .channel(NioSocketChannel.class)
             .handler(new ChannelInitializer<SocketChannel>() {
                 @Override
                 protected void initChannel(SocketChannel ch) throws Exception {
                     ChannelPipeline p = ch.pipeline();
                     p.addLast(new FirstClientHandler());
                 }
             });

            // 连接服务器
            ChannelFuture f = b.connect(HOST, PORT).sync();

запустить сервер и клиент

С вышеуказанными приготовлениями мы можем бежать. Сначала запустите сервер, затем клиент.

Если проблем нет, он должен вывести следующее:

[nioEventLoopGroup-3-1] INFO com.flydean01.FirstServerHandler - 收到消息:Hello flydean.com

Суммировать

Полный пример сервера, клиента сделан. Подытожим рабочий процесс netty.Для серверной части сначала установите обработчик для фактической обработки сообщений, а затем используйте ServerBootstrap для группировки EventLoop и привязки порта к запуску. Для клиента также необходимо установить обработчик для обработки сообщения, затем вызвать Bootstrap для группировки EventLoop и привязать порт для запуска.

С учетом приведенного выше обсуждения вы можете разработать свой собственный сервис NIO. Разве это не просто? В последующих статьях будет подробно рассмотрена архитектура netty и лежащие в ее основе принципы, так что следите за обновлениями.

Эта статья была включена вwww.flydean.com

Самая популярная интерпретация, самая глубокая галантерея, самые краткие уроки и множество трюков, о которых вы не знаете, ждут вас!

Добро пожаловать, чтобы обратить внимание на мой официальный аккаунт: «Программируйте эти вещи», разбирайтесь в технологиях, лучше поймите себя!