Облазил весь интернет, толком не нашел примера как всё таки реализовать такое.
Нужно например по 500 клиентов в цикле на поток раскинуть, да и будет ли от этого какой то прирост производительности?
Выбрал Java хотя изначально думал на с++ делать.
Думаю примерно так:
Создание неблокирующего сокета, ожидание.
ssc = ServerSocketChannel.open();
sel = Selector.open();
...
while(true) {
sel.select();
...
Дождались, получаем дескриптор нового сокета, Заносим куда??? Мысль создать Map<id сокете, класс Клиент>
Далее думаю так: в цикле, в методе run, отдельного треда ожидать sel.select(); пока какой либо сокет станет активный. И пробегать по активным сокетом читая из них.
Но как тогда сделать распределение на треды по несколько сотен юзеров?
Можно конечно при добавлении нового сокета, проверять что Map размером до 500, иначе создавать новый Map, но как тогда быть? Создавать новый select для отдельных сокетов?
И ещё, отпишусь в этой же теме, читать в цикле, зная размер пакета, типа пока (длинна меньше прочитанного) читать... как во многих примерах, это как бы должно гарантировать что весь пакет прочтём, но если у юзера повис интернет, то весь поток станет... А просто читать, без цикла, нет гарантии что пакет весь придёт, или что придёт 1 пакет...
Как поступить? Я думаю, сделать переменную, в которой при каждой итерации цикла while (true) читать без цикла, и дописывать к переменной, если она меньше длинны чем ожидаемый пакет. Но если вдруг пришло 2 пакета, а я прочту только часть данных из сокета, то селект при следующей итерации покажет что сокет готов к чтению?
И вообще такой подход нормальный?
Неблокирующие сокеты собственно и заняты тем, что создают свои, отдельные потоки. Я не прав?=)
А вообще от большого количества потоков производительность падать и не должна.
Производительность неплохо теряется в тот момент, когда сокет создается(ну и убивается тоже).
Поэтому полезно для производительности сделать скажем 100 потоков и очередь коннектов(сокеты блокирующие, разумеется) и не убивать их после завершения а снова переводить в спящее состояние.
Ну если делать по клиенту на поток, то мы получим на 100 потоков 100 клиентов. А надо хотя бы несколько тысяч...
+ я не совсем понимаю, как можно блокирующему сокету, пока он в ожидании данных, отправить данные клиенту с сервера.
> полезно для производительности сделать скажем 100 потоков
Dervinar, а почему не 1 000 ? или 10 000 ?
> как можно блокирующему сокету
Easy, а зачем он блокирующий?
Вообще, ты бы начал с чего-то попроще - глядишь, и гемороя было бы и отпала бы необходимость в не нужных оптимизациях. А если бы она и возникла - проще что-то править из уже готового, чем сейчас мудрить непонятно что неясно зачем )
Dervinar
> А вообще от большого количества потоков производительность падать и не должна.
Очень даже должна. Слишком большое количество thread-ов тормозит весьма заметно.
Easy
> как можно блокирующему сокету, пока он в ожидании данных, отправить данные клиенту с сервера.
То что сокет блокирующий, не означает, что он висит в ожидании данных до посинения.
Попроще я делал) в отдельном потоке)) с блокирующими сокетами, сервер для морского боя онлайн с сотовых телефонов)
Бела в том что даже в книге сетевое программирование, самый крутой пример, это пример где в одной функции майт всё происходит, не могу найти стоящей инфы, а английский знаю плохо, понимаю смысл чаще всего, но не всё понимаю.
Easy, всё, что тебе нужно - сделать НЕ блокируемые сокеты. Это позволит в одной функции обрабатывать сотни/тысячи клиентов.
Разносить это всё по потокам имеет смысл лишь в том случае, если ты упрёшься в производительность и одного потока реально будет недостаточно для выполнения задачи, а работать это всё будет на многоядерном проце.
З.Ы. Ну и можно конечно и на блокируемых сокетах сделать в одной функции. Только, имхо, это больше гемороя, чем толку ) Не знаю уж, чем мне так не нравятся блокируемые сокеты )))
Я на блокируемых и не хотел делать, я начал делать на не блокируемых. Сейчас набросаю кодом свою идею, выложу, может что подскажите, так как до этого я в основном скрипты для тринити писал, а не готовый сервер :) А то я не могу толком объяснить задумку, и будет ли она работать)
Если не рассматривать многоядерность. (Там нужно давать по потоку на ядро).
Потоки стоит множить стоит только тогда, когда есть задачи Ввода-вывода, блокирующие поток. Да и то умеренно.
Только тогда производительность может увеличиться, т.к. пока один поток висит, в это время можно делать что-то еще.
Если на одно ядро повесить несколько активных потоков, то производительность наоборот упадет. Как минимум за счет времени на переключение контекста, которое будет происходить чаще, чем больше потоков.
Преимущество не блокируемых сокетов в том, что поток не стопорится, а а сразу читает(копирует буфер) из тех сокетов, в которых есть что почитать, а остальные пропускает, поэтому на селект достаточно одного отдельного потока.
Easy
> + я не совсем понимаю, как можно блокирующему сокету, пока он в ожидании
> данных, отправить данные клиенту с сервера.
из другого потока. Сокеты, емнип дуплексые. и ввод с выводом не связан, они как независимые каналы
вот набросал пример
http://pastebin.com/RJ1qjZi7
http://pastebin.com/QCvWRjDk
http://pastebin.com/7Lcw8dbR
http://pastebin.com/2iDQVtn3
max_client = 2 это типа 2 клинтеа на поток, чтоб потестить самому, вообще предполагается 1000+ на поток.
Вообще такая реализация слишком кривая?)
Ява слишком давит на череп ) Потому особо не смотрел. Общая суть, вроде бы, верная.
З.Ы. Лучше бы псевдокодом написал. Вообще это очень плохая практика - писать код на этапе формирования архитектуры.
ммм... а можно поподробней что значит псевдокод? Типа как в универе учили
встал
пошел к шкафу
открыл дверь
пока есть полотенца
взял полотенце
закрыл дверь
пошел назад slava_mib
> Ява слишком давит на череп )
то есть с++ лучше? или питон? или что ещё?) я просто ещё не определился на чём писать) работу с сокетами я во всех языках знаю одинаково плохо :)
Easy
ЧТо то вы с кодом намудрили
зачем несколько селектов в разных потоках? тем более с selectNow, так вообще производительность угробите.
чтение из сокета в финали - это жесть
очистки ресурсов при ошибке сокета нет.
Логгирование в вашем случае удобнее через Logger, а не этот самопал.
Easy, конечно "как в универе учили". Так просто, понятно и ничего лишнего.
Правка: только старайся псевдо-код писать на более высоком уровне. Не надо там "прочитать N байт из сокета, если не было ошибки, взывать функцию парсинга, передав ей байты". Просто пиши "читаем данные, передаём в парсер".
> > Ява слишком давит на череп )
> то есть с++ лучше? или питон? или что ещё?) я просто ещё не определился на чём писать) работу с сокетами я во всех языках знаю одинаково плохо :)
Easy, лучше на том, на чём вам удобнее и привычнее ) Я больше привык к плюсам, кто-то к питону, кто-то к бейсику... )
Тема в архиве.