Серый крокодильчик
> зачем несколько селектов в разных потоках?
Я и спрашиваю как по другому разбить на потоки по 1000к конектов? Я сделал так, что у меня в каждом потоке селект только для сокетов из текущего потока. Например при 2к конектов, каждый поток будет содержать 1000к конектов, и 1 селек будет привязан к 1к сокетов.
Вот если юзать только один селект, то как осуществить разбитие на патоки я не представляю...
Я не говорю что так надо) я спрашиваю как надо правильно?)
Серый крокодильчик
> тем более с selectNow
по одной простой причине... если я добавляю новый сокет в поток, а селект в данный момент висит, то новый сокет не добавится пока како либо из сокетов не сработает на чтение или запись. Я думал не селектНов использовать а например селект(1000) чтоб каждую секунду например выполнялся цикл.
Серый крокодильчик
> чтение из сокета в финали - это жесть
Это вообще просто так) обработку ошибок я кликал в эклипсе по крестикам и она вставляла мне блоки try, я это пока не продумывал :)
Серый крокодильчик
> Логгирование в вашем случае удобнее через Logger, а не этот самопал.
В данном случае самопал на время теста, потом будет класс логирования, с записью в файл.
slava_mib
> Easy, конечно "как в универе учили". Так просто, понятно и ничего лишнего.
> Правка: только старайся псевдо-код писать на более высоком уровне. Не надо там
> "прочитать N байт из сокета, если не было ошибки, взывать функцию парсинга,
> передав ей байты". Просто пиши "читаем данные, передаём в парсер".
1. Создаём класс, который отвечает за распределение по потокам клиентов. 2. Открываем сокет, ждём клиента 3. Добавляем клиента в класс из 1. 4. проверяем если есть в созданных потоках пустое место то добавляем сокет иначе создаём поток и добавляем сокет. 5. добавили сокет из 4 в поток, у потока свой селект, 1 на поток. 6. в цикле ожидаем select() и проверяем, если read то выполняем чтение из сокета.
вот в 6ом беда. Цикл останавливается на select и функция add() которая добавляет в множество нового клиента не выполняется. Как только один из клиентов уже подключеных в текущем потоке срабатывает, то после этого выполняется add и уже новый клиент добавляется в поток.
Может использовать что то типа select(1000) чтобы раз в секунду поток оживал?)
Easy
> Я и спрашиваю как по другому разбить на потоки по 1000к конектов?
так у меня вопрос, зачем разбивать по 1000 коннектов на поток?
Easy
> , а селект в данный момент висит,
Selector.wakeup()
>Цикл останавливается на select
Вообще-то селект тоже бывает не блокируемый.
Серый крокодильчик
> так у меня вопрос, зачем разбивать по 1000 коннектов на поток?
Ну я как бы в самом первом посте спросил, будет ли прирост производительности? Как я понял всё таки будет.
Серый крокодильчик
> Selector.wakeup()
Спасибо! Не знал про эту функцию. Но проблема в том, откуда запускать её? я выполняю t.add() и основной поток виснет, пока второй висит :)
Easy
> Ну я как бы в самом первом посте спросил, будет ли прирост производительности?
> Как я понял всё таки будет.
нет
Easy
> Спасибо! Не знал про эту функцию. Но проблема в том, откуда запускать её? я
> выполняю t.add() и основной поток виснет, пока второй висит :)
положить сокет в буфер. сделать вейкап
в основном потоке проверить буфер и положить сокет в селектор
slava_mib
> ообще-то селект тоже бывает не блокируемый.
Ну так тогда цикл постоянно крутится, хоть и не чего не делает но крутится, точнее он проверяет есть ли кей :) А это дополнительная нагрузка... или нет?
Серый крокодильчик
> положить сокет в буфер. сделать вейкап
> в основном потоке проверить буфер и положить сокет в селектор
сокет в переменной c
делаю
t.sel.wakeup();
t.add(c);
не успевает видимо) так как цикл 1 раз проскакивает, а add не срабатывает :(
>Ну так тогда цикл постоянно крутится, хоть и не чего не делает но крутится, точнее он проверяет есть ли кей :) А это дополнительная нагрузка... или нет?
Угу. Нагрузка. Ты решил от неё избавиться?... Ведь пока в сокетах ничего нет и проц ничего не делает - ОЧЕНЬ важно экономить процессорное время, угу )))
slava_mib
> Угу. Нагрузка. Ты решил от неё избавиться?... Ведь пока в сокетах ничего нет и
> проц ничего не делает - ОЧЕНЬ важно экономить процессорное время, угу )))
ну как бы не совсем проц не чего не делает.
Выполняется каждый раз вот это
Iterator<SelectionKey> it = sel.selectedKeys().iterator();
while(it.hasNext()) {цикл вайл не начнётся, так как селектКей пуст, но всё таки что то проверяется...
Или это не нагрузит?
slava_mib
> Ведь пока в сокетах ничего нет
верно
slava_mib
> проц ничего не делает
неверно
он в это время может быть занят другими задачами, в том числе обработкой прошлых пакетов.
крутить поток в пустую плохая практика, если поток ничего не делает - он должен спать. Иначе он будет давать
туже нагрузку что и работающий.
Easy
> не успевает видимо) так как цикл 1 раз проскакивает, а add не срабатывает :(
t.putBuffer(c);
t.sel.wakeup();
а уже внутри run
if(!buffer.isEmpty()){
add(buffer.poll());
}
> крутить поток в пустую плохая практика, если поток ничего не делает - он должен
> спать. Иначе он будет давать
> туже нагрузку что и работающий.
Серый крокодильчик, для этого есть sleep )
Вот так изменил, работает с блокирующим сокетом) Спасибо!
public void add(SocketChannel c) throws IOException {
boolean add = false;
LoginServer.pDebug("added new sock");
for (ClientThread t: threads) {
if (t.Clients().size() < max_clients) {
t.buf.add(c);
t.sel.wakeup();
add = true;
break;
}
}
if (!add) {
ClientThread t = new ClientThread();
t.buf.add(c);
t.sel.wakeup();
threads.add(t);
t.start();
}
}public Set<SocketChannel> buf = new HashSet<SocketChannel>();
public void run() {
while(true) {
try {
sel.select();
} catch (IOException e) {
LoginServer.pDebug("ClientThread -> run -> select");
e.printStackTrace();
}
if (!buf.isEmpty()) {
for (SocketChannel newSc: buf)
try {
add(newSc);
} catch (ClosedChannelException e) {
e.printStackTrace();
}
}
Iterator<SelectionKey> it = sel.selectedKeys().iterator();
while(it.hasNext()) {
SelectionKey key = it.next();
it.remove();
if (key.isValid()) {
LoginServer.pDebug("key valid");
if (key.isReadable()) {
try {
read(key);
} catch (IOException e) {
LoginServer.pDebug("ClientThread -> run -> read : " + key.channel());
cs.remove(key.channel());
if (key.channel() != null)
try {
key.channel().close();
} catch (IOException e1) {
LoginServer.pDebug("ClientThread -> run -> read/close");
e1.printStackTrace();
}
e.printStackTrace();
}
}
}
}
}
}Ну так вообще такая реализация имеет место жить?) Или всё таки лучше в один поток всех клиентов запихивать?
> для этого есть sleep )
ну я как бы и намекал на это select(1000) то же самое что selectNow(); sleep(1000);
slava_mib
> Серый крокодильчик, для этого есть sleep )
слип - слипом, селект - селектом. :)
Что ж это творится такое. Набежали велосипедисты. Сажи велосипедистам ;)
В порядке обучения пусть человек поюзает какуюто сложную (вроде ASIO для С++ только для явы) или простую либу (вроде Win32 IOCP или там libev для линуха) для асинхронки.
Поюзает, разберётся как все работает, пусть потом лезет в сокеты, флаги, селекты и прочий хлам.
Тема в архиве.