Автоматическое переподключение — это функция, используемая для повышения стабильности и надежности сетевых приложений. Когда соединение между клиентом и сервером неожиданно разрывается, клиент может автоматически попытаться повторно подключиться к серверу, чтобы обеспечить нормальную передачу данных.
Автоматическое повторное подключение относится к механизму, при котором клиент может автоматически попытаться восстановить соединение, когда соединение между клиентом и сервером по какой-либо причине разрывается. Эта функция используется для повышения стабильности и надежности сетевых приложений.
В частности, когда клиент обнаруживает, что соединение с сервером прервано, он автоматически инициирует новую попытку подключения, чтобы обеспечить нормальную передачу данных. Это важно для устранения нестабильности сети, временных отключений или перезапусков сервера, уменьшения вмешательства пользователя и улучшения взаимодействия с пользователем вашего приложения.
package com.artisan.reconnect;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
/**
* @author маленький мастер
* @version 1.0
* @mark: show me the code , change the world
*/
public class ArtisanNettyServer {
public static void main(String[] args) throws Exception {
// Создайте две группы потоков BossGroup и WorkerGroup. По умолчанию количество подпотоков, содержащихся в NioEventLoop, в два раза превышает количество ядер процессора.
// BossGroup просто обрабатывает запросы на соединение , реальная бизнес-обработка будет передана рабочей группе.
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup(8);
try {
// Создайте объект запуска на стороне сервера.
ServerBootstrap bootstrap = new ServerBootstrap();
// Используйте цепное программирование для настройки параметров
bootstrap.group(bossGroup, workerGroup) //Настраиваем две группы потоков
// Используйте NioServerSocketChannel в качестве реализации канала сервера.
.channel(NioServerSocketChannel.class)
// Инициализируйте размер очереди сервера. Сервер обрабатывает клиентсоединять запросы последовательно, поэтому одновременно может обрабатываться только один клиентсоединять.
// Когда одновременно приходит несколько клиентов, сервер поместит запрос клиентсоединять, который не может быть обработан, в очередь и будет ждать обработки.
.option(ChannelOption.SO_BACKLOG, 1024)
.childHandler(new ChannelInitializer<SocketChannel>() {//Создаем объект инициализации канала, задаем параметры инициализации, в SocketChannel Выполните перед настройкой
@Override
protected void initChannel(SocketChannel ch) throws Exception {
//Устанавливаем процессор для SocketChannel рабочей группы
//ch.pipeline().addLast(new LifeCycleInBoundHandler());
ch.pipeline().addLast(new ArtisanNettyServerHandler());
}
});
System.out.println("netty server start。。");
// Привяжите порт и синхронизируйте, Создается асинхронный объект ChannelFuture, и о состоянии выполнения асинхронного события можно судить с помощью isDone() и других методов.
// Запустите сервер (и привяжите порт), привязка — это асинхронная операция, а метод синхронизации — ожидание завершения асинхронной операции.
ChannelFuture cf = bootstrap.bind(9000).sync();
// Зарегистрируйте прослушиватель для cf, чтобы слушать события, которые нас интересуют
/*cf.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if (cf.isSuccess()) {
System.out.println("Успешно прослушивается порт 9000");
} else {
System.out.println("Ошибка прослушивания порта 9000");
}
}
});*/
// Подождите, пока порт прослушивания сервера закроется. closeFuture — асинхронная операция.
// Синхронно дождаться завершения процесса закрытия канала с помощью метода синхронизации. Это заблокирует и дождется завершения закрытия канала. Метод wait() объекта вызывается внутренне.
cf.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
EventLoopGroup
:NettyиспользоватьEventLoopGroup
для обработки цикла событий иIOдействовать。Здесь созданы дваEventLoopGroup
,один для обработкисоединятьпросить(bossGroup
),另один для обработки实际избизнес-логика(workerGroup
)。ServerBootstrap
:ЭтоNettyиз Еще один основной компонент,Используется для настройки и инициализации сервера.ChannelFuture
:Это一个异步результат对象,用于表示通道действоватьизрезультат。ChannelInitializer
:Это一个用于初始化新соединятьизпроцессор。ArtisanNettyServerHandler
:Это должно быть обычаемизкласс обработки,Используется для обработки бизнес-логики,Приведено ниже.bind()
иcloseFuture()
:bind()
Метод используется для запуска сервера и привязки порта,closeFuture()
Используется для ожидания закрытия канала сервера。finally
кусок:Здесь убедитесь, что после запуска сервера произойдет сбой или успех,EventLoopGroup
будет закрыто изящно,освободить ресурсы.package com.artisan.reconnect;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil;
/**
* @author маленький мастер
* @version 1.0
* @mark: show me the code , change the world
* @Description: Пользовательский обработчик должен наследовать определенный HandlerAdapter (спецификацию), указанный netty.
*/
public class ArtisanNettyServerHandler extends ChannelInboundHandlerAdapter {
/**
* Прочитайте данные, отправленные клиентом
*
* @param ctx объект контекста, Содержит каналы, трубопроводы
* @param msg Это данные, отправленные клиентом
* @throws Exception
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("Поток чтения сервера " + Thread.currentThread().getName());
//Channel channel = ctx.channel();
//ChannelPipeline pipeline = ctx.pipeline(); //По сути, это двусторонняя ссылка, исходящий входящий
//Воля msg преобразовать в один ByteBuf, аналог NIO из ByteBuffer
ByteBuf buf = (ByteBuf) msg;
System.out.println("Клиент отправил сообщение:" + buf.toString(CharsetUtil.UTF_8));
}
/**
* Метод обработки завершения чтения данных
*
* @param ctx
* @throws Exception
*/
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ByteBuf buf = Unpooled.copiedBuffer("HelloClient".getBytes(CharsetUtil.UTF_8));
ctx.writeAndFlush(buf);
}
/**
* обрабатывать исключения, В общем, надо закрыть канал
*
* @param ctx
* @param cause
* @throws Exception
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
ctx.close();
}
}
определяет обычайизNetty服务器процессорArtisanNettyServerHandler
,он наследует отChannelInboundHandlerAdapter
。这个процессор Включать了几个重要изметод борьбы склиентизпроситьи响应:
channelRead(ChannelHandlerContext ctx, Object msg)
:Когда сервер запускается склиент Когда данные получены,Этот метод будет вызван. В этом методе,Вы можете написать логику, которая обрабатывает отправку данных. В этом примере,Он просто печатает полученныйиз Содержание сообщения。channelReadComplete(ChannelHandlerContext ctx)
:Этот методchannelReadВызывается после завершения выполнения метода。В этом методе,Вы можете отправлять ответы клиенту. В этом примере,它отправлять了一个简单из"HelloClient"сообщение дляклиент。exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
:Этот метод出现异常时被调用。В этом методе,Вы можете написать обработку исключенийизлогика。В этом примере,Он просто закрывает канал.Этот код представляет собой простой пример клиента, использующего платформу Netty, реализующую функцию переподключения. Ниже приводится объяснение этого кода на китайском языке:
package com.artisan.reconnect;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import java.util.concurrent.TimeUnit;
/**
* @author маленький мастер
* @version 1.0
* @mark: show me the code , change the world
* @Description: Достигнуто переподключениеизклиент
*/
public class ArtisanNettyClient {
private String host;
private int port;
private Bootstrap bootstrap;
private EventLoopGroup group;
public static void main(String[] args) throws Exception {
ArtisanNettyClient artisanNettyClient = new ArtisanNettyClient("localhost", 9000);
artisanNettyClient.connect();
}
public ArtisanNettyClient(String host, int port) {
this.host = host;
this.port = port;
init();
}
private void init() {
// клиенту требуется группа цикла событий
group = new NioEventLoopGroup();
// Создать объект запуска клиента
// bootstrap многоразовый, Просто инициализируйте его при создании экземпляра NettyClient.
bootstrap = new Bootstrap();
bootstrap.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
// Добавить процессор
ch.pipeline().addLast(new ArtisanNettyClientHandler(ArtisanNettyClient.this));
}
});
}
public void connect() throws Exception {
System.out.println("netty client start。。");
// Начать клиент подключать серверную часть
ChannelFuture cf = bootstrap.connect(host, port);
cf.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if (!future.isSuccess()) {
// Повторное соединение передается внутреннему потоку для выполнения.
future.channel().eventLoop().schedule(() -> {
System.err.println("Повторно подключиться к серверу...");
try {
connect();
} catch (Exception e) {
e.printStackTrace();
}
}, 3000, TimeUnit.MILLISECONDS);
} else {
System.out.println("Сервер соединился успешно...");
}
}
});
// Мониторинг закрытия канала
cf.channel().closeFuture().sync();
}
}
Этот код определяет файл с именемArtisanNettyClient
издобрый,он содержитклиентиз初始化исоединятьлогика。
EventLoopGroup
:NettyиспользоватьEventLoopGroup
для обработки цикла событий иIOдействовать。Здесь созданNioEventLoopGroup
,для обработкиклиентизIOдействовать。Bootstrap
:ЭтоNettyиз Еще один основной компонент,Используется для настройки и инициализации клиента.ChannelFuture
:Это一个异步результат对象,用于表示通道действоватьизрезультат。connect()
метод:这个метод用于启动клиентисоединятьна сервер。еслисоединятьнеудача,它将использоватьschedule
метод在3Повторите попытку через несколько секундсоединять。ArtisanNettyClientHandler
:Это должно быть обычаемизкласс обработки,Используется для обработки бизнес-логики,Но в этом коде не приведена конкретная реализация.init()
метод:这个метод用于初始化клиентизBootstrap
иEventLoopGroup
。operationComplete()
метод:ЭтоChannelFutureListener
из回调метод,для обработкисоединятьдействоватьизрезультат。еслисоединятьнеудача,Он организует повторную попытку соединения. Если соединение прошло успешно,Он напечатает сообщение об успехе.closeFuture().sync()
:这个метод用于等待клиентканал закрыт,Обязательноклиент Заполните все необходимое перед закрытиемизочистка。В этом примере клиент попытается подключиться к указанному адресу и порту сервера, и если соединение не удастся, он автоматически повторит попытку подключения.
package com.artisan.reconnect;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil;
/**
* @author маленький мастер
* @version 1.0
* @mark: show me the code , change the world
*/
public class ArtisanNettyClientHandler extends ChannelInboundHandlerAdapter {
private ArtisanNettyClient artisanNettyClient;
public ArtisanNettyClientHandler(ArtisanNettyClient artisanNettyClient) {
this.artisanNettyClient = artisanNettyClient;
}
/**
* Этот метод будет запущен, когда сервер завершит работу.
*
* @param ctx
* @throws Exception
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
// СоздайтеByteBuf,Содержит строку «HelloServer»из
ByteBuf buf = Unpooled.copiedBuffer("HelloServer".getBytes(CharsetUtil.UTF_8));
// Отправить сообщение на сервер
ctx.writeAndFlush(buf);
}
/**
* Он сработает, когда на канале произойдет событие чтения, то есть сервер отправит данные клиенту.
*
* @param ctx
* @param msg
* @throws Exception
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
// Получить содержимое сообщения
ByteBuf buf = (ByteBuf) msg;
// 打印服务端отправлятьиз消息
System.out.println("Получено сообщение от сервера:" + buf.toString(CharsetUtil.UTF_8));
// Адрес сервера печати
System.out.println("Адрес сервера: " + ctx.channel().remoteAddress());
}
/**
* Вызывается, когда канал неактивен
*
* @param ctx
* @throws Exception
*/
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
// Распечатать сообщение с подсказкой
System.err.println("Отключить и снова подключить во время работы...");
// 调用клиентизconnectметод进行重连
artisanNettyClient.connect();
}
/**
* Вызывается при обнаружении исключения
*
* @param ctx
* @param cause
* @throws Exception
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
// Распечатать информацию о стеке исключений
cause.printStackTrace();
// Закрыть канал
ctx.close();
}
}
Этот класс обработчика содержит некоторые основные методы для обработки активации, чтения, неактивности и исключений канала. Вот краткое описание каждого метода:
channelActive()
:когдаклиентуспехсоединятьна сервер时,Этот метод будет называться,и отправляет сообщение на сервер.channelRead()
:когдаклиент Когда сообщение получено с сервера,Этот метод будет называться,и打印出接收到из Содержание сообщенияи服务器изадрес。channelInactive()
:когда通道不再活跃时(Например,связь отключена),Этот метод будет называться,И попробуйте перезагрузить сервер.exceptionCaught()
:когда捕获到异常时,Этот метод будет называться,и打印异常из Информация трассировки стека,Затем Закрыть канал。Этот класс обработки является частью клиентской логики и отвечает за взаимодействие между клиентом и сервером.
Сначала запустите клиент (обязательно), а затем запустите сервер, чтобы проверить автоматическое переподключение клиента.
Запускайте клиент, а не сервер
Запустить сервер
Сбой сети или сбой сервера во время работы системы,В результате клиент отключается от сервера и его необходимо подключить заново.,Можно найти вклиент处理данныеизHandlerизchannelInactive
метод中进行重连。
Во время работы отключите сервер и перезапустите его через некоторое время, чтобы убедиться, что клиент автоматически подключается во время работы.
Отключить сервер
Восстановить сервер