Как стать автором
Обновить

Комментарии 26

Была бы карма :) запостил бы в Java
теперь попробуйте.
спасибо за статью.
:) ну постараюсь в ближайщих статьях, осветить создание своего сокет-сервера делающего чего-нить полезное, с неблокирующим коннектором и многопоточными воркерами :)
НЛО прилетело и опубликовало эту надпись здесь
Спасибо за статью. На сколько я понял у вас только один поток отвечает за работу сокетами. Что бы увеличить их число нужна ли какая либо дополнительная синхронизация?
Selector и должен работать в одном потоке, ключам даже interestOps поменять из другого нельзя.
Пример использования нескольких потоков, планируется в следующем посте, обычно использую блокирующую очередь и N воркеров для этой задачи.

Если предложите что полезного бы сервер мог делать, сделаю пример на базе этих полезных действий.
Ну на пример кеш, со стандартным набором команд: положить, взять, удалить, для простого типа String. На политики очистки кеша можно не заморачиваться.
Ну тогда хранилище с простым протоколом для хранения текстовых данных,
данные будут складываться например в lucene с возможность полнотекстового поиска.

Команда на положить:

>key \n
data data data\n
data data data\n
data 123 data data\n
\n

команда на поискать.

?123 data\n

и дальше соответственно ответ.

Поисковые задачи будут соответственно распаралелены.

Для примера достаточно складывать просто в ConcurrentMap, и доставать только по ключу. Если понадобиться можно легко будет перейти на другое хранилище.
Вообще для операции проксирования, одного потока вполне достаточно, т.к. все методы неблокируюшие, процессор тратится только на работу с доступными данными, размер которых на одной итерации ограничен размером сокет буфера или байтбуфера в который происходит чтение. Скорее всего такой сервер сможет достаточно безпроблемно прокачать 100мБ канал.

Раз у нас Java >= 1.5, то вот это безобразие…

Iterator <SelectionKey> iterator = selector.selectedKeys().iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
iterator.remove();

}

… наверно можно в одну строчку переписать?
for(SelectionKey key: selector.selectedKeys()) {...}

// -----------8K-------------

Byte[] ar;
int p = (((0xFF & ar[2]) << 8) + (0xFF & ar[3]));

«О амперсанд, безсмысленный и беспощадный!»
Разве в Byte может быть что-то болшее чем 0xFF?

int p = (ar[2] << 8) | ar[3];

// -----------8K-------------

Attachment peerAttachemtn // — опечатка

// -----------8K-------------

p.s. вообще такие вещи проще писать на чистом Си с использованием libevent.
>Iterator iterator = selector.selectedKeys().iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
iterator.remove();

Нельзя, при одновременном проходе по коллеции и удалении элементов из нее цикл foreach вызовет ConcurrentModificationException (http://www.java2s.com/Code/Java/Collections-Data-Structure/IterateaCollectionandremoveanitemExceptionwrongversion.htm)
Для этих целей и нужен iterator
Нельзя, при одновременном проходе по коллеции и удалении элементов из нее цикл foreach вызовет ConcurrentModificationException ну для этих целей ещё можно проходится по коллекции в обратном направлении. Помогает
Блин, только проснулся) Сделаем по — другому…

>>Нельзя, при одновременном проходе по коллеции и удалении элементов из нее цикл foreach вызовет ConcurrentModificationException
Ну, для этих целей ещё можно проходится по коллекции в обратном направлении. Помогает
А можно пример для Сета :)
for (int i = collection.size() — 1; i > 0; i--)
collection.remove(i);
java.sun.com/javase/6/docs/api/java/util/Set.html
не вижу remove по индексу, в сете вообще нету индексов :) и правда ещё не проснулся :)
>>А можно пример для Сета :)

Омг)))) Я понял о чем вы говорите))))) Так, я пошёл делать себе кофе )
амперсанд тут по делу… рекомендую выполнить

byte x = (byte)0xFF;
byte y = (byte)0xFF;
System.out.println (((0xFF & x) << 8) + (0xFF & y));
System.out.println ((x << 8) | y);

и удивиться. дело в том, что в Java побитовые операции применяются только к интам и лонгам (в байткоде не предусмотрены побитовые операции для байтов), поэтому перед применением операции сдвига происходит знаковое расширение байта до инта…
Спасибо. Крутое западло, не знал.
НЛО прилетело и опубликовало эту надпись здесь
Я смотрел на MINA, на Grizzly и Netty. Остановился в конце-концов на Netty.
Зачем Runnable? Если нужен все таки поток, то вы не через run() start-уйте ;-)
Надеюсь у вас появится возможность сделать сравнение linux kern2.6 vs kern2.4 vs xp.
accept лучше делать в отдельном треде классическим блокирующим способом, lattency от этого сильно выигрывает
Не поспоришь, конечно же аццептить будет намного быстрее, только это может вызвать усложнение кода при регистрации сокета в селекторе, скорее всего это операция возможна только в том же треде, где происходит select(), по крайней мере с установкой interstOps всё именно так и приходится кидать ChangeRequest в очередь на выполнение и кричать selector.wakeUp(), т.е. после accept скорее всего надо будет сделать тоже самое, только RegisterRequest.
да, но выигрышь того стоит. Плюс еще в acceptor'е можно разбрасывать соединения на несколько реакторов (чтобы лучше загружать ядра)
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории