G
G
grabedinex2016-12-28 23:28:32
Java
grabedinex, 2016-12-28 23:28:32

How to properly cast deserialized protobuf data to one type?

Good evening. I will try to describe the problem in detail, since I asked a question on stackoverflow and did not receive an answer.
So. We have a java server using the Netty.io framework .
The server receives packets from the client in C# in the form:
[2byte length][1byte type][Xbyte protobuf data]
The server in its pipeline pumps out the required frame based on the length bytes. And as a result, 1 frame arrives in the handler: [1byte type][Xbyte protobuf data] this is 1 packet from the client that needs to be passed to the processing logic without delaying the Netty streams. For
greater clarity, I will give the code described above .

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();
        }

further code of ByteToPackageDecoder handler. It extends 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());
            }
    }

These are just my tests, and a rough sketch. As you can see, I convert 1 byte of the type into a readable form so that I have 255 types of packets. Next, I extract the protobuf data and try to get the login. Everything is working.
BUT! there is one BUT. This is all in the pipeline and this should not be allowed.
I understand that I need to make a separate server logic thread and start it together with netty for the test, I create a public class Logic implements Runnable
Which has a static public static BlockingQueue listMSG = new PriorityBlockingQueue(1000);
For adding packets to the queue, well, and endless While for reading this list.
And that's actually the question. There are several options for the development of events..
1. I can pass a ByteBuf like this [1byte type][Xbyte protobuf data] to handle logic. And in the logic to already assign protobuf data to the desired instance
Login1PackageOuterClass.Login1Package Login1Package = Login1PackageOuterClass.Login1Package.parseFrom(buf);

in the Switch(1byte type) construct
2. I can also use reflection to create a new Package object passing in the package type. And then write all the data from protobuf into it. Pass this Package to the queue.
In logic, I will simply get the methods already by reflection. (in fact, there are not many methods, each package has a read and send buffer)
My knowledge does not allow me to see more options ...
I don’t like the 1st option because I need to pass a channel (socket) to the game logic, so that later I could answer (after passing the database, etc.). And so I will only pass the same data to the logic.
Option 2 seems too slow to me, because I consider it unnecessary to use reflection when I know all possible message options.
Can you tell me the correct approach to this kind of architecture? I just need to queue my packets for processing by the game logic. For example, in BlockingQueue and that's it .. But in logic to get it ...
And I don’t understand how it’s more correct to bring them to one type ....

Answer the question

In order to leave comments, you need to log in

1 answer(s)
R
Ruslan Lopatin, 2016-12-29
@grabedinex

The problem is sucked from the finger. Protobuf decodes quickly. This is what it was created for.
Don't use switch/case constructs. In this case, an array of dispatchers suggests itself, each of which decodes the protobuf and sends the request further, each to its own handler. You can do this in different ways. If you want, get in line. But it's easier to make an Executor and process it in a certain number of threads.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question