Pull to refresh

Comments 26

теперь попробуйте.
спасибо за статью.
:) ну постараюсь в ближайщих статьях, осветить создание своего сокет-сервера делающего чего-нить полезное, с неблокирующим коннектором и многопоточными воркерами :)
UFO landed and left these words here
Спасибо за статью. На сколько я понял у вас только один поток отвечает за работу сокетами. Что бы увеличить их число нужна ли какая либо дополнительная синхронизация?
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);
>>А можно пример для Сета :)

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

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

и удивиться. дело в том, что в Java побитовые операции применяются только к интам и лонгам (в байткоде не предусмотрены побитовые операции для байтов), поэтому перед применением операции сдвига происходит знаковое расширение байта до инта…
Спасибо. Крутое западло, не знал.
Отличная статья! Хочу лишь заметить, что для реальных задачь все же лучше использовать Apache Mina — обертку над NIO.
Я смотрел на 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'е можно разбрасывать соединения на несколько реакторов (чтобы лучше загружать ядра)
Only those users with full accounts are able to leave comments. Log in, please.