我在使用ByteBuffer时还是有点犹豫。我想要做的是将数据写入 ByteBuffer,然后转到 ByteBuffer 的开头并在所有数据之前写入一个字节(写入数据包的有效负载,然后附加标头。)我该怎么做那?
图表:
缓冲区开始于:
| PAYLOAD |
添加操作码标头后的缓冲区(在我想做的之后):
| HEADER | PAYLOAD |
该| 只是作为数据类型的分隔符,而不是任何东西。
我在使用ByteBuffer时还是有点犹豫。我想要做的是将数据写入 ByteBuffer,然后转到 ByteBuffer 的开头并在所有数据之前写入一个字节(写入数据包的有效负载,然后附加标头。)我该怎么做那?
图表:
缓冲区开始于:
| PAYLOAD |
添加操作码标头后的缓冲区(在我想做的之后):
| HEADER | PAYLOAD |
该| 只是作为数据类型的分隔符,而不是任何东西。
您要查找的内容称为“分散-收集 I/O”,它由ScatteringByteChannel.read(ByteBuffer[])
和支持GatheringByteChannel.write(ByteBuffer[])
。注意数组。这些接口由FileChannel
、SocketChannel
和DatagramSocketChannel
和 管道通道支持。
ByteBuffer bbuf = ByteBuffer.allocate(HEADER_SZ + PAYLOAD_SZ);
bbuf.position(HEADER_SZ);
for(int i=0; i < PAYLOAD_SZ; i++)
bbuf.put(payload[i]);
bbuf.rewind();
for(int i=0; i < HEADER_SZ; i++)
bbuf.put(header[i]);
我已经假设对源数据进行字节索引。批量放置会更好,但这是一个开始。
我要为这个问题添加另一个答案,因为我今天遇到了这个问题,并且接受的解决方案对我的情况没有太大帮助。
为了解决我的问题,我定义了一个int
表示将ByteBuffer
保存的数据量(以字节为单位),以及Queue<Consumer<ByteBuffer>>
如下:
/**
* An {@code int} representing the amount
* of bytes that this {@link OutgoingPacket}
* will send.
*/
private int size;
/**
* A {@link Queue} that lazily writes data to the
* backing {@link ByteBuffer}.
*/
private final Queue<Consumer<ByteBuffer>> queue = new ArrayDeque<>();
接下来,我创建了putByte
,putInt
等方法。
/**
* Writes a single {@code byte} to this
* {@link Packet}'s payload.
*
* @param b
* An {@code int} for ease-of-use,
* but internally down-casted to a
* {@code byte}.
* @return
* The {@link Packet} to allow for
* chained writes.
*/
public OutgoingPacket putByte(int b) {
size++;
queue.offer(payload -> payload.put((byte) b));
return this;
}
最后,我创建了一个分配并传递相应数据的send
方法。ByteBuffer
/**
* Transmits this {@link OutgoingPacket} to
* a specific client.
*
* @param channels
* A variable amount of {@link AsynchronousSocketChannel}s.
*
* TODO: Send to {@link Client} instead.
*/
public void send(AsynchronousSocketChannel... channels) {
/*
* Allocate a new buffer with the size of
* the data being added, as well as an extra
* two bytes to account for the opcode and the
*/
ByteBuffer payload = ByteBuffer.allocate(size + 2);
/*
* Write the opcode to the buffer.
*/
payload.put((byte) opcode);
/*
* Write the length to the buffer.
*/
payload.put((byte) size);
/*
* Add the rest of the data to the buffer.
*/
queue.forEach(consumer -> consumer.accept(payload));
/*
* Flip the buffer so the client can immediately
* read it on arrival.
*/
payload.flip();
/*
* Write the buffer to the channels.
*/
for (AsynchronousSocketChannel channel : channels) {
channel.write(payload);
}
}
希望这将为将来遇到此问题的人提供见解!