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

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Оптимальная работа с ByteBuffer, код чтеца сообщений из сокета 
:(
    Опции темы
Platon
Дата 26.2.2008, 12:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


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

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



Здравствуйте, уважаемые. Сделал чтец сообщений из сокета.

Но беспокоит оптимальность работы с БайтБуффером:
1. Расширение буфера.
2. Возможно есть лишние операции buffer.rewind(); buffer.flip(); buffer.compact();

Код

public class SocketMessageReader implements Runnable {

    private MessageHandler handler;
    private MessageDecoder decoder;
    private InputStream stream;
    private ByteBuffer buffer;
    private static final boolean DEBUG = false;

    public SocketMessageReader(MessageHandler handler, MessageDecoder decoder, Socket socket) throws IOException {
        this.handler = handler;
        this.decoder = decoder;
        stream = socket.getInputStream();
        buffer = ByteBuffer.allocate(4096);
    }

    public void run() {
        try {
            while (!Thread.currentThread().isInterrupted()) {
                byte[] buff = new byte[4096];
                int amount = stream.read(buff);
                if (amount == -1)
                    return;
                if (buffer.remaining() < amount) {
                    int newSize = buffer.capacity();
                    int needSize = buffer.position() + amount;
                    while (newSize <= needSize)
                        newSize <<= 1;
                    if (DEBUG)
                        System.out.println("Message reader: allocating new size" + newSize);
                    ByteBuffer tmp = buffer;
                    tmp.flip();
                    buffer = ByteBuffer.allocate(newSize);
                    buffer.put(tmp.array(), 0, tmp.limit());
                }
                buffer.put(buff, 0, amount);
                boolean dataEnough = true;
                while (dataEnough) {
                    buffer.flip();
                    switch(decoder.decodable(buffer)) {
                        case MessageDecoder.OK : {
                            buffer.rewind();
                            Object o = decoder.decode(buffer);
                            if (o != null) {
                                try {
                                    handler.messageReceived(o);
                                } catch(Throwable e) {
                                    e.printStackTrace();
                                }
                            }
                            buffer.compact();
                            break;
                        }
                        case MessageDecoder.NEED_DATA : {
                            if (DEBUG)
                                System.out.println("Socket reader: NEED more data");
                            buffer.position(buffer.limit());
                            buffer.limit(buffer.capacity());
                            dataEnough = false;
                            break;
                        }
                        case MessageDecoder.NOT_OK : {
                            if (DEBUG)
                                System.out.println("Socket reader: wrong message");
                            //TODO: сложная ситуация :)
                            break;
                        }
                    } // switch(decoder.decodable(buffer))
                } // while (true)
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

PM MAIL ICQ   Вверх
COVD
Дата 26.2.2008, 17:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


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

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



Platon, тут надо сначала пояснить, как размер сообщения определяется. Он может в начале сообщения присутствовать. Тогда, прочитав первые байты сообщения (например, все сообщения имеют в первых 4 байтах свой размер - только ваша int amount может быть равна и 1) можно узнать размер и создать буфер под сообщение фиксированного размера. Второй вариант - используется маркер конца сообщения в виде спецсимвола. Этот вариант обычно работает при передаче строк.  Тогда буфер под сообщение создается динамический, например, List. А других вариантов и нет.   
PM MAIL   Вверх
Platon
Дата 28.2.2008, 12:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


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

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



Цитата(COVD @  26.2.2008,  18:12 Найти цитируемый пост)
А других вариантов и нет.

Другие варианты есть.

Код

decoder.decodable(buffer)

Говорит нам о том, может ли содержимое буфера содержать по крайней мере 1 сообщение, не важно как оно помечается, это уже внутреннее решение декодера. Единственное, этот декодер возьмет из буфера данных столько, сколько ему нужно, и не больше!

По сути дела надо поковыряться в искходниках Apache MINA там эта штука хорошо реализована. Сравнивая с текущей версией моего сокет ридера MINA гораздо быстрей читает сообщения. Проверял на передаче изображения 4Мб MINA читает практически мгновенно, мой ридер, немного думает.
PM MAIL ICQ   Вверх
COVD
Дата 28.2.2008, 17:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


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

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



Цитата

Другие варианты есть.


Есть третий вариант. Передать сообщение и закрыть соединение. Тогда концом сообщения будет выполнение условия if (amount == -1) .

Цитата

это уже внутреннее решение декодера


а декодер-то чем руководствуется? Если вы передаете сырые байты (не char или какой-то другой ограниченный набор байтов), то вариант только один - в начале сообщения должна быть информация о сообщении, из которой можно определить его длину. А раз длина сразу известна, то нет необходимости реккурентно увеличивать буфер:
Код

                 if (buffer.remaining() < amount) {
                    ....
                }


Если у вас по одному байту будет читаться (amount = 1), вы по одному байту будете буфер наращивать.

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


Эксперт
***


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

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



COVD, мы сейчас решаем не эту проблему ^_^ декодер мы не трогаем, он сам разберется, какая там структура.

Я попробовал порыться в дебрях MINA, так и запутался в дебрях... Буфер Mina работает шустрей чем мой, факт остается фактом.
Мне важно понять где тормозит мой ридер?
PM MAIL ICQ   Вверх
COVD
Дата 3.3.2008, 17:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


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

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



Цитата

Мне важно понять где тормозит мой ридер?
 

на мой взгляд, в ненужном промежуточном buffer. 

PM MAIL   Вверх
Platon
Дата 3.3.2008, 18:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


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

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



Код

byte[] buff = new byte[4096];

Вот этот имеете ввиду? а как же мне принимать данные иначе?
PM MAIL ICQ   Вверх
COVD
Дата 3.3.2008, 19:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


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

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



нет, buff - это основной, куда вы читаете из сокета. Потом вы все копируете в buffer. При этом, если не хватает места, то увеличиваете его.  На этом, наверное, и теряете. 

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

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

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


 




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


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

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