У вас есть серьезная проблема в вашем примере.
С Java NIO, нить, делающего принять()необходимо только делать то принимать(). Примеры игрушек в стороне, вероятно, вы используете Java NIO из-за ожидаемого большого количества соединений. Если вы даже думаете о том, что делать чтение в том же потоке, что и при выборе, ожидающие непринятые выбирают время ожидания, пока соединение не будет установлено. К тому моменту, когда эта переполненная нить приближается к принятию соединения, ОС с обеих сторон откажется, а accept() завершится с ошибкой.
Выполняйте абсолютный минимум только в нити выбора. Больше, и вы просто переписываете код, пока не сделаете только минимум.
[В ответ на комментарий]
только в игрушечные примеры должны чтение быть обработаны в основном потоке.
Попробуйте справиться:
- 300+ одновременных попыток соединения.
- Каждое установочное соединение отправляет 24 Кбайт на один сервер, т. Е. Небольшую веб-страницу, маленькую .jpg.
- Замедление каждого соединения незначительно (соединение устанавливается по коммутируемому каналу или сеть имеет скорость с высокой ошибкой/повторной попыткой) - поэтому ACK TCP/IP занимает больше времени, чем это необходимо (из-за вашего уровня управления уровнем ОС)
- Проведите несколько тестовых подключений, отправьте один байт каждые 1 миллисекунду. (это имитирует клиента, который имеет собственное условие высокой нагрузки, поэтому генерирует данные с очень низкой скоростью.) Поток должен тратить почти столько же усилий на обработку одного байта, сколько 24K байт.
- Удалите некоторые соединения без предупреждения (проблемы с потерей связи).
Как правило, соединение должно устанавливаться в пределах 500 мс -1500 мс до того, как попытка машины отключит соединение.
В результате всех этих проблем один поток не сможет получить все соединения, установленные достаточно быстро, прежде чем машина на другом конце откажется от попытки подключения. Чтения должны быть в другом потоке. период.
[Key Point] Я забыл, чтобы действительно было ясно. Но в потоках, выполняющих чтение, будет свой собственный Селектор. Селектор, используемый для установления соединения, не должен использоваться для прослушивания новых данных.
Добавление (в ответ на утверждение Gnarly о том, что нет ввода/вывода на самом деле не происходит во время вызова Java считывать поток.
Каждый слой имеет определенный размер буфера. После того, что буфер заполнен, то операции ввода-вывода Например, буферы TCP/IP имеют между буферами 8K-64K на одно соединение. После того, как буфер TCP/IP заполняется, принимающий компьютер сообщает, что отправляющий компьютер останавливается. Если принимающий компьютер не обрабатывает буферизованные байты достаточно быстро, отправляющий компьютер отключит соединение.
Если принимающий компьютер обрабатывает буферизованные байты, отправитель будет продолжать передавать по tes, , в то время как java io read call делается.
Кроме того, убедитесь, что первый байт, который должен прибыть, запускает «байты, доступные для чтения» на селекторе. Нет никаких гарантий относительно того, сколько прибыли.
Размеры буфера, определенные в java-коде, не имеют отношения к размеру буфера ОС.
Что такое ОС хоста? Это может быть функция реализации/ошибка, поскольку спецификации пакета утверждают, что это все поточно-безопасные конструкции. – alphazero
Хост-компьютер под Mac OS X 10.5.6. Сегодня я повторяю тесты под Windows 7, и все работает отлично. Похоже, вы правы. –
Что произойдет, если вы закроете channel.socket() перед закрытием канала? – Nuoji