Обработка нескольких подключений TcpClient без использования потоков

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

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

Что-то типа...

while (keepRunning)
{
     // Wait for any one connection to receive something.
     TcpClient active = WaitAnyTcpClient(collectionOfOpenTcpClients);

     // One selected connection has incomming traffic. Deal with it.
     // (If other connections have traffic during this function, the OS
     // will have to buffer the data until the loop goes round again.)
     DealWithConnection(active);
}

Дополнительная информация:
Объекты TcpClient поступают из TcpListener.
Целевая среда будет MS .NET или Mono-on-Linux.
Протокол требует длительных периодов простоя, пока соединение открыто.


person billpg    schedule 04.04.2011    source источник
comment
В мире Unix для этого можно использовать select системный вызов. Я уверен, что в винде есть аналог.   -  person Victor Sorokin    schedule 04.04.2011
comment
Ваше предположение о потоке для каждого соединения ошибочно. Пулы потоков в сочетании с методами APM - способ решить эту проблему. Всего несколько потоков могут обслуживать множество клиентов. Этот ответ, который я дал, должен оказаться информативным: stackoverflow.com/questions/3153959/   -  person spender    schedule 04.04.2011
comment
@spender - Вы предлагаете мне BeginRead всех ~ 1000 TcpClients и обрабатывать любой трафик в обратном вызове? Если вы хотите записать это в ответ, я приму это.   -  person billpg    schedule 04.04.2011


Ответы (1)


То, что вы пытаетесь сделать, в терминологии Microsoft называется асинхронным шаблоном. Общая идея состоит в том, чтобы изменить все операции блокировки ввода-вывода на неблокирующие. Если это сделано, приложению обычно требуется столько же системных потоков, сколько ядер ЦП на машине.

Взгляните на библиотеку параллельных задач в .Net 4: http://msdn.microsoft.com/en-us/library/dd460717%28VS.100%29.aspx

Это довольно зрелая оболочка над простой старой парадигмой Begin / Callback / Context .Net.

Обновлять:

Подумайте, что вы будете делать с данными после чтения из соединения. В реальной жизни вам, вероятно, придется ответить клиенту или сохранить данные в файл. В этом случае вам понадобится некоторая инфраструктура C #, чтобы содержать / управлять вашей логикой и при этом оставаться в одном потоке. TPL предоставляет это вам бесплатно. Его единственный недостаток в том, что он был введен в .Net 4, так что, вероятно, его еще нет в Mono.

Еще нужно учитывать время жизни соединения. Как часто ваши связи открываются / закрываются и как долго они живут? Это важно, потому что принятие и отключение TCP-соединения требует обмена пакетами с клиентом (который является асинхронным по своей природе, и, более того, злонамеренный клиент может вообще не возвращать пакеты ACK (-подтвержденные)). Если вы считаете, что этот аспект важен для вашего приложения, вы можете узнать, как правильно с этим справиться в .Net. В WinAPI соответствующие функции - AcceptEx и DisconnectEx. Вероятно, они завернуты в .Net с методами Begin / End - в этом случае все готово. В противном случае вам, вероятно, придется создать оболочку для этих вызовов WinAPI.

person Krit    schedule 04.04.2011