NIO Http文件服务器 - 连接过早关闭

时间:2015-09-16 05:57:46

标签: http netty nio nanohttpd

我想使用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响应大小的正确方法是什么?

2 个答案:

答案 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变为可写...