Одно- или многопоточный с классом TCPListener?

2

Мы создаем приложение С#, которое должно связываться с другой системой через сокеты TCP/IP. Мы ожидаем получить около 1-2 входящих транзакций в секунду, каждое сообщение в среднем составляет около 10 тыс. (Текст и 1 изображение).

Затем мы сделаем некоторую обработку (может занять от 100 миллисекунд до 3 секунд, в зависимости от нескольких переменных), а затем отправить ответ примерно на 1k.

В примерах, которые я рассмотрел, некоторые из них многопоточные. Для этого приложения было бы лучше сделать его одиночным или многопоточным? Если рекомендуется многопоточность, примерно то, что будут делать разные потоки?

Теги:
sockets
tcp

4 ответа

5

(не относится к С#)

Сделав это в обоих направлениях (экстремальная производительность не была решающим фактором), я предпочитаю подход 1-нить за соединение.

Тема прослушивателя
Задача этого потока - прослушивать сокет для входящих подключений, принимать их и порождать новый поток подключений (давая ему подключенный сокет).

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

Когда соединение замирает, этот поток также умирает.

Темы управления
Если выполняется очистка или периодическое техническое обслуживание, все они могут работать в своих потоках.

Просто помните о блокировке (очевидно): Сколько данных необходимо делать для обмена данными? Убедитесь, что все ваши ресурсы правильно заблокированы при доступе, и что у вас нет каких-либо взаимоблокировок или условий гонки. Тем не менее, это более общая тема.

  • 3
    Подумайте об использовании потоков-пулов вместо создания нового потока для каждого запроса. Создание нового потока может быть дорогим и предоставляет хорошую возможность для DOS-атак.
  • 0
    Будет несколько общих ресурсов: объект соединения с базой данных, объект журналирования и т. Д. Это, как правило, поточнобезопасные синглтоны, но я также мог бы взглянуть на предоставление каждому потоку своего собственного экземпляра ...
Показать ещё 3 комментария
3

Если вы ожидаете нескольких подключений, вам понадобятся несколько потоков. Каждому потоку будут предоставлены потоки для конкретного клиента, которые ему нужно будет обрабатывать отдельно.

Я думаю, что сервер политики Silverlight - отличный пример использования многопоточного серверного приложения. Хотя он использует класс Socket вместо TcpListener.

  • 0
    Вы бы сказали, что много подключений к одному и тому же порту от одного и того же клиента составляют «несколько подключений» или только одно подключение?
  • 0
    Это все еще считается несколько соединений.
2

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

В принципе создайте сокет с прослушивателем

Socket socket = tcpListener.AcceptSocket();

и Socket.BeginReceive, чтобы начать прием данных.

0

Я думаю, важно определить, что подразумевается под словом "соединение".

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

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

  • Основной поток
  • Прочитать поток
  • Обработка потока
  • Создать поток

Основной поток создает TcpListener и ждет, пока соединение не будет установлено. В этот момент он просто инициирует асинхронное чтение и ждет, пока программа не закончится (ManualResetEvent.WaitOne()).

Поток чтения - это асинхронный поток, который обслуживает чтение из NetworkStream.

Поток обработки принимает транзакции из потока Read и выполняет любую обработку.

Нить записи принимает любые ответы, генерируемые потоком обработки, и записывает их в NetworkStream.

В соответствии с этой ссылкой вам не нужно синхронизировать чтение и запись с тем же NetworkStream, пока чтение и запись выполняется в отдельных потоках. Вы можете использовать общий список или очередь для перемещения данных между потоками. Я бы создал один для данных Read-to-Processing и один для данных "Обработка-Запись" . Просто не забудьте синхронизировать доступ к ним с помощью свойства SyncRoot.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню