Java - несколько селекторов в нескольких потоках для неблокирующих сокетов - PullRequest
6 голосов
/ 10 июля 2009

Я пишу Java-приложение, которое будет создавать экземпляры объектов класса для представления клиентов, которые подключились и зарегистрировались во внешней системе на другой стороне моего приложения.

В каждом клиентском объекте есть два вложенных класса, представляющих интерфейс и бэкэнд. интерфейсный класс будет непрерывно получать данные от реального клиента и отправлять указания и данные во внутренний класс, который будет принимать эти данные из интерфейсного модуля и отправлять их во внешнюю систему, используя надлежащий формат и протокол эта система требует.

В проекте мы стремимся к тому, чтобы каждый экземпляр объекта client был потоком. Тогда в каждом потоке, естественно, будет два сокета [EDIT] со своими собственными каналами NIO каждый [/ EDIT], один на стороне клиента, а другой на стороне системы, соответственно, на передней и задней частях. Однако теперь это приводит к необходимости неблокирующих сокетов. Я читал учебник здесь , в котором объясняется, как безопасно использовать селектор в вашем основном потоке для обработки всех потоков с подключениями.

Но мне нужны несколько селекторов, каждый из которых работает в своем собственном потоке. Прочитав вышеупомянутое руководство, я узнал, что наборы ключей в селекторе не являются потокобезопасными. Означает ли это, что отдельные селекторы, созданные в их собственных репрезентативных потоках, могут создавать конфликтующие ключи, если я попытаюсь дать им каждому по своей паре сокетов и каналов? Перемещение селектора вверх по основному потоку - небольшая возможность, но далеко не идеальная, исходя из требований к программному обеспечению, которые мне были даны. Спасибо за вашу помощь.

Ответы [ 2 ]

3 голосов
/ 07 октября 2009

Можно использовать несколько селекторов, если вы не зарегистрируете один и тот же канал с одинаковыми интересами (OP_READ / OP_WRITE и т. Д.) В обоих экземплярах селектора. Регистрация одного и того же канала с несколькими экземплярами селектора может вызвать проблему, при которой selector1.select () может использовать событие, которое может заинтересовать selector2.select ().

Селекторы по умолчанию на большинстве платформ основаны на poll () [или epoll ()]. ​​

Selector.select внутренне вызывает int poll( ListPointer, Nfdsmsgs, Timeout) method.

        where the ListPointer structure can then be initialized as follows:

    list.fds[0].fd = file_descriptorA;
    list.fds[0].events = requested_events;
    list.msgs[0].msgid = message_id;
    list.msgs[0].events = requested_events;

Тем не менее, я бы порекомендовал использовать один выбранный поток, как упомянуто в руководстве ROX RPC nio. Реализации NIO зависят от платформы, и вполне возможно, что то, что работает на одной платформе, может не работать на другой. Я также видел проблемы в минорных версиях. Например, в AIX JDK 1.6 SR2 использовался селектор на основе poll () - PollSelectorImpl и соответствующий поставщик селекторов как PollSelectorProvider, наш сервер работал нормально. Когда я перешел на AIX JDK 1.6 SR5, который использовал оптимизированный селектор на основе интерфейса pollset (PollSetSelectorImpl), мы столкнулись с частыми зависаниями на нашем сервере в select () и socketchannel.close (). Я вижу одну причину в том, что мы открываем несколько селекторов в нашем приложении (в отличие от идеальной модели Selecting Thread) и реализацию PollSetSelectorImpl, как описано здесь .

3 голосов
/ 11 июля 2009

Если вам нужно использовать это соединение с одним сокетом, вы должны отделить процесс приема и записи данных из канала и в канал от самой обработки данных. Вы не должны делегировать канал. Канал похож на автобус. Шина (единственный поток, который управляет каналом) должна прочитать данные и записать их в (потокобезопасную) входную очередь, включающую необходимую информацию, чтобы ваш клиентский поток (ы) мог подобрать правильный пакет дейтаграммы из очередь. Если клиентскому потоку нравится записывать данные, эти данные записываются в очередь вывода, которая затем считывается потоком каналов для записи данных в канал.

Таким образом, из концепции совместного использования связи между субъектами, использующими это соединение, с их непредсказуемым временем обработки (которое является основной причиной для блоков), вы переходите к концепции асинхронного чтения данных, обработки данных и записи данных. Таким образом, теперь не время обработки непредсказуемо, а время чтения или записи ваших данных. Неблокирующая означает, что поток данных является максимально постоянным, несмотря на то, какое время требуется для обработки этих данных.

...