ByteBuffer-编码字符串和put与CharSet编码之间的区别?

问题描述 投票:1回答:1

我有两种不同的方法可以从字符串创建ByteBuffer对象:

  1. 从字符串中使用byte[]方法获取ByteBuffer.put(byte[])
private ByteBuffer respWithPut() {
    ByteBuffer respBuf = ByteBuffer.allocate(1024);
    respBuf.put(httpResponse().getBytes(StandardCharsets.US_ASCII));
    return respBuf;
}
  1. 使用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/"

java nio bytebuffer
1个回答
0
投票

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
© www.soinside.com 2019 - 2024. All rights reserved.