Я пишу аудио-стример (клиент-сервер) как мой проект (C / C ++),
и я решил сделать многопоточный UDP-сервер для этого проекта.
Логика заключается в том, что каждый клиент будет обрабатываться в своем собственном потоке.
Проблемы, с которыми я сталкиваюсь — это взаимодействие потоков друг с другом.
Первое, что делает мой сервер, это создает своего рода пул потоков; это создает 5
темы, которые все автоматически блокируются recvfrom()
функция,
хотя кажется, что в большинстве случаев, когда я подключаю другое устройство
на сервер, более одного потока отвечает, а затем
это приводит к тому, что сервер полностью блокируется и больше не работает.
Это довольно сложно отлаживать, поэтому я пишу здесь по порядку
чтобы получить совет о том, как обычно реализованы многопоточные серверы UDP.
Должен ли я использовать мьютекс или семафор в части кода? Если так, то где?
Любые идеи будут чрезвычайно полезны.
Сделай шаг назад: ты говоришь
каждый клиент будет обрабатываться в своем собственном потоке
но UDP не ориентирован на соединение. Если все клиенты используют один и тот же адрес многоадресной рассылки, нет естественного способа решить, какой поток должен обрабатывать данный пакет.
Если вы привержены идее, что у каждого клиента есть свой собственный поток (который я обычно советую, но здесь это может иметь смысл), вам нужен какой-то способ выяснить, с какого клиента пришел каждый пакет.
Это означает, что либо
читая каждый пакет, выясняя, к какому логическому клиентскому соединению оно принадлежит, и отправляя его нужному потоку. Обратите внимание, что, поскольку информация о маршрутизации находится в глобальном / общем состоянии, эти два значения эквивалентны:
Первое, кажется, то, что вы ловите, но это плохой дизайн. Когда приходит пакет, вы просыпаете один поток, затем он блокирует мьютекс и выполняет поиск, и, возможно, пробуждает другой нить. Поток, который вы хотите обработать этим соединением, также может быть заблокирован для чтения, поэтому вам нужен какой-то механизм для его пробуждения.
Второе, по крайней мере, дает разделение проблем (чтение / отправка или обработка).
Разумно, ваш дизайн должен зависеть от
Первое, что делает мой сервер, это создает своего рода пул потоков; он создает 5 потоков, все из которых автоматически блокируются функцией recvfrom (), хотя кажется, что в большинстве случаев, когда я подключаю другое устройство к серверу, более одного потока отвечает, а затем это приводит к тому, что сервер полностью заблокирован и не работает дальше
Вместо того, чтобы все ваши потоки располагались в recvfrom () в одном и том же соединении с сокетом, вы должны защитить соединение с семафором, и ваши рабочие потоки ожидают семафора. Когда поток получает семафор, он может вызвать recvfrom (), а когда он возвращается с пакетом, поток может освободить семафор (для получения другого потока) и обработать сам пакет. Когда он завершит обслуживание пакета, он может вернуться к ожиданию на семафоре. Таким образом вы избежите необходимости передавать данные между потоками.
Ваш recvfrom должен находиться в главном потоке, а когда он получает данные, вы должны передать адрес IP: порт и данные клиента UDP в потоки помощника.
Передача IP: порта и данных может быть сделана, порождая новый поток каждый раз, когда главный поток получает пакет UDP или может быть передан вспомогательным потокам через очередь сообщений
Я думаю, что ваша главная проблема — непостоянное соединение udp. Udp не поддерживает ваши соединения живыми, он обменивается только двумя дейтаграммами за сеанс. В зависимости от вашего приложения, в худшем случае оно будет иметь параллельные потоки, считывающие первую доступную информацию, т. Е. Recvfrom () разблокируется, даже если это не его очередь.
Я думаю, что путь состоит в том, чтобы использовать select в основном потоке и, с одновременным буфером, управлять тем, что будет делать поток.
В этом решении у вас может быть один поток на клиента или один поток на файл, при условии, что вы храните у клиентов необходимую информацию, чтобы убедиться, что вы отправляете нужную часть файла.
TCP — это еще один способ сделать это, так как он поддерживает соединение для каждого потока, который вы запускаете, но это не лучший способ передачи данных для приложений, утерянных данными.