Модераторы: LSD, AntonSaburov

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Как лучше раздать картинку по сокетам? интересует структура... 
:(
    Опции темы
Proger10
Дата 19.4.2009, 18:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 312
Регистрация: 16.12.2008

Репутация: нет
Всего: нет



Подскажите пожалуйста, как бы раздать картинку по другим программам?

Я предварительно пошлю им команду через сокеты (сервер NIO (каждому клиенту выделяю тред, где и обслуживаю клиента) ).
А вот далее чего бы придумать? Я пытался прямо на этом порту передавать всем, но возникают какие-то проблемы типа - сервер всё отправил, а клиент застрял в цикле на получении (прямо на первой строчки) и т.д. и т.п.
Не хотелось бы столкнуться с этим ещё раз. Хочу написать чего-то новое, что исключит эти проблемы. 

Нельзя ли как-то сделать так, чтобы клиенты подконнектились ко мне и слили к себе эту картинку? Но только какая при этом должна быть архитектура программы?

Можно конечно выделить отдельный порт под передачу файла.. да какая разница - и тот застрянет smile
PM MAIL   Вверх
ivg
Дата 19.4.2009, 19:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Autonomous R&D
**


Профиль
Группа: Участник
Сообщений: 686
Регистрация: 8.2.2006
Где: Екатеринбург

Репутация: 3
Всего: 81



Цитата(Proger10 @  19.4.2009,  20:26 Найти цитируемый пост)
а клиент застрял в цикле на получении (прямо на первой строчки)

В этом скорее всего проблема. 1. Картинки "обычно" smile не передаются построчно. 2. Кроме того, конец последовательности байт картинки должен быть каким-то образом обозначен.
Цитата(Proger10 @  19.4.2009,  20:26 Найти цитируемый пост)
Нельзя ли как-то сделать так, чтобы клиенты подконнектились ко мне и слили к себе эту картинку? Но только какая при этом должна быть архитектура программы?
 Embedded HTTP Server, например. Если хочется покопаться - в составе JDK есть пример реализации HTTP(S) сервера на NIO (/sample/nio).


Это сообщение отредактировал(а) ivg - 19.4.2009, 19:32
PM MAIL   Вверх
Proger10
Дата 19.4.2009, 20:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 312
Регистрация: 16.12.2008

Репутация: нет
Всего: нет



Не, читаю я ессно не построчно. Предварительно шлю размер файла и читаю стрим сокета на клиенте (read) до тех пор пока число байтов общего размера не достигнет. Но почему-то после первого read'а клиент виснет.. (видимо не получив почему-то.. данных. А сервер в это время весь цикл отработал - типа уже послал ему файл, справился smile ).
Вот таким образом я шлю картинки:
http://forum.vingrad.ru/forum/topic-252263.html
(только не зипованные)

Причём иногда оно работает, а иногда нет. Как понять в чём проблема - не пойму. Поэтому наверное проще использовать другой сервер, чем искать дыры в этом smile
PM MAIL   Вверх
ivg
Дата 19.4.2009, 21:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Autonomous R&D
**


Профиль
Группа: Участник
Сообщений: 686
Регистрация: 8.2.2006
Где: Екатеринбург

Репутация: 3
Всего: 81



Полный код сервера, ну и клиента тоже покажите. Судя по этому
Цитата(Proger10 @  19.4.2009,  22:10 Найти цитируемый пост)
Предварительно шлю размер файла и читаю стрим сокета на клиенте (read) до тех пор пока число байтов общего размера не достигнет.
 они явно отличаются от того, что приведено в той теме.

PM MAIL   Вверх
Platon
Дата 20.4.2009, 10:50 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1801
Регистрация: 25.4.2006

Репутация: 3
Всего: 40



Если вы плотно работаете с сетью, но еще не чувствуете уверенности под ногами, рекомендую посмотреть блог о сетевых методах и технологиях, который ведет COVD.

По поводу Embedded HTTP Server есть FAQ, мною оформленная.
PM MAIL ICQ   Вверх
Proger10
Дата 20.4.2009, 10:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 312
Регистрация: 16.12.2008

Репутация: нет
Всего: нет



0. Открываю сокет и коннекчусь (всё ок!)
1. Посылаю через сокет bufferedWriter.write( line + "\n" ); информацию о размере файла с сервера клиенту (приходит то, что надо)
2. Посылка файла с сервера на клиент:
Код
public synchronized void sendFile( String file ) { 

    OutputStream os = null;
    FileInputStream fis = null;

    try{

        fis = new FileInputStream( file );

    } catch ( FileNotFoundException e1 ) {
    }

    System.out.println( "Start to sending file: " + file );
    try {

        os = s.getOutputStream();

        byte[] buffer = new byte[ 8192 ];
        int count;

        while ( ( count = fis.read( buffer ) ) > 0 ) {

            os.write( buffer, 0, count );

        }

        fis.close();
        os.flush();

        System.out.println( "file sent!" );

    } catch ( IOException e2 ) {
    }

}

3. Приём:
Код
try {

    int sChunk = 8192;

    InputStream is = socket.getInputStream();
    FileOutputStream out = new FileOutputStream( "file.png" );

    byte[] buffer = new byte[ sChunk ];
    int length;

    int totalFileSize = Integer.parseInt( fileCmd[ 3 ] );

    System.out.println( "totalFileSize = " + totalFileSize ); // totalFileSize - пришёдший предварительно размер файла

    int currFileSize = 0;
    while ( currFileSize < totalFileSize ) {

        System.out.println( "got a portion" );

        length = is.read( buffer, 0, sChunk );

        System.out.println( "read" );

        out.write( buffer, 0, length );
        currFileSize += length;

    }

    out.close();

} catch ( IOException e ) {
}


Сервер по такому принципу: http://javatalks.ru/sutra33322.php#33322
Ну и клиент как клиент.. smile

Вот так и работает.. точнее не очень smile
PM MAIL   Вверх
ivg
Дата 20.4.2009, 12:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Autonomous R&D
**


Профиль
Группа: Участник
Сообщений: 686
Регистрация: 8.2.2006
Где: Екатеринбург

Репутация: 3
Всего: 81



Исправления к клиенту
Код

15:    int remains = totalFileSize;
16:    while (remains > 0) {
17:
18:        System.out.println("got a portion");
19:        
20:        length = is.read(buffer, 0, Math.min(sChunk, remains));
21:        if (length < 0) break;
22:        System.out.println("read");
23:
24:        out.write(buffer, 0, length);
25:        remains -= length;
26:
27:    }

Цитата из JavaDoc для InputStream#read(byte[] b, int off, int len)
Цитата
The default implementation of this method blocks until the requested amount of input data len has been read, end of file is detected, or an exception is thrown.

Ну а ни выходной поток, ни сокет на сервере вы не закрываете.
PS: Подавление исключений - дурной тон. smile 

Это сообщение отредактировал(а) ivg - 21.4.2009, 06:26
PM MAIL   Вверх
Proger10
Дата 20.4.2009, 14:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 312
Регистрация: 16.12.2008

Репутация: нет
Всего: нет



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

Добавлено через 1 минуту и 5 секунд
Интересное исправление кода клиента! Спасибо!
PM MAIL   Вверх
Proger10
Дата 21.4.2009, 11:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 312
Регистрация: 16.12.2008

Репутация: нет
Всего: нет



Кстати, по поводу:
Цитата
Цитата из JavaDoc для InputStream#read(byte[] b, int off, int len)Цитата
The default implementation of this method blocks until the requested amount of input data len has been read, end of file is detected, or an exception is thrown.

а когда этот экзепшн будет выброшен в случае чего? read ведь блочится намертво и хоть ты сколько жди походу..
Можно ли как-то поставить timeout на получение порции данных в read?
Тогда если бы он не получал данные, то не вешал бы прогу (ну или хотя бы на 20 секунд её вешал) - оно и так у меня в отдельном потоке, так что цикл не вешает программу, но неплохо бы, чтобы этот цикл всё-таки оно обходило бы как-то (после него тоже инструкции к выполнению есть smile ).
PM MAIL   Вверх
ivg
Дата 22.4.2009, 08:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Autonomous R&D
**


Профиль
Группа: Участник
Сообщений: 686
Регистрация: 8.2.2006
Где: Екатеринбург

Репутация: 3
Всего: 81



1. NIO неблокирующие операции.
2. java.net.Socket#setSoTimeout(int)
PM MAIL   Вверх
Proger10
Дата 27.4.2009, 22:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 312
Регистрация: 16.12.2008

Репутация: нет
Всего: нет



Кстати.. А я вот подумал тут.. А нафига я вообще делаю именно такой вызов read'a у клиента.. можно ведь сделать и так:
Код
length = is.read( buffer );

и действительно всё сработало! smile
PM MAIL   Вверх
Platon
Дата 28.4.2009, 11:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1801
Регистрация: 25.4.2006

Репутация: 3
Всего: 40



Proger10, я бы не стал раньше времени ликовать. Сработало хорошо на локальной машине с маленьким файлом, вы большой файлик скачать. У вас этот метод прочитает только первую порцию данных.
PM MAIL ICQ   Вверх
Proger10
Дата 30.4.2009, 15:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 312
Регистрация: 16.12.2008

Репутация: нет
Всего: нет



Platon, а почему? В чём проблема?

Большой, это насколько большой?

Я вообще думаю, что лучше отдельный сокет открывать специально для отправки файлов.. Может присоветуете каким образом в таком случае лучше пересылать файл через сокет?

Добавлено через 1 минуту и 50 секунд
Предполагаю вот такой метод передачи использовать (первое сообщение)
http://forum.vingrad.ru/forum/topic-252355.html
PM MAIL   Вверх
Platon
Дата 30.4.2009, 20:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1801
Регистрация: 25.4.2006

Репутация: 3
Всего: 40



Proger10, внимательней:
Цитата(Platon @  28.4.2009,  12:49 Найти цитируемый пост)
У вас этот метод прочитает только первую порцию данных. 


Тест подтверждает, что считываются только данные, которые уже получены в буффер сокета.
Код

byte[] arrr = new byte[16000000];
        InputStream s = new URL("http://forum.vingrad.ru/forum/java-forum.html").openStream();
        int am = s.read(arrr);
        System.out.println(am);

Читал локальный файл, программа считывает 16*10^6 байтов в легкую за раз.

Это сообщение отредактировал(а) Platon - 30.4.2009, 20:50
PM MAIL ICQ   Вверх
COVD
Дата 2.5.2009, 07:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1655
Регистрация: 26.7.2005

Репутация: 11
Всего: 43



Цитата

Читал локальный файл, программа считывает 16*10^6 байтов в легкую за раз.

Кстати, вот решение в ситуации, когда размер данных точно не известен - удобно их сначала в ByteArrayOutputStream записывать, а потом уже оттуда извлекать в виде byte[] - http://developers.sun.com/mobility/midp/questions/calcbyte/

PM MAIL   Вверх
Proger10
Дата 12.5.2009, 22:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 312
Регистрация: 16.12.2008

Репутация: нет
Всего: нет



COVD, так там изначально получают длину данных или нет?
Код
int length = connection.getLength();


А как же я её получу, это ж поток... Который читается до тех пор пока другая сторона не закроет сокет..
PM MAIL   Вверх
COVD
Дата 12.5.2009, 22:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1655
Регистрация: 26.7.2005

Репутация: 11
Всего: 43



Цитата

А как же я её получу, это ж поток... 

В политбюро не дураки сидят - ночью полетите (шутка). Там предлагается читать из файла (или соединения) в другой, временный поток, который по сути выполняет роль безразмерного буфера ( как ArrayList, например). После того, как чтение завершено, и, следовательно, фактическая длина данных известна, из этого временного буферного потока данные копируются в byte[], т.е. массив создается, когда уже известен необходимый размер. Это просто удобное решение, потому что не надо заранее создавать массив большого размера и увеличивать его длину при необходимости. Этим временный поток занимается.  

Это сообщение отредактировал(а) COVD - 12.5.2009, 22:44
PM MAIL   Вверх
Proger10
Дата 13.5.2009, 00:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 312
Регистрация: 16.12.2008

Репутация: нет
Всего: нет



Мы вот об этом коде?
Код
HttpConnection connection = (HttpConnection)
Connector.open("http://www.test.com/servlet/readData");

InputStream inputStream = connection.openDataInputStream();

int length = connection.getLength();
byte[] byteArray;
if (length == -1) {
// Reading from an HTTP 1.0 server or a chunked HTTP 1.1
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int c ;
while (true) {
c = inputStream.read();
if (c == -1)
break;
baos.write(c);
}
byteArray = baos.getBytes();
} else {
// Reading a Content-Length labeled payload
byteArray = new byte[length];
inputStream.readFully(byteArray);
}


А.. ну насколько я понял тут length вообще не нужен?
Идея этого кода в том, чтобы читать очередной байт через: inputStream.read() и по мере каждого байта подсчитать длину?
Чего-то походу здесь уже какая-то ошибка.. инае зачем нам повторно расширять массив и перекачивать в него данные, если мы уже при подсчёте получаем эти байты.. smile
PM MAIL   Вверх
Proger10
Дата 13.5.2009, 00:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 312
Регистрация: 16.12.2008

Репутация: нет
Всего: нет



Кстати! А что плохого вот в таком методе приёма?

Код
int c = -1;
while( ( c = socketInputStream.read() ) != -1 ) {
    fileOutputStream.write( c );
}

Потихоньку тянем файл.. Таким образом и большой вытащить получится наверное..? smile
PM MAIL   Вверх
COVD
Дата 13.5.2009, 03:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1655
Регистрация: 26.7.2005

Репутация: 11
Всего: 43



Цитата

Мы вот об этом коде?


об этом, вестимо

Цитата

Идея этого кода в том, чтобы читать очередной байт через: inputStream.read() и по мере каждого байта подсчитать длину?


читаем байт и пихаем его в ByteArrayOutputStream. Мы длину сами не подсчитываем. ByteArrayOutputStream обо всем заботится. 

Цитата

Чего-то походу здесь уже какая-то ошибка.. инае зачем нам повторно расширять массив и перекачивать в него данные, если мы уже при подсчёте получаем эти байты.. 


Смысл той заметки в том, что удобно пользоваться ByteArrayOutputStream , который всю рутинную работу сделает. Точно также, как, например, ArrayList. 

Цитата

Кстати! А что плохого вот в таком методе приёма?


Наоборот, это самый лучший вариант. Для перевалочного пункта. Например, сервлет. Он откуда-то читает (БД, файл,другой компьютер) и тут же отправляет клиенту (браузеру) не буферизуя и, следовательно, не расходуя памяти. Идеальный посредник.  А вот на клиенте, т.е. у конечного потребителя, буферизация бывает неизбежна, если данные имеют смысл только при полной загрузке. Например, jpeg. Пока картинка полностью не загрузилась, ее невозможно употребить по назначению.


Это сообщение отредактировал(а) COVD - 13.5.2009, 03:18
PM MAIL   Вверх
Platon
Дата 13.5.2009, 08:53 (ссылка) |    (голосов:2) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1801
Регистрация: 25.4.2006

Репутация: 3
Всего: 40



Цитата(COVD @  13.5.2009,  04:09 Найти цитируемый пост)
ее невозможно употребить по назначению.

Однако браузеры справляются smile
PM MAIL ICQ   Вверх
COVD
Дата 13.5.2009, 15:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1655
Регистрация: 26.7.2005

Репутация: 11
Всего: 43



Спасибо за поправку. Рад за браузеры smile . Ну, тогда не jpeg, а другой тип данных. Тут ведь не только вопрос умения клиента "потреблять" загружаемые данные "на лету", не дожидаясь конца загрузки. Что будет, если данные загрузятся наполовину и произойдет разрыв соединения? Клиент может попытаться повторить попытку. Если загружаемые данные накапливались в буфере, то буфер просто очищается и все начинается сначала. А что будет, если данные уже пошли в дело, породили какие-то действия, новые данные или сообщения? Откатывать назад последствия неполной обработки данных в этом случае может оказаться намного сложнее. Тут мы к понятию "транзакция" подбираемся. Хотя для клиентов это не типично, а для тонких и вообще, наверное, не применимо.

Это сообщение отредактировал(а) COVD - 15.5.2009, 12:39
PM MAIL   Вверх
Страницы: (2) [Все] 1 2 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Java"
LSD   AntonSaburov
powerOn   tux
  • Прежде, чем задать вопрос, прочтите это!
  • Книги по Java собираются здесь.
  • Документация и ресурсы по Java находятся здесь.
  • Используйте теги [code=java][/code] для подсветки кода. Используйтe чекбокс "транслит", если у Вас нет русских шрифтов.
  • Помечайте свой вопрос как решённый, если на него получен ответ. Ссылка "Пометить как решённый" находится над первым постом.
  • Действия модераторов можно обсудить здесь.
  • FAQ раздела лежит здесь.

Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, tux.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Java: Работа с сетью | Следующая тема »


 




[ Время генерации скрипта: 0.1094 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.