通过数据包从服务器向客户端发送 png:indexOutOfBoundsException

Send png via packet from server to client: indexOutOfBoundsException

我在尝试从服务器向客户端发送 png 时使用 netty 收到 indexOutOfBoundException。错误发生在它读取客户端中的字节 p.readBytes() 的行上。

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)

服务器端:

  1. 获取服务器所在特定文件夹中的图片
  2. 将图像转换为字节数组以发送数据
  3. 使用数据包向客户端发送数据

客户端:

  1. 接收图像的字节数组//我相信这里出现问题
  2. 将字节数组转换为像素图 (libgdx)
  3. 将像素图添加到像素图数组的特定索引
  4. 稍后用像素图做点什么

服务器数据包:

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


客户端数据包:

    @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 方法:

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

        return bytes;
    }

您的问题是您 re-encoding 图片,因此改变了文件大小。当您读取图像 ImageIO.read() 时,它可能会丢失元数据,然后当您使用 ImageIO.write() 写入它时,不能保证将其逐字节编码与最初在磁盘上编码的完全相同。我建议直接从文件中复制字节:

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