Надлежащий способ остановить TcpListener

Позвольте мне показать вам, что я считаю еще лучшим способом многообразий. Если вы хотите, чтобы Action s были подключаемыми, и пусть кто-нибудь их добавляет, часто бывает полезно предоставить простой Module для кого-то, кто будет использовать эту шкуру, нуждающуюся в создании экземпляра Multibinder. Вот пример:

public abstract class ActionModule extends AbstractModule {
  private Multibinder<Action> actionBinder;

  @Override protected void configure() {
    actionBinder = Multibinder.newSetBinder(binder(), Action.class);
    configureActions();
  }

  /**
   * Override this method to call {@link #bindAction}.
   */
  protected abstract void configureActions();

  protected final LinkedBindingBuilder<Action> bindAction() {
    return actionBinder.addBinding();
  }
}

Теперь почему это лучше? Это позволяет кому-то использовать ActionModule из любого места, чтобы добавить больше Action s через стандартный API привязки. Я думаю, что это более читаемо. Вот пример использования:

public final class MyStandardActionModule extends ActionModule() {
  @Override protected void configureActions() {
    bindAction().to(FooAction.class);
    bindAction().to(BarAction.class);
    // If you need to instantiate an action through a Provider, do this.
    bindAction().toProvider(BazActionProvider.class);
    // You can also scope stuff:
    bindAction().to(MySingletonAction.class).in(Singleton.class);
  }
}

Этот шаблон использования Module, чтобы скрыть многострочный бит, используется в коде Guice. Это немного работает впереди, но держит вещи в чистоте. Вы также можете сделать что-то подобное для MapBinder, если вам нужно. Имейте в виду, что вы можете создать столько ActionModule, сколько хотите.

60
задан Christian P. 13 December 2008 в 16:12
поделиться

7 ответов

Существует 2 предложения, которые я сделал бы, учитывая код и что я предполагаю, Ваш дизайн. Однако я хотел бы указать сначала, что необходимо действительно использовать неблокирующиеся обратные вызовы ввода-вывода при работе с вводом-выводом как сетевые или файловые системы. Это далеко , более эффективный FAR и Ваше приложение будет работать намного лучше, хотя они более тверды к программе. Я кратко покрою предложенную модификацию дизайна в конце.

  1. Использование Используя () {} для Потока TcpClient
  2. . Аварийное прекращение работы ()
  3. TcpListener. Ожидание ()
  4. Асинхронная перезапись

Использование Используя () {} для Примечания TcpClient

***, что необходимо действительно включить вызов TcpClient в использование () {} блок для обеспечения того TcpClient. Расположите () или TcpClient. Близко () методы называют даже в случае исключения. Поочередно можно вставить это наконец блок попытки {} наконец {} блок.

Поток. Аварийное прекращение работы ()

существует 2 вещи, я вижу, что Вы могли сделать. 1 то, что при запуске этого потока TcpListener от другого можно просто назвать Поток. Прервите метод экземпляра для потока, который будет заставлять threadabortexception быть брошенным в блокирующемся вызове и идти по стеку.

TcpListener. При ожидании ()

вторая недорогая фиксация должна была бы использовать слушателя. Ожидание () метод для реализации модели опроса. Вы тогда использовали бы Поток. Сон для "ожидания" прежде, чем видеть, находится ли новое соединение на рассмотрении. Как только у Вас есть незаконченное соединение, которое Вы назвали бы AcceptTcpClient, и это выпустит незаконченное соединение. Код выглядел бы примерно так.

while (listen){
     // Step 0: Client connection
     if (!listener.Pending())
     {
          Thread.Sleep(500); // choose a number (in milliseconds) that makes sense
          continue; // skip to next iteration of loop
     }

     TcpClient client = listener.AcceptTcpClient();
     Thread clientThread = new Thread(new ParameterizedThreadStart(HandleConnection));
     clientThread.Start(client.GetStream());
     client.Close();
}

Асинхронная Перезапись

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

В основном Вы запустили бы свой код с метода BeginAcceptTcpClient и отслеживали бы IAsyncResult, что Вы возвращаетесь. Вы указываете на это на метод чей ответственный за получение TcpClient и передачу его прочь НЕ к новому потоку, но к потоку прочь ThreadPool. QueueUserWorkerItem, таким образом, Вы не вращаетесь и закрываете новое обсуждение для каждого клиентского запроса (Отмечают Вас, возможно, должен использовать Ваш собственный пул потоков, если у Вас есть особенно долговечные запросы, потому что пул потоков совместно используется и если Вы монополизируете все потоки, другие части Вашего приложения, реализованного системой, могут быть исчерпаны ресурсы). Как только метод прослушивателя начал Ваш новый TcpClient к своему собственному запросу ThreadPool, который это называет BeginAcceptTcpClient снова и указывает на делегата назад на себя.

Эффективно Вы просто разбиваете свой существующий метод в 3 различных метода, которые тогда назовут различные части. 1. загружать все, 2. чтобы быть целью для вызова EndAcceptTcpClient начните TcpClient к своему собственному потоку и затем назовите себя снова, 3. обработать клиентский запрос и закрыть его по окончании.

58
ответ дан Ortund 7 November 2019 в 14:13
поделиться

Не используйте цикл. Вместо этого назовите BeginAcceptTcpClient () без цикла. В обратном вызове просто издайте другой приказ к BeginAcceptTcpClient (), если Ваш слушать флаг все еще установлен.

Для остановки слушателя, так как Вы не заблокировались, Ваш код может просто звонить Близко () на нем.

2
ответ дан Mike Scott 7 November 2019 в 14:13
поделиться

Сокеты обеспечивают мощные асинхронные возможности. Смотрите на Используя Асинхронный Сокет Сервера

, Вот несколько примечаний по коду.

Используя вручную созданные потоки в этом случае могут быть издержки.

код ниже подвергается условиям состязания - TcpClient. Близко () закрывает сетевой поток, Вы проходите через TcpClient. GetStream (). Рассмотрите заключительный клиент, где можно определенно сказать, что это больше не необходимо.

 clientThread.Start(client.GetStream());
 client.Close();

TcpClient. Остановите () завершения, лежащие в основе сокета. TcpCliet. AcceptTcpClient () использует Сокет. Примите () метод на базовом сокете, который бросит SocketException, как только это закрывается. Можно назвать его от различного потока.

Так или иначе я рекомендую асинхронные сокеты.

3
ответ дан Dzmitry Huba 7 November 2019 в 14:13
поделиться

Вероятно, лучше всего использовать асинхронное функция BeginAcceptTcpClient. Тогда можно просто назвать Остановку () на слушателе, поскольку она не будет блокироваться.

-1
ответ дан Paul 7 November 2019 в 14:13
поделиться

Только для добавления еще большей причины использовать асинхронный подход я - вполне уверенный Поток. Аварийное прекращение работы не будет работать, потому что вызов заблокирован в стеке TCP уровня ОС.

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

1
ответ дан Eric Nicholson 7 November 2019 в 14:13
поделиться

Некоторые изменения, чтобы сделать ответ Питера Олерта идеальным. Потому что до 500 миллисекунд слушатель снова блокируется. Чтобы исправить это:

    while (listen)     
    {
       // Step 0: Client connection     
       if (!listener.Pending())     
       {
           Thread.Sleep(500); // choose a number (in milliseconds) that makes sense
           continue; // skip to next iteration of loop
       }
       else // Enter here only if have pending clients
       {
          TcpClient client = listener.AcceptTcpClient();
          Thread clientThread = new Thread(new ParameterizedThreadStart(HandleConnection));
          clientThread.Start(client.GetStream());
          client.Close();
       }
   }
-2
ответ дан 24 November 2019 в 17:46
поделиться

listener.Server.Close () из другого потока прерывает блокирующий вызов.

A blocking operation was interrupted by a call to WSACancelBlockingCall
48
ответ дан 24 November 2019 в 17:46
поделиться
Другие вопросы по тегам:

Похожие вопросы: