我有两种不同的方法可以从字符串创建ByteBuffer
对象:
byte[]
方法获取ByteBuffer.put(byte[])
:private ByteBuffer respWithPut() {
ByteBuffer respBuf = ByteBuffer.allocate(1024);
respBuf.put(httpResponse().getBytes(StandardCharsets.US_ASCII));
return respBuf;
}
Charset.encode(String)
方法:private ByteBuffer respFromChar() {
return StandardCharsets.US_ASCII.encode(httpResponse());
}
我正在尝试使用此命令发送一个简单的HTTP响应(问题末尾的完整代码)。使用respWithPut()
时,客户端上的响应已损坏,而respFromChar()
正常运行。
respWithPut()
我在做什么错?
完整示例代码:
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.Arrays;
import java.util.concurrent.Future;
public class AsyncServer {
final String HTTP_DELIM = "\r\n";
private String httpResponse() {
String body = "HELLO";
String prologue = "HTTP/1.1 200 OK";
String header = String.join(HTTP_DELIM,
Arrays.asList(
"Date: " + Instant.now().toString(),
"Content-Type: text/plain",
String.format("Content-Length: %d", body.length()),
HTTP_DELIM
)
);
return prologue + HTTP_DELIM + header +body;
}
private ByteBuffer respWithPut() {
ByteBuffer respBuf = ByteBuffer.allocate(1024);
respBuf.put(httpResponse().getBytes(StandardCharsets.US_ASCII));
return respBuf;
}
private ByteBuffer respFromChar() {
return StandardCharsets.US_ASCII.encode(httpResponse());
}
public void startHttpServer() throws Exception {
AsynchronousServerSocketChannel listener
= AsynchronousServerSocketChannel.open().bind(new InetSocketAddress(8080));
while (true) {
Future<AsynchronousSocketChannel> asyncCh = listener.accept();
AsynchronousSocketChannel aSock = asyncCh.get();
aSock.write(respWithPut());
aSock.close();
}
}
public static void main(String[] args) throws Exception {
AsyncServer asyncServer = new AsyncServer();
asyncServer.startHttpServer();
}
}
要提出样品请求,请使用:curl -v "http://localhost:8080/"
。
ByteBuffer具有一个position,指示应从下一个字节读取。您的respWithPut方法需要调用respBuf.flip()以确保缓冲区的位置指向您刚刚放入其中的数据。
[C0之后:
ByteBuffer.allocate
例如,使用长度为八的字节数组调用position limit
↓ ↓
|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_| … |_|
0 1 2 3 4 5 5 6 7 8 9 1 1 1 1 1 1 ↑
0 1 2 3 4 5 buffer size
之后:
ByteBuffer.put
下一个 position limit
↓ ↓
|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_| … |_|
0 1 2 3 4 5 5 6 7 8 9 1 1 1 1 1 1 ↑
0 1 2 3 4 5 buffer size
调用将读取索引8处的字节,该字节仍为零,因为您没有使用ByteBuffer.get
在此处添加任何数据。
调用put
后,限制将是旧位置,新位置将为零,从而使任何现有数据都可以读取:
ByteBuffer.flip