Написание серверного приложения, которое отправляет клиентам (TCP) - PullRequest
4 голосов
/ 01 ноября 2011

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

Сервер:

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

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

Итак, как мне подойти к этому?

Ответы [ 2 ]

4 голосов
/ 01 ноября 2011

Как правило, если у вас несколько клиентов, есть несколько способов справиться с этим.

Прежде всего, в TCP, когда клиент подключается к вам, он помещается в очередь до тех пор, пока его не смогут обслуживать. Это дано, вам не нужно ничего делать, кроме как вызвать системный вызов accept, чтобы получить нового клиента. Как только клиент получен, вам будет предоставлен сокет, который вы используете для чтения и записи. Кто читает / пишет первым, полностью зависит от вашего протокола, но обеим сторонам необходимо знать протокол (который вы можете определить).

Как только у вас есть розетка, вы можете сделать несколько вещей. В простом случае вы просто читаете некоторые данные, обрабатываете их, записываете обратно в сокет, закрываете сокет и обслуживаете следующего клиента. К сожалению, это означает, что вы можете одновременно обслуживать только одного клиента, поэтому «принудительные» обновления невозможны. Другая стратегия состоит в том, чтобы сохранить список всех открытых сокетов. Любые «обновления» просто перебирают список и записывают в каждый сокет. Это может представлять проблему, хотя, поскольку только разрешает push-обновления (если клиент отправил запрос, кто будет его отслеживать?)

Более продвинутый подход заключается в назначении одного потока для каждого сокета. В этом сценарии каждый раз, когда создается сокет, вы запускаете новый поток, цель которого - обслуживать только одного клиента. Это сокращает задержку и использует несколько ядер (если доступно), но гораздо сложнее программировать. Кроме того, если у вас есть 10 000 подключающихся клиентов, это 10000 потоков, что становится слишком много. Передача обновления одному клиенту (в этом сценарии) очень проста (поток просто записывает в соответствующий сокет). Нажать на все сразу немного сложнее (требуется либо событие потока, либо очередь производителя / потребителя, ни то, ни другое не очень интересно реализовать)

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

1 голос
/ 01 ноября 2011

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

...