2015-09-16 3 views
0

Я хочу создать статический файловый сервер HTTP с использованием java NIO, и он отлично работает для небольших файлов, но, кажется, урезает HTTP-ответ для больших файлов (672 КБ из 3,8 МБ изображения возвращается в соответствии с моим Chrome Inspector, и мой браузер отображает частично поврежденное изображение). Неправильно ли этот код?NIO Http file server - соединение закрыто досрочно

(я знаю, что есть существующие библиотеки для этого и в конце концов я буду использовать один в моем проекте. Но сначала я хочу реализовать базисна себя, чтобы увидеть, если мой проект концепции выполнимо.)

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(); 

    } 
} 

(обработка исключений и т.д. опущены для краткости)

РЕДАКТИРОВАТЬ

у меня есть сообщение об ошибке контента длины несоответствия. Итак, каков правильный способ определить размер ответа HTTP при чтении содержимого файла с использованием API NIO?

ответ

1
buffer.clear(); 

Это должно быть

buffer.compact(); 

и цикл должен быть

while (fc.read(buffer) > 0 || buffer.position() > 0) 

Вы предполагаете все получили написанное записи.

Также вам необходимо изменить терминаторы строки заголовка HTTP на \r\n.

И вам нужно изучить RFC 2616 о длине содержимого.

+0

Я сделал 3 редактирования, но теперь браузер ничего не показывает. Также я не уверен, что вы подразумеваете под «копированием данных в файл». Я пытаюсь прочитать ОТ файла. Мы говорим о той же проблеме? –

1

Я думаю, вы должны проверить возвращаемое значение selectedClient.write(), проверьте документацию SocketChannel.write():
Если не указано иное, операция записи будет возвращать только после написания всех г просил байт. Некоторые типы каналов, в зависимости от их состояния, могут писать только некоторые из байтов или, возможно, вообще ничего.

Какой может быть случай здесь. Либо добавьте еще один внутренний цикл, который будет писать для вывода, если в буфере остаются байты. Или вы можете изменить цикл в соответствии с примером в 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(), ожидающий, когда выбранныйClient станет доступным для записи ...

Смежные вопросы