Эмуляция зависания потока клиента блокирует принятие сервером ввода-вывода в течение времени ожидания клиента - PullRequest
1 голос
/ 16 ноября 2011

Как видно из темы, у меня есть сервер и несколько клиентов.
Сервер одновременно принимает соединения ввода / вывода (нет очереди в сокетных соединениях), но у меня есть эта тревожная проблема, и я не знаю, как ее обойти! Если я заставляю клиента выдавать I/O Exception, сервер обнаруживает его и правильно завершает поток клиента (проверено в диспетчере задач (Windows) и системном мониторе (Ubuntu)). Но если я эмулирую ввод-вывод, который «зависает», как
, т.е.
Thread.sleep(60*1000);
или

private static Object lock = new Object();

synchronized(lock) {
   while (true) {
      try {
         lock.wait();
      } catch (InterruptedException e) {
         /* Foo */
      }
   }
} 

тогда все последующие операции ввода-вывода (подключение и передача данных), по-видимому, блокируются или ждут, пока «зависший» клиент не будет завершен. В приложениях используется ExecutorService, поэтому, если «зависший» клиент не завершит операции в предложенный срок, то для задачи истечет время ожидания, и клиент будет вынужден выйти. Последующие «заблокированные» операции ввода-вывода возобновятся, но мне интересно, почему сервер не принимает какие-либо подключения ввода-вывода или выполняет какие-либо операции ввода-вывода, когда клиент «зависает»?

ПРИМЕЧАНИЕ: Потоки клиентов происходят в главном сервере следующим образом:

while (true) { 
   accept client connection;
   submit client task;
          ||
         \  /
          \/ 
   // ExecutorService here in the form 
   // spService.submit(new Callable<Tuple<String[], BigDecimal[]>>() { 
   // ... code ... }}).get(taskTimeout, taskTimeUnit);
   check task result & perform cleanup if result is null;
   otherwise continue;
}

Ответы [ 2 ]

1 голос
/ 16 ноября 2011

Проблема:

Это может очень хорошо указывать на то, что ваш сервер ПРИНИМАЕТ клиентские соединения одновременно, однако он только синхронно обрабатывает эти соединения.Это означает, что даже если миллион клиентов успешно подключится в любой момент времени, если кто-либо из них займет много времени (или зависнет), он задержит остальных.

ТЕСТ:

Чтобы убедиться в этом: я бы переключил количество времени, которое требуется клиенту для подключения, добавив статистику Thread.sleep (1000) в ваши клиенты.

Ожидаемый результат:

Я полагаю, вы увидите, что даже добавление одного выражения Thread.sleep (1000) в ваш клиент задерживает все остальные подключающиеся клиенты на 1000.

0 голосов
/ 20 ноября 2011

Я думаю, что нашел источник своих проблем!Я использую одну модель потока на клиента, но я запускаю свои тесты локально, т.е. на одной машине, что означает, что все они имеют один и тот же IP!Таким образом, каждому клиенту назначается один и тот же IP с сервером!Я предполагаю, что это приводит к тому, что сервер и клиенты различаются только по номеру порта, но поскольку каждый клиент сопоставлен с отдельным локальным портом для каждого соединения с сервером, сервер не должен блокироваться.Я подтвердил, что каждый клиент и сервер используют разные операции ввода-вывода (сравниваемые ссылки), и я обертываю их сокеты с помощью <Input/Output>Stream s до BufferedReader s & PrintWriter s, но все же, когда клиент зависает, все другие клиенты тоже зависают (поэтомуможет быть каналы ввода / вывода действительно одинаковые ???)!Я проверю это на другой машине и проверю результаты обратно с вами!:)

РЕДАКТИРОВАТЬ: Подтверждено ошибочное поведение.Кажется, что даже с удаленными клиентами, если один зависает, другие клиенты, кажется, тоже зависают!: /Не знаю, но я полон решимости это исправить.Просто это довольно странно, так как я почти уверен, что использую один поток на клиента (операции ввода-вывода отличаются, сокеты клиентов различаются, IP-адреса не являются проблемой, я даже сопоставляю каждого клиента на сервере с локальным портом моеговыбор ...)Может быть, я переключусь на NIO, если не найду решение достаточно скоро.

РЕШЕНИЕ : Решил проблему!Казалось, что ExecutorService должен быть запущен в отдельном потоке, иначе, если ввод / вывод на клиенте заблокирован, все операции ввода / вывода будут блокироваться!Это странно, учитывая тот факт, что я пробовал и Executors.newFixedThreadPool(<nThreads>);, и Executors.newCachedThreadPool();, и действия клиента (также известные как операции ввода-вывода) должны выполняться в новом потоке для каждого клиента.В любом случае я использовал метод и обернул вызовы, чтобы каждое клиентское учреждение использовало final ExecutorService baseWorker = Executors.newSingleThreadExecutor();, и каждый раз явно создавал новый поток, используя <Thread instance>.start();, чтобы каждый поток работал в фоновом режиме:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...