Код, который я использовал, похож на это:
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();
}
}
Я полагаю, что Вы делаете это таким же образом как любую другую асинхронную операцию в.NET: Вы называете версию BeginXxx метода, в этом случае BeginAcceptSocket. Ваш обратный вызов выполнится на пуле потоков.
Объединенные потоки обычно масштабируются намного лучше, чем для каждого подключения потоком: после того как Вы преобладаете над несколькими десятками соединений, системных работ намного тяжелее в переключении между потоками, чем при получении фактической сделанной работы. Кроме того, каждый поток имеет свой собственный стек, который обычно является 1 МБ в размере (хотя он зависит от флагов ссылки), который должен быть найден в виртуальном адресном пространстве на 2 ГБ (в 32-разрядных системах); на практике это ограничивает Вас меньше чем 1 000 потоков.
я не уверен, использует ли пул потоков.NET в настоящее время его, но Windows имеет объект ядра, названный Портом Завершения ввода-вывода, который помогает в масштабируемом вводе-выводе. Можно связать потоки с этим объектом, и запросы ввода-вывода (включая принятие входящих соединений) могут быть связаны с ним. Когда ввод-вывод завершается (например, соединение прибывает), Windows выпустит поток ожидания, но только если количество в настоящее время выполнимых потоков (не заблокированный по некоторой другой причине) является меньше, чем настроенный предел масштабируемости для порта завершения. Обычно Вы установили это на маленькое несколько из количества ядер.
Я хотел бы предложить другой подход: Мое предложение использует только два потока. * один поток проверяет на входящие соединения. *, Когда новое соединение открылось, эта информация записана в структуру совместно используемых данных, которая содержит все текущие открытые соединения. * 2-й поток перечисляет ту структуру данных, и для каждого открытого соединения получают отправленные данные и отправляют ответы.
Это решение более масштабируемое мудрый потоком, и, если реализовано currectly должен иметь лучшую производительность, затем открывающую новый поток на открытое соединение.
В Поваренной книге O'Reilly C# 3.0 существует яркий пример. Можно загрузить сопроводительный источник от http://examples.oreilly.com/9780596516109/CSharp3_0CookbookCodeRTM.zip
Я использовал бы пул потоков, этот способ, которым Вы не должны будете начинать новую дискуссию каждый раз, когда (так как это довольно дорого). Я также не ожидал бы неограниченно долго дальнейших соединений, так как клиенты не могут закрыть свои соединения. Как Вы планируете направить клиент к тому же потоку каждый раз?
Извините, не имеют образца.