У меня есть программа 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, Вы найдете комментарий там.
Не уверен, почему это могло произойти, я не вижу проблемы с вашим код. Вы пробовали использовать BufferedInputStream
для включения FileInputStream
?
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));
На основе быстрого просмотра кодовой базы 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)
и попробуйте сделать это, прежде чем открывать выходной поток.
Я привык сначала отправлять длину, а затем ждать, пока я получу эти данные, но если вы не можете этого сделать, этот блог должен быть полезным:
http: // vadmyst.blogspot.com/2008/04/proper-way-to-close-tcp-socket.html
Это для .NET, но основная логика должна быть такой же.
После отправки данных , вам нужно, чтобы отправляющая сторона закрыла свое соединение, затем выполните shutdownOutput
и пусть другая сторона продолжит чтение до тех пор, пока не возникнет ситуация, когда ничего не может быть прочитано или возникнет исключение, а затем вы должно быть все.