Как распространить входящие соединения tcplistener по потокам в .NET? - PullRequest
15 голосов
/ 15 сентября 2008

При использовании Net.Sockets.TcpListener, как лучше всего обрабатывать входящие соединения (.AcceptSocket) в отдельных потоках?

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

Пример C # кода VB.NET приветствуется.

Ответы [ 5 ]

14 голосов
/ 29 октября 2008

Код, который я использовал, выглядит следующим образом:

class Server
{
  private AutoResetEvent connectionWaitHandle = new AutoResetEvent(false);

  public void Start()
  {
    TcpListener listener = new TcpListener(IPAddress.Any, 5555);
    listener.Start();

    while(true)
    {
      IAsyncResult result =  listener.BeginAcceptTcpClient(HandleAsyncConnection, listener);
      connectionWaitHandle.WaitOne(); // Wait until a client has begun handling an event
      connectionWaitHandle.Reset(); // Reset wait handle or the loop goes as fast as it can (after first request)
    }
  }


  private void HandleAsyncConnection(IAsyncResult result)
  {
    TcpListener listener = (TcpListener)result.AsyncState;
    TcpClient client = listener.EndAcceptTcpClient(result);
    connectionWaitHandle.Set(); //Inform the main thread this connection is now handled

    //... Use your TcpClient here

    client.Close();
  }
}
3 голосов
/ 15 сентября 2008

Я полагаю, что вы делаете это так же, как любая другая асинхронная операция в .NET: вы вызываете версию метода BeginXxx, в данном случае BeginAcceptSocket. Ваш обратный вызов будет выполнен в пуле потоков.

Пулы, как правило, масштабируются намного лучше, чем потоки на соединение: как только вы получите несколько десятков соединений, система будет работать намного тяжелее при переключении между потоками, чем при фактической работе. Кроме того, каждый поток имеет свой собственный стек, размер которого обычно составляет 1 МБ (хотя это зависит от флагов канала), который должен быть найден в виртуальном адресном пространстве 2 ГБ (в 32-разрядных системах); на практике это ограничивает вас до 1000 потоков.

Я не уверен, использует ли он сейчас пул потоков .NET, но в Windows есть объект ядра, называемый портом завершения ввода / вывода, который помогает в масштабируемом вводе / выводе. Вы можете связать потоки с этим объектом, и с ним могут быть связаны запросы ввода-вывода (включая прием входящих соединений). Когда ввод-вывод завершается (например, устанавливается соединение), Windows освобождает ожидающий поток, но только в том случае, если количество выполняемых в данный момент потоков (не заблокированных по какой-либо другой причине) меньше настроенного предела масштабируемости для порта завершения. Обычно вы устанавливаете это на кратное число ядер.

2 голосов
/ 20 сентября 2008

Я хотел бы предложить другой подход: Мое предложение использует только две темы. * один поток проверяет наличие входящих соединений. * Когда новое соединение открыто, эта информация записывается в общую структуру данных, которая содержит все текущие открытые соединения. * 2-й поток перечисляет эту структуру данных и для каждого открытого соединения получает отправленные данные и отправляет ответы.

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

1 голос
/ 15 сентября 2008

Отличный пример есть в поваренной книге O'Reilly C # 3.0. Вы можете скачать сопроводительный источник с http://examples.oreilly.com/9780596516109/CSharp3_0CookbookCodeRTM.zip

0 голосов
/ 15 сентября 2008

Я бы использовал пул потоков, так что вам не придется каждый раз запускать новый поток (так как это довольно дорого). Я также не буду ждать бесконечно дальнейших соединений, так как клиенты могут не закрывать свои соединения. Как вы планируете каждый раз направлять клиента в один и тот же поток?

Извините, нет образца.

...