4

When sending file, you can do ctx.writeAndFlush(new ChunkedFile(new File("file.png")));.

how about a List<Object>?

The list contains String and bytes of image.

from the documentation there's ChunkedInput() but I'm not able to get the use of it.

UPDATE

let's say in my Handler, inside channelRead0(ChannelHandlerContext ctx, Object o) method where I want to send the List<Object> I've done the following

@Override
protected void channelRead0(ChannelHandlerContext ctx, Object o) throws Exception {

   List<Object> msg = new ArrayList<>();

   /**getting the bytes of image**/
   byte[] imageInByte;
   BufferedImage originalImage = ImageIO.read(new File(fileName));
   // convert BufferedImage to byte array
   ByteArrayOutputStream bAoS = new ByteArrayOutputStream();
   ImageIO.write(originalImage, "png", bAoS);
   bAoS.flush();
   imageInByte = baos.toByteArray();
   baos.close();

   msg.clear();
   msg.add(0, "String"); //add the String into List
   msg.add(1, imageInByte); //add the bytes of images into list

   /**Chunk the List<Object> and Send it just like the chunked file**/
   ctx.writeAndFlush(new ChunkedInput(DONT_KNOW_WHAT_TO_DO_HERE)); //

}
Polar
  • 3,327
  • 4
  • 42
  • 77

1 Answers1

4

Just implement your own ChunkedInput<ByteBuf>. Following the implementations shipped with Netty you can implement it as follows:

public class ChunkedList implements ChunkedInput<ByteBuf> {
    private static final byte[] EMPTY = new byte[0];
    private byte[] previousPart = EMPTY;
    private final int chunkSize;
    private final Iterator<Object> iterator;

    public ChunkedList(int chunkSize, List<Object> objs) {
        //chunk size in bytes
        this.chunkSize = chunkSize;
        this.iterator = objs.iterator();
    }


    public ByteBuf readChunk(ChannelHandlerContext ctx) {
        return readChunk(ctx.alloc());
    }

    public ByteBuf readChunk(ByteBufAllocator allocator) {
        if (isEndOfInput())
            return null;
        else {
            ByteBuf buf = allocator.buffer(chunkSize);
            boolean release = true;
            try {
                int bytesRead = 0;
                if (previousPart.length > 0) {
                    if (previousPart.length > chunkSize) {
                        throw new IllegalStateException();
                    }
                    bytesRead += previousPart.length;
                    buf.writeBytes(previousPart);
                }
                boolean done = false;
                while (!done) {
                    if (!iterator.hasNext()) {
                        done = true;
                        previousPart = EMPTY;
                    } else {
                        Object o = iterator.next();
                        //depending on the encoding
                        byte[] bytes = o instanceof String ? ((String) o).getBytes() : (byte[]) o;
                        bytesRead += bytes.length;
                        if (bytesRead > chunkSize) {
                            done = true;
                            previousPart = bytes;
                        } else {
                            buf.writeBytes(bytes);
                        }
                    }
                }
                release = false;
            } finally {
                if (release)
                    buf.release();
            }
            return buf;
        }
    }

    public long length() {
        return -1;
    }

    public boolean isEndOfInput() {
        return !iterator.hasNext() && previousPart.length == 0;
    }

    public long progress() {
        return 0;
    }

    public void close(){
        //close
    }
}

In order to write ChunkedContent there is a special handler shipped with Netty. See io.netty.handler.stream.ChunkedWriteHandler. So just add to your downstream. Here is the quote from documentation:

A ChannelHandler that adds support for writing a large data stream asynchronously neither spending a lot of memory nor getting OutOfMemoryError. Large data streaming such as file transfer requires complicated state management in a ChannelHandler implementation. ChunkedWriteHandler manages such complicated states so that you can send a large data stream without difficulties.

St.Antario
  • 26,175
  • 41
  • 130
  • 318
  • Just a note... if you want to send a file and not need to manipulate its content in the pipeline you should really use `DefaultFileRegion` as it will allow you to use `sendfile(...)` a.k.a zero-copy file transfer. – Norman Maurer Dec 13 '17 at 17:56
  • @St.Antario - Thank you for answering my question! I really appreciate it and I think your answer could give me the solution, I really don't get the use of `ChunkedInput() `, so can you please make it more clear for me? I already update my question, inside my Handler, in `channelRead0(ChannelHandlerContext ctx, Object o) ` how can I use your given solution? Thank you so much! – Polar Dec 13 '17 at 17:56
  • @St.Antario - Thank you so much! Still, I don't get it, XD, but let me try to read the documentation again and try your solution, I really appreciate your help! thanks! I'll update you later, Thank you so much! – Polar Dec 13 '17 at 18:05
  • @Polar replace `new ChunkedInput(DONT_KNOW_WHAT_TO_DO)` with `new ChukedList(msg, 1024)`. It will chunk your content by 1024 bytes. – St.Antario Dec 13 '17 at 18:15
  • @St.Antario - Yo! Thanks for every response! By the way, from the Server where I want to receive the List Object, I'm still getting `io.netty.handler.codec.TooLongFrameException: Adjusted frame length exceeds 1048576: 1399157370 - discarded` error. . . do you have any idea? – Polar Dec 14 '17 at 01:02
  • Also, I'm getting error of `io.netty.util.concurrent.BlockingOperationException: DefaultChannelPromise@ee834e(incomplete)` from the Client where I'm sending the List Object. maybe this happen because the Client being disconnected from the Server due to `io.netty.handler.codec.TooLongFrameException: Adjusted frame length exceeds 1048576: 1399157370 - discarded` error... – Polar Dec 14 '17 at 01:04
  • I give up. . . I'm having a hard time understanding this library. . . :( I now using `ServerSocket` and `Socket` from my old project. Thank you. – Polar Dec 15 '17 at 16:01