Задать вопрос
@grabedinex

Как правильно привести к одному типу десериализованные данные protobuf?

Добрый вечер. Постараюсь расписать проблему развернуто т.к задав вопрос на stackoverflow я так и не получил ответ.

Итак. Имеем сервер на java с использованием фреймворка Netty.io.
На сервер приходят пакеты от клиента на C# в виде:
[2byte длина][1byte тип][Xbyte protobuf данные]
Сервер в своей pipeline выкачивает нужный frame исходя из байтов длинны. И в итоге в обработчик приходит 1 frame: [1byte тип][Xbyte protobuf data] это и есть 1 пакет от клиента который нужно передать на обработку логике не задерживая при этом потоки Netty
Для пущей наглядности приведу код описанного выше

Здесь просто инициализация netty
private static void start(){
        LOG.info("Starting netty");
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup(3);
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .localAddress(new InetSocketAddress(Config.PORT))
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast("Register",new RegisterHandler());
                            ch.pipeline().addLast("FrameDecoder",new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN,27,0,2,0,2,true));
                        ch.pipeline().addLast(new ByteToPackageDecoder());
      }
                    });
            ChannelFuture f = b.bind().sync();
            f.channel().closeFuture().sync();
        } catch (Exception ex) {
        }
        finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }


далее код ByteToPackageDecoder хэндлера. Он расширяет extends MessageToMessageDecoder
@Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {

        Logic.listMSG.add(in);
        Logic.getLogin();

            int bits32 = (int) in.getByte(0) & 0xff; //Читаем правильно 1 байт(убираем отрицательные числа)
            LOG.info("Bytes to frame:" + in.readableBytes() + "READ 1 byte: " + bits32);
            byte[] buf = new byte[in.readableBytes() - 1];
            in.getBytes(1, buf);
            Package p = new Package(1, buf, ctx);
            switch (bits32) {
                case 1:
                    Login1PackageOuterClass.Login1Package Login1Package =   Login1PackageOuterClass.Login1Package.parseFrom(buf);
                    LOG.debug("Read message : " + Login1Package.getLogin());
            }
    }


Это лишь мои тесты, и грубый набросок. Как видите я привожу 1 байт типа в читаемый вид что бы видов пакетов у меня было 255. Далее извлекаю protobuf данные и пробую достать логин. Все работает.
НО! есть одно НО. Это все в pipeline и этого допускать нельзя.

Я понимаю мне нужно сделать отдельный поток серверной логики и стартовать его вместе с netty для теста я создаю public class Logic implements Runnable

Который имеет статический public static BlockingQueue listMSG = new PriorityBlockingQueue(1000);
Для добавление пакетов в очередь ну и бесконечный While для чтения этого списка.

И вот собственно в чем вопрос. Есть несколько вариантов развития событий..
1. Я могу передавать ByteBuf такого вида [1byte тип][Xbyte protobuf data] для обработки логики. А в логике уже производить присвоение protobuf данных нужному экземпляру
Login1PackageOuterClass.Login1Package Login1Package = Login1PackageOuterClass.Login1Package.parseFrom(buf);

в конструкции Switch(1byte тип)

2. Я также могу воспользоваться рефлексией создавать новый объект Package передавая тип пакета. А потом записывать уже в него все данные из protobuf. Передавать в очередь уже этот Package.
В логике же я буду просто доставать методы уже рефлексией. (на самом деле методов то не много, у каждого пакета будер read и send)

Больше вариантов мои знания увидеть не позволяют...

1 вариант мне не нравится тем что мне необходимо передавать канал(сокет) в игровую логику, что бы потом я мог ответить (после прохождения бд и т.д). А так я буду лишь передавать те же данные логике.

2 вариант мне кажется слишком медленным т.к я считаю излишним применение рефлексии когда я знаю все возможные варианты сообщений.

Подскажите правильный подход к архитектуре подобного рода? Мне нужно всего лишь поместить мои пакеты в очередь на обработку игровой логике. Например в BlockingQueue и все.. А в логике достать...
И я не понимаю как их правильнее привести к одному типу....
  • Вопрос задан
  • 367 просмотров
Подписаться 1 Оценить Комментировать
Решения вопроса 2
Проблема высосана из пальца. Protobuf декодируется быстро. Для этого и создан.
Не пользуйтесь конструкциями типа switch/case. В данном случае напрашивается массив диспетчеров, каждый из которых декодирует protobuf и отправляет запрос дальше, каждый своему обработчику. Делать это можно по-разному. Хотите - складывайте в очередь. Но проще сделать Executor и обрабатывать в некоторое число потоков.
Ответ написан
@grabedinex Автор вопроса
Посмотрел в целом на интересующие моменты в архитектуре вполне годного эмулятора, буду делать нечто похожее с ExecutorService. https://bitbucket.org/l2jserver/l2j_server/src/0e6...
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы