|
|
|
java nio server + многопоточность
|
|||
|---|---|---|---|
|
#18+
Всем привет. Я пишу простой TCP сервер, основанный на технологии NIO. О возможных советах по использованию готовых решений, моя цитата из другой темы, там я о UDP спрашивал и вопрос был вообще о другом - "Почитал о MINA, Netty, но это показалось мне overkill-ом, так как мой сервак ничего не пишет/не отправляет, работает только как приемник. Ну и самое главное, захотелось для опыта пощупать технологию руками." Наверное, многие сталкивались с таким примером в сети: Код: java 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. этот пример работает. есть несколько вопросов: 1) во многих примерах проверка key.isConnectable() отсутствует, а где-то пишут, что это необходимо. Почитал об этом, говорят, что это нужно для правильного закрытия пришедшего соединения - не понял, надо ли это или нет? 2) вышеприведенный код в принципе работает. Но при больших нагрузках рекомендуют прикрутить многопоточность. Я правильно понимаю, что надо создать ThreadPool и вместо текущего readMessage(key) делать что-то вроде Код: java 1. , то есть осуществлять считывание инфы и ее обработку в отдельном потоке? Какие есть рекомендации, каие возможны подводные камни, какие объекты скорее всего придется синхронизировать? Можно ли сюда маленький, лаконичный псевдокод, дополняющий вышеприведенный псевдокод многопоточностью? 3) как логически корректно закрывать сокет? другими словами, когда делать key.channel.close()? ведь TCP соединение это как сессия, можно даже не разрывать его и пользоваться им, если сообщения от клиента поступают постоянно. Или лучше даже при постоянном приеме сообщений каждый раз разрывать соединение после считки сообщения? а если я не хочу разрывать соединение, значит обрыв соединения производим только при Exception-ах, правильно? И еще, дополнение ко второму пункту о синхронизации - если я не разрываю соединения, значит при приеме сообщений от одних и тех же клиентов возможна ситуация, когда в одном потоке обрабатываю selectionKey и пока его обрабатываю, от этого же клиента приходит сообщение - а ведь selectionKey.channel будет тем же, мы же не разрываем соединения, помните? А это значит, я в двух разных потоках обрабатываю одновременно один и тот же объект, я прав? 4) еще очень часто в инете видел рекомендации по поводу реализации считки сообщений - говорят, что сообщения могут приходит хаотично, например начало сообщения, потом только его конец и я должен уметь распознавать цельные сообщения либо по наличию символа окончания строки, либо дополнять сообщение префиксом - количеством байт в сообщении и ждать именно столько байтов. А если я выделяю достаточно большой ByteBuffer могу ли я забить на такую хитрую обработку и считать то, что я считал из канала методом selectedChannel.read(someByteBuffer) цельным сообщением? Возможны ли ситуации, когда по каким-то причинам одно цельное сообщение теоретически помещающееся в буфер дробится на несколько мелких сообщений? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 29.03.2013, 18:20:10 |
|
||
|
java nio server + многопоточность
|
|||
|---|---|---|---|
|
#18+
BaurzhanS, 1) В доке написано авторTests whether this key's channel has either finished, or failed to finish, its socket-connection operation.. То есть, если вы распоточили обработку, то такую проверку нужно выполнять. 2) Да, верно. Также, в зависимости от задачи, возможно вам стоит поставить сервер на NIO.2 - асинхронное event driven IO. Там можно завязать обработку на callback'и, что на мой взгляд довольно удобно. По синхронизации особенностей никаких не припомню. Вроде с селекшн кеями заморочки были. В принципе, после получения SelectionKey можно начинать распараллеливать задачи (чтение, установка соединения и т.д.). ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 29.03.2013, 20:34:29 |
|
||
|
java nio server + многопоточность
|
|||
|---|---|---|---|
|
#18+
DoSOfRedRiver, 3) Не вижу в этом смысла - куча проблем, минимум профита. Ну опять же от задачи зависит. 4) С такого рода "фрагментацией" не сталкивался. А размер сообщения всё-таки лучше передавать, в заголовке, например. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 29.03.2013, 20:53:06 |
|
||
|
java nio server + многопоточность
|
|||
|---|---|---|---|
|
#18+
BaurzhanSВозможны ли ситуации, когда по каким-то причинам одно цельное сообщение теоретически помещающееся в буфер дробится на несколько мелких сообщений?Поленился вычитывать входной поток сервлета в цикле и получил в буфере "правильного" размера только (начальную) часть клиентского запроса. Переделал. Если по UDP отправлять достаточно большие пакеты, то может быть и так, что фрагменты из начала, середины и конца "приедут" в строгом беспорядке. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 29.03.2013, 21:21:18 |
|
||
|
java nio server + многопоточность
|
|||
|---|---|---|---|
|
#18+
Basil A. Sidorov, Дык вроде автор TCP использовать собирается, UDP это из другого топика. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 29.03.2013, 21:37:29 |
|
||
|
java nio server + многопоточность
|
|||
|---|---|---|---|
|
#18+
DoSOfRedRiver, спасибо за ответы. Но, честно признаться, не понял я ответов 1) почему надо проверять именно при "распоточивании" 2) а есть ли ссылка на пример такого применения пула потоков, только лаконичная 3) нет в смысла в чем, в разрыве соединений? и еще, в ОС есть ограничение на кол-во соединений к порту - как его увеличить? а то получится, что сервер выдерживает нагрузку, а порт нет. кстати, что нассчет такого трюка для разгрузки порта - вначале все слушаем на одном порту, как только соединений набирается > 1000, регаем этот канал на другой селектор. то есть ассепт регается на один селктор, а при наборе каждой например тысячи соединений регаем этот канал на очередной селектор, которых мы в начале создадим ~20. Код: java 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 4) то есть фрагментация все таки вероятна? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 29.03.2013, 22:13:25 |
|
||
|
java nio server + многопоточность
|
|||
|---|---|---|---|
|
#18+
BaurzhanS, 1) Такая проверка обычно выполняется если что-то помимо основного потока исполнения может работать с соединением. В подавляющем большинстве случаев это либо клиент (со своей стороны, разумеется), либо другой поток вашей программы. 2) Если и была, то сейчас не найду. Как то писал подобную штуку, могу потом сорцы кинуть, опять же если найду. 3) Нет смысла хранить соединения. Если конечно ваш клиент не посылает данные через очень короткие промежутки времени. Возможно это имеет смысл в каких то сверхоптимизациях, но, может быть, лучше взглянуть в сторону UPD? Про порты ничего сказать не могу, думаю нагуглить не сложно. Не понял, что вы хотите сделать с селекторами, на производительность раздельный биндинг никак не повлияет, порт разгрузить вам не поможет. 4) Нет, если вы используете TCP. Возможно вам нужно почитать о протоколах TCP/UDP и их различиях? И всё-таки я рекомендую вам посмотреть в сторону NIO.2, AsynchronousChannel и т.д.. Поглядите на паттерны Reactor/Proactor. Может пригодится. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 29.03.2013, 23:09:30 |
|
||
|
java nio server + многопоточность
|
|||
|---|---|---|---|
|
#18+
BaurzhanS, getThreadFromPool - это вообще откуда? Что делает? Возвращает новый/старый threаd? Тогда у вас количество Thread'ов может неконтролируемо расти. Вы можете себе это позволить? Если да, то зачем вообще использовать NIO, а не старый добрый синхронный обмен. Если нет, то вам нужен не getThreadFromPool , а java.util.concurrent.Executor.execute(). Далее, если вы все же решили пройти путь NIO и асинхронно-параллельного программирования на thread pool'e до конца: основная проблема в том, что вам запрещено блокировать thread'ы. Нельзя thread.sleep, read() может вернуть 0 считанных байтов, нельзя take() из очереди, нельзя явно или неявно Object.wait(). Вместо этого вам придется выставлять callback'и, и тут новые засады: чтобы обезопасить вызывающего, callback'и запускаются отдельными task'ами, что снижает производительность и реактивность. Но это еще фигня, проблема в том, что callback должен модифицировать состояние некоего общего объекта, а как быть уверенным в том, что он не используется в данный момент другим callback'ом или пользовательской процедурой? Использовать synchronized? Но это опять же блокировка (запрещенная), плюс нехилая возможность deadlock'a. Все callback'и запускать на единственном thread'e (как в GUI framework'ах, там не смогли иначе решить проблему)? Прощай параллельность. Всё это относится и к NIO, и NIO.2 (AsynchronousChannel etc). Теперь хорошая новость. Проект df4j предлагает концепцию и реализацию асинхронно-параллельного стиля программирования, с адаптацией NIO и NIO.2. В связи с практическим отсутствием пользователей, проект сыроват. Вы можете помочь его развитию, просто попытавшись его использовать и прислав замечания. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 30.03.2013, 15:18:50 |
|
||
|
java nio server + многопоточность
|
|||
|---|---|---|---|
|
#18+
BaurzhanS4) еще очень часто в инете видел рекомендации по поводу реализации считки сообщений - говорят, что сообщения могут приходит хаотично, например начало сообщения, потом только его конец и я должен уметь распознавать цельные сообщения либо по наличию символа окончания строки, либо дополнять сообщение префиксом - количеством байт в сообщении и ждать именно столько байтов. А если я выделяю достаточно большой ByteBuffer могу ли я забить на такую хитрую обработку и считать то, что я считал из канала методом selectedChannel.read(someByteBuffer) цельным сообщением? Возможны ли ситуации, когда по каким-то причинам одно цельное сообщение теоретически помещающееся в буфер дробится на несколько мелких сообщений? Сообщения не приходят "хаотично". Плюньте в морду тому, кто это вам рассказывал. Это чистейший бред. Сообщения идут сплошным потоком, TCP протокол гарантирует доставку пакетов и их последовательность. При этом поток оптимизируется. Ведь кроме данных, в пакете есть еще и заголовок, служебная информация. Так вот если передавать очень маленькие пакеты, то заголовок будет в несколько раз больше самого пакета и это не оптимально. Поэтому существует так называемый "нагл" алгоритм, который склеивает несколько пакетов в один для оптимизации передачи. его кстати можно и отключать при работе. Но смысла в этом нет. В итоге сплошной поток байтов, которые представляют собой идущие подряд пакеты, протокол TCP "нарезает" на блоки так как ему удобнее для передачи. Но никакого хаоса в этом процессе нет. Все байтики идут последовательно и никуда не денутся. Ваша задача, "нарезать" этот поток байтов на ваши сообщения. Вообще есть только 3 варианта нарезки, либо передавать длину сообщения потом само сообщение, либо делать разделитель, либо делать пакеты одинакового размера. Но разделитель пакетов не универсальное средство и часто приводит к геморрою. Да и работать с ним неудобно. Поэтому передача сообщения в нормальных реализациях идет так INT(длинна сообщения)само сообщение. Таким образом вы будете точно знать где начинается и заканчивается ваше сообщение и проблем не будет. И это совсем не хитрая обработка, она тривиальна. И да, вы никогда не сможете гарантировать, что в буфере лежит целое сообщение. При любом его размере. DoSOfRedRiver4) С такого рода "фрагментацией" не сталкивался. А размер сообщения всё-таки лучше передавать, в заголовке, например. Что значит не сталкивались? Это основы. Самые самые основы. Размер сообщения не "лучше" передавать а просто необходимо, это самое нормальное средство. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 31.03.2013, 18:14:43 |
|
||
|
java nio server + многопоточность
|
|||
|---|---|---|---|
|
#18+
Ищущий Знания, А чем вам не нравится читать до -1? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 31.03.2013, 18:46:36 |
|
||
|
java nio server + многопоточность
|
|||
|---|---|---|---|
|
#18+
DoSOfRedRiverА чем вам не нравится читать до -1?Ну, например, HTTP/1.1 позволяет и несколько сообщений в одном подключении и несколько подключений для одного сообщения. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 31.03.2013, 21:08:45 |
|
||
|
java nio server + многопоточность
|
|||
|---|---|---|---|
|
#18+
DoSOfRedRiverИщущий Знания, А чем вам не нравится читать до -1? Поясните. Каким образом это чтение даст нам одно целое сообщение? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 01.04.2013, 00:20:21 |
|
||
|
java nio server + многопоточность
|
|||
|---|---|---|---|
|
#18+
Ищущий Знания, насчет Ищущий ЗнанияПоэтому существует так называемый "нагл" алгоритм, который склеивает несколько пакетов в один для оптимизации передачи. Я правильно понял, что если мои сообщения достаточно велики, то склеивание пакетов не происходит и тогда я могу не дополнять сообщение его длиной а делать просто socketChannel.read()? Я написал тестовый клиент, в котором отправляю сообщения вида Message # 1,Message # 2,... а на стороне сервера Код: java 1. 2. 3. и все нормально. У меня тут такая ситуация, клиента я не контролирую это не моя программа, я некое устройство, отправляющее на заданный порт сообщения. Поэтому дополнять префиксом не могу. Разве что по endline делить сообщения, но надо ли? Тест показал, что не надо, а от устройства будет приходить строка примерно такой длины, какую сейчас отправляет тестовый клиент. А так, на всякий случай, не знаете ли вы ресурс, где описывается обработка по эндлайну? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 01.04.2013, 07:54:48 |
|
||
|
java nio server + многопоточность
|
|||
|---|---|---|---|
|
#18+
Если (реальный) клиент формирует сообщение и оправляет его в одном подключении, то вычитывать из сокета "до минус один". Если клиент может отправить несколько сообщений в одном соединении или, наоборот, разбить одно сообщение на несколько подклчений - взять спецификацию клиента и разбирать/собирать сообщения на сервере. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 01.04.2013, 08:11:32 |
|
||
|
java nio server + многопоточность
|
|||
|---|---|---|---|
|
#18+
Ищущий Знания, Стандартный веб сервер на Thread-per-Connection модели: подключился, записал данные, получил ответ, отключился. Сервер считал все данные до end of stream, распарсил, записал ответ, закрыл соединение. В подавляющем большинстве случаев этого хватает. Записывать размер сообщения или нет зависит от протокола и задачи. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 01.04.2013, 12:21:59 |
|
||
|
java nio server + многопоточность
|
|||
|---|---|---|---|
|
#18+
BaurzhanSЯ правильно понял, что если мои сообщения достаточно велики, то склеивание пакетов не происходит Склеивание происходит не от объема происходит. Там много параметров. В общем случае невозможно гарантировать будет склейка или нет. Да и вообще, надо делать так чтобы склейка не играла роль, иначе гарантированно будут проблемы. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 01.04.2013, 23:48:40 |
|
||
|
java nio server + многопоточность
|
|||
|---|---|---|---|
|
#18+
Ищущий ЗнанияСклеивание происходит не от объема происходит. Там много параметров. В общем случае невозможно гарантировать будет склейка или нет. Да и вообще, надо делать так чтобы склейка не играла роль, иначе гарантированно будут проблемы.Nagle работает прозрачно для приложений и применяется тогда, когда данные "просто записываются в сокет". Если приложение (явно) делает send() и, вероятно, flush() - никакой nagle не остановит отправку одного байта. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 02.04.2013, 06:18:17 |
|
||
|
|

start [/forum/topic.php?fid=59&msg=38205132&tid=2129638]: |
0ms |
get settings: |
18ms |
get forum list: |
17ms |
check forum access: |
5ms |
check topic access: |
5ms |
track hit: |
61ms |
get topic data: |
17ms |
get forum data: |
5ms |
get page messages: |
105ms |
get tp. blocked users: |
3ms |
| others: | 326ms |
| total: | 562ms |

| 0 / 0 |
