英文:
Send png via packet from server to client: indexOutOfBoundsException
问题
我在尝试从服务器发送PNG图像到客户端时,使用Netty出现了IndexOutOfBoundsException异常。错误发生在客户端的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)
服务器端:
- 从服务器所在位置的特定文件夹获取图像
- 将图像转换为字节数组以便传输数据
- 使用数据包将数据发送到客户端
客户端:
- 接收图像的字节数组 //我认为问题出在这里
- 将字节数组转换为Pixmap(libgdx)
- 将Pixmap添加到Pixmap数组的特定索引位置
- 稍后处理Pixmap
服务器数据包部分:
@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()); //写入图像大小
ByteArrayOutputStream stream = new ByteArrayOutputStream();
ImageIO.write(img, "png", stream);
writeBytes(stream.toByteArray()); // 写入图像的字节数组
stream.flush();
stream = null;
} catch (IOException e) {
writeInt(0);
}
}
setLength(getBuffer().readableBytes());
}
客户端数据包部分:
@Override
public void execute(Packet p) {
size = (int)p.readByte();
context.pixmapArray = new Pixmap[size]; //创建与地图数量相符的Pixmap数组
int i=0;
while(i<size) {
context.getMaps().add((String)p.readByteString()); //将所有地图名称写入列表
Integer fileSize = p.readInt(); //读取PNG大小
if(fileSize == 0) {
context.pixmapArray[i] = null;
}else {
Pixmap pixmap = new Pixmap(p.readBytes(fileSize), 0, fileSize); //字节数组转换为Pixmap
context.pixmapArray[i] = pixmap; //将Pixmap添加到Pixmap数组中以供将来使用
}
i++;
}
}
readBytes方法:
public byte[] readBytes(int length) {
byte[] bytes = new byte[length];
this.dataBuffer.readBytes(bytes); //netty的ByteBuf
return bytes;
}
英文:
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:
- Get images in a specific folder where the server is located
- Convert image to a byte array for sending data
- Send data to the client using packet
Client-Side:
- Receive byte array of image // issue occurs here I believe
- Convert byte array to Pixmap (libgdx)
- Add pixmap to a specific index of Pixmap array
- 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;
}
答案1
得分: 2
问题在于您正在重新编码图像,从而更改文件大小。当您读取图像 ImageIO.read()
时,它可能会丢失元数据,然后当您使用 ImageIO.write()
写入时,不能保证与最初在磁盘上编码时的字节完全相同。我建议直接从文件中复制字节:
File imageFile = new File(mapDir);
byte[] fileContent = Files.readAllBytes(imageFile.toPath());
writeInt((int)imageFile.length()); //这应该与fileContent.length相同
writeBytes(fileContent);
请注意,上述代码部分是代码示例,不需要翻译。
英文:
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);
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论