dree
dree

Reputation: 170

Send png via packet from server to client: indexOutOfBoundsException

I am getting an indexOutOfBoundException using netty when trying to send over a png from server to client. The error occurs on the line where it reads the bytes p.readBytes() in client.

Exception in thread "LWJGL Application" java.lang.IndexOutOfBoundsException: readerIndex(97) + length(199852) exceeds writerIndex(185453): PooledUnsafeDirectByteBuf(ridx: 97, widx: 185453, cap: 185453)
    at io.netty.buffer.AbstractByteBuf.checkReadableBytes0(AbstractByteBuf.java:1395)
    at io.netty.buffer.AbstractByteBuf.checkReadableBytes(AbstractByteBuf.java:1389)
    at io.netty.buffer.AbstractByteBuf.readBytes(AbstractByteBuf.java:850)
    at io.netty.buffer.AbstractByteBuf.readBytes(AbstractByteBuf.java:858)
    at com.benberi.cadesim.client.codec.util.Packet.readBytes(Packet.java:79)
    at com.benberi.cadesim.client.packet.in.ListAllMapsPacket.execute(ListAllMapsPacket.java:29)

Server Side:

  1. Get images in a specific folder where the server is located
  2. Convert image to a byte array for sending data
  3. Send data to the client using packet

Client-Side:

  1. Receive byte array of image // issue occurs here I believe
  2. Convert byte array to Pixmap (libgdx)
  3. Add pixmap to a specific index of Pixmap array
  4. Do something with pixmap later

Server Packet:

    @Override
    public void encode() {
        setPacketLengthType(PacketLength.MEDIUM); //
        writeByte((byte)ServerConfiguration.getAvailableMaps().size());
        for (int i=0; i<ServerConfiguration.getAvailableMaps().size(); i++)
        {
            String map = ServerConfiguration.getAvailableMaps().get(i).replace(".txt", "");
            writeByteString(map);
            String mapDir = String.format("maps/%s.png", map);
            try {
                File imageFile = new File(mapDir);
                BufferedImage img = ImageIO.read(imageFile);
                writeInt((int)imageFile.length()); //write size of image
                ByteArrayOutputStream stream = new ByteArrayOutputStream();
                ImageIO.write(img, "png", stream);
                writeBytes(stream.toByteArray()); // write image; byte array
                stream.flush();
                stream = null;
            } catch (IOException e) {
//              e.printStackTrace();
                writeInt(0);
            }
        }
        setLength(getBuffer().readableBytes());
    }


Client Packet:

    @Override
    public void execute(Packet p) {
        size = (int)p.readByte();
        context.pixmapArray = new Pixmap[size]; //create Pixmap array with number of maps
        int i=0;
        while(i<size) {
            context.getMaps().add((String)p.readByteString()); //writes all map names to list
            Integer fileSize = p.readInt(); //read size of png
            if(fileSize == 0) {//incase image not found from server
                context.pixmapArray[i] = null;
            }else {
                Pixmap pixmap = new Pixmap(p.readBytes(fileSize), 0, fileSize); //byte[] to pixmap
                context.pixmapArray[i] = pixmap; //add pixmap to pixmap array for future use
            }
            i++;
        }
    }

readBytes method:

    public byte[] readBytes(int length) {
        byte[] bytes = new byte[length];
        this.dataBuffer.readBytes(bytes); //netty ByteBuf 

        return bytes;
    }

Upvotes: 0

Views: 162

Answers (1)

Lunchbox
Lunchbox

Reputation: 1633

Your issue is that you are re-encoding the image, and thus changing the file size. When you read the image ImageIO.read() it may lose metadata, then when you write it with ImageIO.write() it is not guaranteed to encode it byte for byte the exact same as it was initially encoded on disk. I'd recommend just copying the bytes directly from the file:

File imageFile = new File(mapDir);
byte[] fileContent = Files.readAllBytes(imageFile.toPath());
writeInt((int)imageFile.length()); //this should be the same as fileContent.length
writeBytes(fileContent); 

Upvotes: 2

Related Questions