Netty CorruptedFrameException с несколькими пакетами подключения, поступающими одновременно

Я столкнулся с очень странной проблемой в моей программе, которая использует Netty.

Я слушаю порт и анализирую сообщения (используя реализацию FrameDecoder). Все работает нормально, если я получаю одно соединение, но когда я получаю два соединения на один и тот же порт (каждое с другого сервера), я сталкиваюсь с редкой, но критической ситуацией, когда я получаю CorruptedFrameException

Проблема возникает, когда моя программа получает TCP-пакеты с точно такой же отметкой времени (при отправке информации с очень высокой скоростью) следующим образом.

  1. TCP-пакет с сервера 1
  2. Пакет TCP от сервера 2
  3. TCP-пакет с сервера 1 (продолжение сообщения, начатого в пункте 1)
  4. TCP-пакет с сервера 2 (продолжение сообщения, отмеченного пунктом 2)

Моя программа пытается разобрать 1 и 2 как сообщение, вместо того, чтобы знать, что фактическим сообщением является 1 и 3 и 2 и 4. Я где-то читал, что, возможно, мне нужно создать новый экземпляр FrameDecoder для каждого соединения канала, но я не знаю как именно это сделать. Я добавляю декодер в конвейер при запуске и не могу понять, как добавить новый на конкретный канал

Исключения, с которыми я сталкиваюсь:

org.jboss.netty.handler.codec.frame.CorruptedFrameException: Adjusted frame length (0) is less than lengthFieldEndOffset: 2
    at org.jboss.netty.handler.codec.frame.LengthFieldBasedFrameDecoder.decode(LengthFieldBasedFrameDecoder.java:340) ~[netty-3.1.5.GA.jar:]
    at org.jboss.netty.handler.codec.frame.FrameDecoder.callDecode(FrameDecoder.java:282) ~[netty-3.1.5.GA.jar:]
    at org.jboss.netty.handler.codec.frame.FrameDecoder.messageReceived(FrameDecoder.java:214) ~[netty-3.1.5.GA.jar:]
    at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:345) ~[netty-3.1.5.GA.jar:]
    at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:332) ~[netty-3.1.5.GA.jar:]
    at org.jboss.netty.channel.socket.nio.NioWorker.read(NioWorker.java:323) ~[netty-3.1.5.GA.jar:]
    at org.jboss.netty.channel.socket.nio.NioWorker.processSelectedKeys(NioWorker.java:275) ~[netty-3.1.5.GA.jar:]
    at org.jboss.netty.channel.socket.nio.NioWorker.run(NioWorker.java:196) ~[netty-3.1.5.GA.jar:]
    at org.jboss.netty.util.internal.IoWorkerRunnable.run(IoWorkerRunnable.java:46) ~[netty-3.1.5.GA.jar:]
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:651) [na:1.5.0]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:676) [na:1.5.0]
    at java.lang.Thread.run(Thread.java:595) [na:1.5.0]

а также

org.jboss.netty.handler.codec.frame.TooLongFrameException: Adjusted frame length exceeds 4096: 8224
        at org.jboss.netty.handler.codec.frame.LengthFieldBasedFrameDecoder.decode(LengthFieldBasedFrameDecoder.java:296) ~[netty-3.1.5.GA.jar:]
        at org.jboss.netty.handler.codec.frame.FrameDecoder.callDecode(FrameDecoder.java:282) ~[netty-3.1.5.GA.jar:]
        at org.jboss.netty.handler.codec.frame.FrameDecoder.messageReceived(FrameDecoder.java:216) ~[netty-3.1.5.GA.jar:]
        at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:345) ~[netty-3.1.5.GA.jar:]
        at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:332) ~[netty-3.1.5.GA.jar:]
        at org.jboss.netty.channel.socket.nio.NioWorker.read(NioWorker.java:323) ~[netty-3.1.5.GA.jar:]
        at org.jboss.netty.channel.socket.nio.NioWorker.processSelectedKeys(NioWorker.java:275) ~[netty-3.1.5.GA.jar:]
        at org.jboss.netty.channel.socket.nio.NioWorker.run(NioWorker.java:196) ~[netty-3.1.5.GA.jar:]
        at org.jboss.netty.util.internal.IoWorkerRunnable.run(IoWorkerRunnable.java:46) ~[netty-3.1.5.GA.jar:]
        at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:651) [na:1.5.0]
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:676) [na:1.5.0]
        at java.lang.Thread.run(Thread.java:595) [na:1.5.0]

person ArnonSe    schedule 04.06.2012    source источник
comment
возможно, мне нужно создать новый FrameDecoder для каждого канала. Нет, может быть, об этом. Это именно то, что вам нужно сделать.   -  person user207421    schedule 04.06.2012
comment
Я понял, но как мне это сделать? Я добавляю декодированный объект ChannelPipeLine object.addLast(decoder, decoderObject) при инициализации, но когда подключается новый канал, я нахожусь в точке channelConnected(ChannelHandlerContext ctx, ChannelStateEvent t)... Если я создаю новый декодер, как привязать его к каналу? Чего-то не хватает в загадке :)   -  person ArnonSe    schedule 04.06.2012
comment
Это работа фабрики каналов. Определите тот, который создает ваш декодер, а затем либо используйте начальную загрузку (с фабрикой каналов), либо передайте фабрику конвейера фабрике каналов при запросе нового канала.   -  person Nicholas    schedule 04.06.2012


Ответы (2)


Вам нужно добавить новый объект декодера кадров в ваш новый(второй?) канал. Повторяющееся исключение связано с тем, что вы используете один и тот же канал.

  1. Начальная загрузка сервера использует конвейерную фабрику, которая настроит все новые каналы с соответствующими кодировщиками и декодерами.
  2. Всякий раз, когда удаленный клиент подключается к вашему серверу, он создает собственный объект канала.
  3. В реализации Channel PipelineFactory, которую вы используете. Убедитесь, что новый экземпляр декодера кадров создается каждый раз при вызове метода pipe().
  4. Аннотация @Sharable предназначена только для документации. Даже если вы его используете, это ни на что не повлияет, так как это не код/логика. Просто маркер и все.
person Abe    schedule 05.06.2012

Вам нужно «НЕ разделять» FrameDecoder между каналами. FrameDecoder не аннотирован @Sharable, поэтому вы не можете поделиться им. Это причина вашей проблемы здесь ..

person Norman Maurer    schedule 04.06.2012
comment
Спасибо. Однако в моем коде нет аннотации @Sharable, но все же это происходит. Я пытаюсь понять, как реализовать то, что предложили люди в комментариях выше, но все равно не повезло :) - person ArnonSe; 04.06.2012
comment
Если можно ссылку на пример, как добавить FrameDecoder в сам канал, а не в пайплайн (или я что-то упускаю в своем понимании), или нужно создавать совершенно новый пайплайн? Я пытался сделать channel.getPipeLine().addLast(декодер,новый объект), но получаю повторяющееся исключение - person ArnonSe; 04.06.2012