MultiCast обменивается сообщениями нескольким клиентам на той же машине

Я пытаюсь записать сервер/сервис, который широковещательно передает сообщение на LAN, когда-либо приблизительно второй, Отчасти как сервисное исследование.

Сообщение должно быть получено несколькими клиентскими программами, которые могли быть на той же машине или различных машинах. Но могла быть больше чем одна программа на каждой машине, работающей одновременно.

Я использую delphi7 с инди 9.0.18

то, где я застреваю, - то, если я должен использовать UDP (TIdUDPClient/Server) или Многоадресный IP-пакет (TIdIPMCastClient/Server) или если его даже возможный...

Мне удалось заставить это работать с IP Много Бросок с одним клиентом на машину, но даже после многих попыток с различной привязкой.. макс. порты / минимальные порты и т.д., я, может казаться, не нахожу решение.

10
задан Kara 25 April 2014 в 18:02
поделиться

5 ответов

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

Вы обычно делаете это, вызывая setsockopt, но я не разработчик Delphi, поэтому я не уверен, как выглядит ваш API. Этот вопрос , кажется, показывает пример того, как кто-то делает нечто подобное в Delphi.

8
ответ дан 3 December 2019 в 21:20
поделиться

У RemObjects есть хорошее решение для этого: ROZeroConf

До того, как это стало доступно, я сам делал что-то подобное с TROBroadcastChannel RemObjects SDK (на основе UDP и Indy). {{1 }} Внутри этого компонента он вызывает TIdUDPBase.Broadcast для отправки и TIdUDPClient.ReceiveBuffer для получения ответов.

(кстати, широковещательная рассылка UDP работает только в той же сети / подсети, ROZeroConf - лучшее решение)

1
ответ дан 3 December 2019 в 21:20
поделиться

Я никогда этого не делал, но похоже, что вам нужны "почтовые ящики". Он будет транслировать сообщение по локальной сети и получать ответы от других рабочих станций, которые знают, как отвечать. Так работает популярный менеджер лицензий «броненосец» (чтобы убедиться, что регистрационные ключи не «переподписаны»). Мое приложение (ClipMate) использует Armadillo как защитную оболочку (условно-бесплатную оболочку). Когда зарегистрированный пользователь запускает приложение, он проверяет, используется ли тот же ключ другими машинами в той же сети. По сути, он говорит: «Я использую лицензию 1234, как насчет вас?» Он ждет ответов (я делаю это в отдельном потоке во время запуска, чтобы не блокировать свой запуск). Если другие рабочие станции сообщают, что используют тот же ключ, я сверяю счет с количеством рабочих мест, содержащихся в лицензии. Я не совсем уверен, что он такой же надежный в Windows7 ....

5
ответ дан 3 December 2019 в 21:20
поделиться

Это определенно возможно.

По поводу «UDP или многоадресной рассылки» вы говорите о яблоках и апельсинах. Многоадресная рассылка - это концепция IP, поэтому вы можете с удовольствием использовать UDP через многоадресный IP или через широковещательный IP.

Если вас устраивает ограничение, когда все клиенты локально связаны (маршрутизаторы и т. Д., Как правило, не пересылают широковещательные пакеты), я бы сказал, что просто используйте широковещательную рассылку. TIdUdpBase.Broadcast будет здесь вашим другом.

Обновление: При многоадресной или широковещательной рассылке только один сокет может быть привязан к любой конкретной паре IP / порт. Таким образом, если вы хотите, чтобы несколько клиентов слушали ОДНУ широковещательную / многоадресную рассылку, я думаю, вам понадобится дополнительный клиент-диспетчер. Этот клиент-диспетчер принимает широковещательные сообщения и уведомляет каждого клиента на машине.

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

Этот процесс регистрации может быть таким же простым, как привязка к любому доступному порту на локальном IP-адресе и обращение к диспетчеру:« Пожалуйста, отправляйте широковещательные рассылки на этот IP / порт ».

Обновление: Кристофер Чейз имеет правильную идею. Я только что закончил почти то же самое решение, что и его, за исключением того, что я пропатчил IdIPMCastClient, добавив свойство ReuseAddr: Boolean и изменив TIdIPMCastClient.GetBinding, добавив

if Self.ReuseAddr then begin
  SetReuseAddr := Id_SO_True;
  Bindings[i].SetSockOpt(Id_SOL_SOCKET, Id_SO_REUSEADDR, @SetReuseAddr, Sizeof(SetReuseAddr));
end;

между вызовами AllocateSocket и Bind (где SetReuseAddr: Integer).

2
ответ дан 3 December 2019 в 21:20
поделиться

с подсказкой от shf301, это код, с которым я заставил его работать

Я создал новый TIdIPMCastClient

 TIdReUseIPMCastClient = class(TIdIPMCastClient)
  private
    procedure SetReUseAddr(InBinding: TIdSocketHandle; const Value: boolean);
  protected
    function GetBinding: TIdSocketHandle; override;
  public
  end;

добавил Процедуру

procedure TIdReUseIPMCastClient.SetReUseAddr(InBinding: TIdSocketHandle; const Value: boolean);
var
  tempi: integer;
begin
  if Assigned(InBinding) and InBinding.HandleAllocated then
    begin
    tempi := iif(Value, 1, 0);
    InBinding.SetSockOpt(Id_SOL_SOCKET, Id_SO_REUSEADDR, PChar(@tempi), SizeOf(tempi));
    end;
end;

скопировал GetBinding код из TIdIPMCastClient и добавил SetReUseAddr перед привязкой

  Bindings[i].AllocateSocket(Id_SOCK_DGRAM);
  SetReUseAddr(Bindings[i], True);
  Bindings[i].Bind;
1
ответ дан 3 December 2019 в 21:20
поделиться
Другие вопросы по тегам:

Похожие вопросы: