Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
Форум программистов > Java: Работа с сетью > Как лучше раздать картинку по сокетам? |
Автор: Proger10 19.4.2009, 18:26 |
Подскажите пожалуйста, как бы раздать картинку по другим программам? Я предварительно пошлю им команду через сокеты (сервер NIO (каждому клиенту выделяю тред, где и обслуживаю клиента) ). А вот далее чего бы придумать? Я пытался прямо на этом порту передавать всем, но возникают какие-то проблемы типа - сервер всё отправил, а клиент застрял в цикле на получении (прямо на первой строчки) и т.д. и т.п. Не хотелось бы столкнуться с этим ещё раз. Хочу написать чего-то новое, что исключит эти проблемы. Нельзя ли как-то сделать так, чтобы клиенты подконнектились ко мне и слили к себе эту картинку? Но только какая при этом должна быть архитектура программы? Можно конечно выделить отдельный порт под передачу файла.. да какая разница - и тот застрянет ![]() |
Автор: Proger10 19.4.2009, 20:10 |
Не, читаю я ессно не построчно. Предварительно шлю размер файла и читаю стрим сокета на клиенте (read) до тех пор пока число байтов общего размера не достигнет. Но почему-то после первого read'а клиент виснет.. (видимо не получив почему-то.. данных. А сервер в это время весь цикл отработал - типа уже послал ему файл, справился ![]() Вот таким образом я шлю картинки: http://forum.vingrad.ru/forum/topic-252263.html (только не зипованные) Причём иногда оно работает, а иногда нет. Как понять в чём проблема - не пойму. Поэтому наверное проще использовать другой сервер, чем искать дыры в этом ![]() |
Автор: ivg 19.4.2009, 21:24 | ||
Полный код сервера, ну и клиента тоже покажите. Судя по этому
|
Автор: Platon 20.4.2009, 10:50 |
Если вы плотно работаете с сетью, но еще не чувствуете уверенности под ногами, рекомендую посмотреть http://vingrad.ru/blogs/COVD/, который ведет COVD. По поводу http://forum.vingrad.ru/faq/topic-227026.html есть FAQ, мною оформленная. |
Автор: Proger10 20.4.2009, 10:52 | ||||
0. Открываю сокет и коннекчусь (всё ок!) 1. Посылаю через сокет bufferedWriter.write( line + "\n" ); информацию о размере файла с сервера клиенту (приходит то, что надо) 2. Посылка файла с сервера на клиент:
3. Приём:
Сервер по такому принципу: http://javatalks.ru/sutra33322.php#33322 Ну и клиент как клиент.. ![]() Вот так и работает.. точнее не очень ![]() |
Автор: ivg 20.4.2009, 12:15 | ||||
Исправления к клиенту
Цитата из JavaDoc для InputStream#read(byte[] b, int off, int len)
Ну а ни выходной поток, ни сокет на сервере вы не закрываете. PS: Подавление исключений - дурной тон. ![]() |
Автор: Proger10 20.4.2009, 14:37 |
Ну выходной поток я не могу закрыть, потому как это приведёт к закрытию сокета, а мне в общем-то ещё работать через него далее... ![]() Добавлено через 1 минуту и 5 секунд Интересное исправление кода клиента! Спасибо! |
Автор: Proger10 21.4.2009, 11:55 | ||
Кстати, по поводу:
а когда этот экзепшн будет выброшен в случае чего? read ведь блочится намертво и хоть ты сколько жди походу.. Можно ли как-то поставить timeout на получение порции данных в read? Тогда если бы он не получал данные, то не вешал бы прогу (ну или хотя бы на 20 секунд её вешал) - оно и так у меня в отдельном потоке, так что цикл не вешает программу, но неплохо бы, чтобы этот цикл всё-таки оно обходило бы как-то (после него тоже инструкции к выполнению есть ![]() |
Автор: ivg 22.4.2009, 08:22 |
1. NIO неблокирующие операции. 2. http://java.sun.com/javase/6/docs/api/java/net/Socket.html#setSoTimeout(int) |
Автор: Proger10 27.4.2009, 22:52 | ||
Кстати.. А я вот подумал тут.. А нафига я вообще делаю именно такой вызов read'a у клиента.. можно ведь сделать и так:
и действительно всё сработало! ![]() |
Автор: Platon 28.4.2009, 11:49 |
Proger10, я бы не стал раньше времени ликовать. Сработало хорошо на локальной машине с маленьким файлом, вы большой файлик скачать. У вас этот метод прочитает только первую порцию данных. |
Автор: Proger10 30.4.2009, 15:34 |
Platon, а почему? В чём проблема? Большой, это насколько большой? Я вообще думаю, что лучше отдельный сокет открывать специально для отправки файлов.. Может присоветуете каким образом в таком случае лучше пересылать файл через сокет? Добавлено через 1 минуту и 50 секунд Предполагаю вот такой метод передачи использовать (первое сообщение) http://forum.vingrad.ru/forum/topic-252355.html |
Автор: Platon 30.4.2009, 20:48 | ||
Proger10, внимательней: Тест подтверждает, что считываются только данные, которые уже получены в буффер сокета.
Читал локальный файл, программа считывает 16*10^6 байтов в легкую за раз. |
Автор: COVD 2.5.2009, 07:37 | ||
Кстати, вот решение в ситуации, когда размер данных точно не известен - удобно их сначала в ByteArrayOutputStream записывать, а потом уже оттуда извлекать в виде byte[] - http://developers.sun.com/mobility/midp/questions/calcbyte/ |
Автор: Proger10 12.5.2009, 22:20 | ||
COVD, так там изначально получают длину данных или нет?
А как же я её получу, это ж поток... Который читается до тех пор пока другая сторона не закроет сокет.. |
Автор: COVD 12.5.2009, 22:37 | ||
В политбюро не дураки сидят - ночью полетите (шутка). Там предлагается читать из файла (или соединения) в другой, временный поток, который по сути выполняет роль безразмерного буфера ( как ArrayList, например). После того, как чтение завершено, и, следовательно, фактическая длина данных известна, из этого временного буферного потока данные копируются в byte[], т.е. массив создается, когда уже известен необходимый размер. Это просто удобное решение, потому что не надо заранее создавать массив большого размера и увеличивать его длину при необходимости. Этим временный поток занимается. |
Автор: Proger10 13.5.2009, 00:26 | ||
Мы вот об этом коде?
А.. ну насколько я понял тут length вообще не нужен? Идея этого кода в том, чтобы читать очередной байт через: inputStream.read() и по мере каждого байта подсчитать длину? Чего-то походу здесь уже какая-то ошибка.. инае зачем нам повторно расширять массив и перекачивать в него данные, если мы уже при подсчёте получаем эти байты.. ![]() |
Автор: Proger10 13.5.2009, 00:57 | ||
Кстати! А что плохого вот в таком методе приёма?
Потихоньку тянем файл.. Таким образом и большой вытащить получится наверное..? ![]() |
Автор: COVD 13.5.2009, 03:09 | ||||||||
об этом, вестимо
читаем байт и пихаем его в ByteArrayOutputStream. Мы длину сами не подсчитываем. ByteArrayOutputStream обо всем заботится.
Смысл той заметки в том, что удобно пользоваться ByteArrayOutputStream , который всю рутинную работу сделает. Точно также, как, например, ArrayList.
Наоборот, это самый лучший вариант. Для перевалочного пункта. Например, сервлет. Он откуда-то читает (БД, файл,другой компьютер) и тут же отправляет клиенту (браузеру) не буферизуя и, следовательно, не расходуя памяти. Идеальный посредник. А вот на клиенте, т.е. у конечного потребителя, буферизация бывает неизбежна, если данные имеют смысл только при полной загрузке. Например, jpeg. Пока картинка полностью не загрузилась, ее невозможно употребить по назначению. |
Автор: Platon 13.5.2009, 08:53 |
Однако браузеры справляются ![]() |
Автор: COVD 13.5.2009, 15:18 |
Спасибо за поправку. Рад за браузеры ![]() |