简体   繁体   English

Netty文件传输导致异常

[英]Netty file transfer causes exception

I'm trying to transfer files through my netty implementation. 我正在尝试通过netty实现来传输文件。 My custom Decoder and Encoder both know two types of Objects: String and FileChunk, which actually contains the index of the chunk and its content as a byte[] . 我自定义的Decoder和Encoder都知道两种对象: String和FileChunk,它们实际上包含块的索引及其内容(以byte[] The transfer works like: 传输方式如下:

  1. Client0 sends Client1 a JsonObject, as String containing the path where the file should be saved, how large it is, how many slices will be sent etc. Client0向Client1发送一个JsonObject,为String其中包含应保存文件的路径,文件的大小,将发送的切片数等。
  2. Client0 sends the first slice as a FileChunk and blocks the thread to wait for an answer that Client1 successfully received its packet. Client0将第一个分片作为FileChunk发送,并阻塞线程以等待Client1成功接收其数据包的答案。
  3. Client1 received the slice of the File and writes it to the disk. Client1接收到文件的分片,并将其写入磁盘。 Afterward, it sends the success packet to Client0 之后,它将成功数据包发送到Client0
  4. Client0 receives the success packet and sends the next slice. Client0接收成功数据包并发送下一个分片。

This progress should keep on going until the file is transfered. 在文件传输之前,此过程应该一直持续下去。 And it works. 而且有效。 If I add a 1 second delay before sending a 64kb slice of the file! 如果在发送64kb的文件片段之前添加了1秒的延迟! Derp. DERP。

Seems like there is no mistake - but it does not work under heavy load and without blocking threads. 似乎没有错误-但这在重负载且没有阻塞线程的情况下无法正常工作。 Do I need to clear buffers anywhere or do I need a copy? 我需要在任何地方清除缓冲区还是需要副本? Please help... If you are interessted in an example project with IntelliJ and Maven let me know in the comments, I will make one ready. 请帮助...如果您对IntelliJ示例项目感兴趣,并且Maven在评论中让我知道,我会准备的。

Explained enough. 解释够了。 Here is code! 这是代码!

FileTransfer Runnable FileTransfer可运行

public class FileTransfer implements Runnable {

    private FileSlicer slicer;
    private Client client;

    public FileTransfer(FileSlicer slicer, Client client) {
        this.slicer = slicer;
        this.client = client;
    }

    public void run() {

        synchronized(this) {

            while(slicer.hasNext()) {

                try {
                    client.getContext().writeAndFlush(slicer.getNextSlice());
                    this.wait(); //Unblocked when success packet received, works
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }

        }
    }
}

Channel-Initializer (Buffer size is set here, should not overflow by default) Channel-Initializer (在此处设置缓冲区大小,默认情况下不应溢出)

@Override
protected void initChannel(Channel channel) throws Exception {

    channel.config().setRecvByteBufAllocator(new FixedRecvByteBufAllocator(1024 * 65));

    ChannelPipeline pipeline = channel.pipeline();
    pipeline.addLast(new PacketDecoder());
    pipeline.addLast(new PacketEncoder());
    pipeline.addLast(new ChannelEncoder());
    pipeline.addLast(new ServerHandler());

}

Decoder (detects if it is a String or FileChunk and parses it): 解码器 (检测它是String还是FileChunk并对其进行解析):

public class PacketDecoder extends ByteToMessageDecoder {

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf buf, List<Object> output) throws Exception {

        int type = buf.readInt();
        if (buf.readableBytes() <= 0) return;
        byte[] buffer;

        switch (type) {

            case 0:
                buffer = buf.readBytes(buf.readInt()).array();
                output.add(new String(buffer));
                break;

            case 1:
                int read = buf.readInt();
                buffer = buf.readBytes(buf.readInt()).array();
                output.add(new FileChunk(buffer, read));
                break;

            default:
                System.out.println("Unknown Decodec.");
                break;

        }

    }

}

Stacktrace : Stacktrace

io.netty.handler.codec.DecoderException: java.lang.IndexOutOfBoundsException: readerIndex(12) + length(65536) exceeds writerIndex(40960): PooledUnsafeDirectByteBuf(ridx: 12, widx: 40960, cap: 66560)
    at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:347)
    at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:230)
    at io.netty.channel.ChannelHandlerInvokerUtil.invokeChannelReadNow(ChannelHandlerInvokerUtil.java:84)
    at io.netty.channel.DefaultChannelHandlerInvoker.invokeChannelRead(DefaultChannelHandlerInvoker.java:153)
    at io.netty.channel.PausableChannelEventExecutor.invokeChannelRead(PausableChannelEventExecutor.java:86)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:389)
    at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:956)
    at io.netty.channel.epoll.AbstractEpollStreamChannel$EpollStreamUnsafe.epollInReady(AbstractEpollStreamChannel.java:618)
    at io.netty.channel.epoll.EpollEventLoop.processReady(EpollEventLoop.java:331)
    at io.netty.channel.epoll.EpollEventLoop.run(EpollEventLoop.java:250)
    at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:116)
    at io.netty.util.internal.chmv8.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1412)
    at io.netty.util.internal.chmv8.ForkJoinTask.doExec(ForkJoinTask.java:280)
    at io.netty.util.internal.chmv8.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:877)
    ...

The decode function assumes the entire file is available, however the buffer may only contain part of the data, depending on how much of the stream was received. 解码功能假定整个文件可用,但是缓冲区可能仅包含部分数据,具体取决于接收到多少流。

One way to address this is by adding a frame decoder, such as LengthFieldBasedFrameDecoder , which segments the stream according to a length field in the message, such as in your example. 解决此问题的一种方法是添加帧解码器,例如LengthFieldBasedFrameDecoder ,该解码器根据消息中的长度字段对流进行分段,例如您的示例。

Another option is to use the same approach as the File Server example in the docs: https://netty.io/4.1/xref/io/netty/example/http/file/package-summary.html 另一个选择是使用与文档中的文件服务器示例相同的方法: https : //netty.io/4.1/xref/io/netty/example/http/file/package-summary.html

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM