2015-03-25 1 views
1

Типичное серверное приложение создало бы сокет для каждого входящего соединения, создавая новый поток.Возможно ли создать один сокет, один поток, устройство чтения TCP/IP для нескольких клиентов?

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

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

Возможно ли это в .NET? P/Invoke также будет приемлемым решением.

ответ

2

Типичное серверное приложение создало бы сокет для каждого входящего соединения, создавая новый поток.

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

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

Но IMHO только серверы производства действительно имеют отношение к вопросу, поскольку они показывают, что хорошо дизайн и реализация были бы. И для тех, нить за соединение определенно будет в меньшинстве.

Однако возможно ли сделать demuxing самостоятельно в одном потоке?

С помощью Socket.Select() можно использовать одну цепочку, предназначенную для обработки нескольких сокетов.

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

Мой предпочтительный подход с текущим .NET 4.5 и C# 5.0 особенностей является обернуть сокет в экземпляре NetworkStream, так что я могу использовать ReadAsync() и WriteAsync() методы, которые, в свою очередь, позволяет использовать await в C# код. Это упрощает чтение и реализацию асинхронного кода.

Но вы можете использовать, например. Socket.BeginReceive() или Socket.ReceiveAsync() (последний полезен для серверов, которым требуется чрезвычайно высокая масштабируемость и hellip, даже первая из них по-прежнему гораздо более масштабируема, чем потоковая связь).

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

1

Абсолютно, трюк заключается в использовании асинхронного ввода-вывода (то есть BeginAccept, EndAccept, BeginRead, EndRead, BeginWrite и EndWrite). Это позволяет обрабатывать несколько клиентов без необходимости потоков. Так реагирует реакция.

1

Используйте метод Socket.Select.

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

Когда вы создаете свой считываемый массив, поместите сокет master/mother, чтобы вы знали, когда есть новое соединение. Также добавьте любые существующие соединения. Поместите все из массива ошибок. Для массива записи вам нужно только поставить сокеты, когда буфер записи заполнен. Вероятно, это то, что вы можете игнорировать на своей первой итерации, но это будет важно, когда вы начнете передавать серьезный трафик.

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

Смежные вопросы