Это 9-й день моего участия в августовском испытании обновлений.Подробности о мероприятии:Испытание августовского обновления
Введение
В предыдущей статье мы упоминали, что для NioSocketChannel он не получает самые основные строковые сообщения, а только ByteBuf и FileRegion. Однако ByteBuf обрабатывается в бинарном виде, что слишком неинтуитивно для программистов, и обрабатывать его сложнее.Возможна ли прямая обработка простых java-объектов? В этой статье будет рассмотрен этот вопрос.
декодировать и кодировать
Например, нам нужно записать строку прямо в канал, в предыдущей статье мы знали, что это невозможно, и будет выдано следующее сообщение об ошибке:
DefaultChannelPromise@57f5c075(failure: java.lang.UnsupportedOperationException: unsupported message type: String (expected: ByteBuf, FileRegion))
То есть ChannelPromise принимает только ByteBuf и FileRegion, так как же это сделать?
Поскольку ChannelPromise принимает только ByteBuf и FileRegion, нам нужно преобразовать объект String в ByteBuf.
Другими словами, преобразуйте String в ByteBuf перед записью String, а затем преобразуйте ByteBuf в String, когда данные должны быть прочитаны.
Мы знаем, что в ChannelPipeline можно добавить несколько обработчиков, и порядок этих обработчиков можно контролировать.
Потом появилась наша идея: добавить encode в ChannelPipeline, который используется для записи данных для кодирования данных в ByteBuf, а затем добавить decode для декодирования данных в соответствующие данные при записи данных.
Вы знакомы с кодированием и декодированием? Кстати, это сериализация объектов.
сериализация объекта
Сериализация объектов в netty заключается в преобразовании передаваемого объекта и ByteBuf напрямую друг в друга.Конечно, мы можем реализовать это преобразование объекта сами. Но netty предоставила нам два удобных класса преобразования: ObjectEncoder и ObjectDecoder.
Сначала посмотрите на ObjectEncoder, его роль заключается в преобразовании объектов в ByteBuf.
Этот класс очень простой, давайте разберем его:
public class ObjectEncoder extends MessageToByteEncoder<Serializable> {
private static final byte[] LENGTH_PLACEHOLDER = new byte[4];
@Override
protected void encode(ChannelHandlerContext ctx, Serializable msg, ByteBuf out) throws Exception {
int startIdx = out.writerIndex();
ByteBufOutputStream bout = new ByteBufOutputStream(out);
ObjectOutputStream oout = null;
try {
bout.write(LENGTH_PLACEHOLDER);
oout = new CompactObjectOutputStream(bout);
oout.writeObject(msg);
oout.flush();
} finally {
if (oout != null) {
oout.close();
} else {
bout.close();
}
}
int endIdx = out.writerIndex();
out.setInt(startIdx, endIdx - startIdx - 4);
}
}
ObjectEncoder наследует MessageToByteEncoder, который, в свою очередь, наследует ChannelOutboundHandlerAdapter. Почему OutBound? Это потому, что мы хотим преобразовать записанный объект, чтобы он был исходящим.
Сначала используйте ByteBufOutputStream для инкапсуляции ByteBuf.В бою сначала напишите поле LENGTH_PLACEHOLDER, чтобы указать длину байта в потоке. Затем используйте CompactObjectOutputStream для инкапсуляции боя, и, наконец, вы можете использовать CompactObjectOutputStream для записи объекта.
Соответственно, у netty также есть объект ObjectDecoder, который используется для преобразования ByteBuf в соответствующий объект, ObjectDecoder наследуется от LengthFieldBasedFrameDecoder, по сути это ByteToMessageDecoder и ChannelInboundHandlerAdapter, который используется для обработки чтения данных.
Давайте рассмотрим наиболее важные методы декодирования в ObjectDecoder:
protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
ByteBuf frame = (ByteBuf) super.decode(ctx, in);
if (frame == null) {
return null;
}
ObjectInputStream ois = new CompactObjectInputStream(new ByteBufInputStream(frame, true), classResolver);
try {
return ois.readObject();
} finally {
ois.close();
}
}
Как видно из приведенного выше кода, входной ByteBuf преобразуется в ByteBufInputStream и, наконец, преобразуется в CompactObjectInputStream, и объект можно читать напрямую.
Работа с кодировщиками и декодерами
При использовании двух вышеуказанных кодеков вам необходимо добавить их непосредственно в ChannelPipeline на стороне клиента и сервера.
Для серверной части основной код выглядит следующим образом:
//定义bossGroup和workerGroup
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
p.addLast(
// 添加encoder和decoder
new ObjectEncoder(),
new ObjectDecoder(ClassResolvers.cacheDisabled(null)),
new PojoServerHandler());
}
});
// 绑定端口,并准备接受连接
b.bind(PORT).sync().channel().closeFuture().sync();
Точно так же для клиентской стороны наш основной код выглядит следующим образом:
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
p.addLast(
// 添加encoder和decoder
new ObjectEncoder(),
new ObjectDecoder(ClassResolvers.cacheDisabled(null)),
new PojoClientHandler());
}
});
// 建立连接
b.connect(HOST, PORT).sync().channel().closeFuture().sync();
Вы можете видеть, что приведенная выше логика заключается в добавлении ObjectEncoder и ObjectDecoder в ChannelPipeline.
Наконец, вы можете вызвать клиент и браузер:
ctx.write("加油!");
Пишите непосредственно в строковый объект.
Суммировать
С ObjectEncoder и ObjectDecoder мы не ограничены ByteBuf, и гибкость программы значительно улучшена.
Примеры этой статьи могут относиться к:learn-netty4
Эта статья была включена вWoohoo.Floyd Press.com/08-Netty-Break…
Самая популярная интерпретация, самая глубокая галантерея, самые краткие уроки и множество трюков, о которых вы не знаете, ждут вас!
Добро пожаловать, чтобы обратить внимание на мой официальный аккаунт: «Программируйте эти вещи», разбирайтесь в технологиях, лучше поймите себя!