我想使用java NIO创建一个HTTP静态文件服务器,它适用于小文件,但似乎截断了较大文件的HTTP响应(根据我的Chrome Inspector,返回了3.8 MB图像中的672 KB,并且我的浏览器显示部分损坏的图像)。以下代码是否错误?
(我知道有现有的库,最终我将在我的项目中使用一个。但最初我想自己实现一个基本的,看看我的项目概念是否可行。)
Iterator<SelectionKey> keys = selector.selectedKeys().iterator();
while (keys.hasNext()) {
SelectionKey key = keys.next();
keys.remove();
if (key.isAcceptable()) {
// New Client encountered
serverSocket.accept().configureBlocking(false)
.register(selector, SelectionKey.OP_READ);
} else if (key.isReadable()) {
// Additional data for existing client encountered
SocketChannel selectedClient = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(548);
String requestedFile2 = getRequstedFile(key, selectedClient, buffer);
buffer.clear();
buffer.flip();
FileChannel fc = FileChannel.open(Paths.get(requestedFile2));
String string = "HTTP/1.1 200 Ok\nContent-Type: image/jpeg\nContent-Length: "
+ (Files.size(Paths.get(requestedFile2)) + "\n\n");
selectedClient.write(ByteBuffer.wrap(string.getBytes()));
while (fc.read(buffer) > -1) {
buffer.flip(); // read from the buffer
selectedClient.write(buffer);
buffer.clear();
}
selectedClient.close();
}
}
(为简洁省略了异常处理等)
修改
我有内容长度不匹配错误消息。那么在使用NIO API读取文件内容时,确定HTTP响应大小的正确方法是什么?
答案 0 :(得分:1)
buffer.clear();
那应该是
buffer.compact();
并且循环应该是
while (fc.read(buffer) > 0 || buffer.position() > 0)
你假设一切都是写的。
您还需要将HTTP标题行终止符更改为\r\n
。
您需要研究有关内容长度的RFC 2616。
答案 1 :(得分:1)
我猜你必须检查来自selectedClient.write()的返回值,检查SocketChannel.write()文档:
除非另有说明,否则只有在写入所有r请求的字节后才会返回写操作。某些类型的通道,根据其状态,可能只写入一些字节,或者根本不写。
这可能就是这种情况。添加另一个内部循环,只要缓冲区中剩余字节,就会写入输出。或者您可以根据ByteBuffer.compact()中的示例修改循环:http://docs.oracle.com/javase/7/docs/api/java/nio/ByteBuffer.html#compact()
while (buffer.position() > 0 || fc.read(buffer) > 0) {
buffer.flip(); // read from the buffer
selectedClient.write(buffer);
buffer.compact();
}
请记住,代码假设selectedClient正在阻止。如果不是这种情况,你需要调用另一个select()等待selectedClient变为可写...