Сокет заключительная проблема - последняя часть данных потерян

У меня есть программа Java, которая принимает соединения, получает Запросы HTTP и отправляет ответы HTTP и некоторые данные, хранившие в файле (это - часть кэширующегося прокси). Удаляя все несоответствующее, мой код похож на это:

FileInputStream fileInputStream = new FileInputStream(file);
OutputStream outputStream = socket.getOutputStream();
byte[] buf = new byte[BUFFER_SIZE];
int len = 0;
while ((len = fileInputStream.read(buf)) > 0) {
    outputStream.write(buf, 0, len);
}
outputStream.flush();
socket.close();

Этот код выполнен в особенности поток для каждого связанного клиента.

Когда я имею дело с маленькими файлами (.htm, .gif, .swf, и т.д.), все хорошо работает (однако, я не вижу ничто плохого в браузере). Но когда я загружаю большие файлы (.iso), особенно несколько файлов одновременно, когда система является объектом загрузки, иногда я получаю действительно странное поведение. Браузер загружает 99,99% файла и когда существуют меньше, чем BUFFER_SIZE незагруженных байтов, загружая остановки в течение нескольких секунд, и затем браузер говорит, что ошибка произошла. Я не могу понять то, что происходит, потому что все данные успешно считаны, и даже все данные успешно записаны в outputStream. Как Вы видите, я даже сбрасываю (), но это не берет результата.

Кто-либо может объяснить меня, что происходит?

Править
Загруженный проект на filehosting.org.
Загрузите исходные файлы. Существует архив zip с исходным кодом, Build.xml и Readme.txt. Используйте муравья для создания решения. Описанная проблема происходит в ClientManager.java, Вы найдете комментарий там.

5
задан levanovd 16 December 2009 в 16:23
поделиться

4 ответа

Не уверен, почему это могло произойти, я не вижу проблемы с вашим код. Вы пробовали использовать BufferedInputStream для включения FileInputStream ?

1
ответ дан 15 December 2019 в 01:03
поделиться

I think the most probable cause is that you closed the connection without waiting for the data to be fully transmitted.

You can ask Java to wait a little while for you,

socket.setOption(SocketOptions.SO_LINGER, new Integer(60));
1
ответ дан 15 December 2019 в 01:03
поделиться

На основе быстрого просмотра кодовой базы JDK 1.6:

  • socket.getOutputStream () возвращает экземпляр SocketOutputStream
  • flush () действительно не влияет на экземпляр SocketOutputStream
  • write () в экземпляре SocketOutputStream , похоже, ничего не буферизует в коде Java
  • shutdownOutput () должен гарантировать, что все ожидающие данные записываются до отключения выходной стороны сокета. По крайней мере, в комментариях говорится об этом.

Однако некоторые реализации Socket и т. Д. Являются собственными методами, и я не углублялся в это.

Исходя из того, что я мог сказать, «правильная» последовательность будет следующей:

socket.shutdownOutput();
socket.close();

Однако вы говорите, что пробовали это. Возможно ли, что приложение на другом конце преждевременно закрывает TCP / IP-соединение?

Другая мысль: вы пробовали setSoLinger (true, 60000) , но 60000 секунд, возможно, дольше, чем позволяет ОС . Попробуйте setSoLinger (true, 60) и попробуйте сделать это, прежде чем открывать выходной поток.

2
ответ дан 15 December 2019 в 01:03
поделиться

Я привык сначала отправлять длину, а затем ждать, пока я получу эти данные, но если вы не можете этого сделать, этот блог должен быть полезным:

http: // vadmyst.blogspot.com/2008/04/proper-way-to-close-tcp-socket.html

Это для .NET, но основная логика должна быть такой же.

После отправки данных , вам нужно, чтобы отправляющая сторона закрыла свое соединение, затем выполните shutdownOutput и пусть другая сторона продолжит чтение до тех пор, пока не возникнет ситуация, когда ничего не может быть прочитано или возникнет исключение, а затем вы должно быть все.

0
ответ дан 15 December 2019 в 01:03
поделиться
Другие вопросы по тегам:

Похожие вопросы: