Одно- или многопоточный с классом TCPListener? - PullRequest
2 голосов
/ 11 августа 2009

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

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

.

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

Ответы [ 4 ]

5 голосов
/ 11 августа 2009

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

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

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

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

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

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

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

3 голосов
/ 11 августа 2009

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

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

2 голосов
/ 11 августа 2009

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

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

Socket socket = tcpListener.AcceptSocket ();

и Socket.BeginReceive для начала приема данных.

0 голосов
/ 11 августа 2009

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

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

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

  1. Основная нить
  2. Читать тему
  3. Обработка потока
  4. Написать тему

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

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

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

Поток записи принимает все ответы, сгенерированные потоком обработки, и записывает их в NetworkStream.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...