【问题标题】:MultiCast Messages to multiple clients on the same machine多播消息到同一台机器上的多个客户端
【发布时间】:2011-02-05 23:37:00
【问题描述】:

我正在尝试编写一个服务器/服务,它每秒左右在局域网上广播一条消息,有点像服务发现。

消息需要被 多个客户端程序可能是 在同一台机器上或不同的机器上 机器。但可能有更多 每台机器上运行一个程序 同一时间。

我正在使用 delphi7,带有 indy 9.0.18

如果我应该使用 UDP(TIdUDPClient/Server) 或 IP MultiCast (TIdIPMCastClient/Server),或者如果它甚至可能的话……

我设法让它与每台机器一个客户端的 IP Multi Cast 一起工作,但即使在多次尝试使用不同的绑定之后.. 最大/最小端口等,我似乎无法找到解决方案。

【问题讨论】:

    标签: delphi delphi-7 indy multicast indy-9


    【解决方案1】:

    RemObjects 对此有一个很好的解决方案:ROZeroConf

    在此之前,我自己使用 RemObjects SDK(基于 UDP 和 Indy)的TROBroadcastChannel 制作了类似的东西。 在该组件内部,它调用TIdUDPBase.Broadcast 发送和TIdUDPClient.ReceiveBuffer 接收响应。

    (顺便说一句,UDP 广播仅适用于同一网络/子网,ROZeroConf 是更好的解决方案)

    【讨论】:

      【解决方案2】:

      绝对有可能。

      关于“UDP 或多播”,您说的是苹果和橘子。组播是一个 IP 概念,因此您可以愉快地通过 UDP 组播 IP 或通过广播 IP。

      如果您对让所有客户端链接本地(路由器等通常不转发广播数据包)的限制感到满意,我会说只使用广播。 TIdUdpBase.Broadcast 将成为您的朋友。

      更新:使用多播或广播,您只能将一个套接字绑定到任何特定的 IP/端口对。因此,如果您希望多个客户端都收听相同的广播/多播,我认为您将需要一个额外的调度程序客户端。此调度程序客户端接收广播并通知机器上的每个客户端。

      在您的每个客户端中,您都有一个小的注册程序,上面写着“尝试绑定到发送广播的端口。如果可以,请在该端口上设置调度程序客户端。如果不能,调度程序已经创建,并将自己注册到该调度程序。”

      该注册过程可以很简单,只需绑定到本地 IP 上的任何可用端口,然后对调度程序说“请向此 IP/端口发送广播。”

      更新: Christopher Chase 有正确的想法。我刚刚完成了与他几乎完全相同的解决方案,除了我修补了 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)。

      【讨论】:

      • 感谢您的回答,实际上需要UDP和多播的限制,即我不希望消息离开局域网等,但我似乎无法解决的问题是有两个客户端同一台计算机监听广播
      • 我在 Indy 10 的 TIdIPMCastClient 中添加了一个新的 ReuseSocket 属性。
      【解决方案3】:

      根据 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;
      

      从 TIdIPMCastClient 复制 GetBinding 代码,并在绑定前添加 SetReUseAddr

        Bindings[i].AllocateSocket(Id_SOCK_DGRAM);
        SetReUseAddr(Bindings[i], True);
        Bindings[i].Bind;
      

      【讨论】:

      • 我在 Indy 10 中为 TIdIPMCastClient 添加了一个新的 ReuseSocket 属性。
      【解决方案4】:

      我认为您正在寻找SO_REUSEADDR 套接字选项。在套接字上设置该选项允许多个套接字在同一个端口上侦听。对于多播,Windows 保证消息将被传递到所有套接字(否则消息只会随机发送到一个套接字)。

      您通常通过调用 setsockopt 来执行此操作,但我不是 Delphi 开发人员,所以我不确定您的 API 是什么样的。这个question 似乎展示了某人在 Delphi 中做类似事情的例子。

      【讨论】:

      • 非常好,SO_REUSEADDR 这就是我需要的提示
      • 在 mac OSX 上,我必须添加:sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, True)
      【解决方案5】:

      我从未这样做过,但您似乎需要“邮槽”。它将在本地网络上广播一条消息,并从其他知道如何回复的工作站接收任何回复。这就是流行的“犰狳”许可证管理器的工作方式(以确保注册密钥不会“超额订阅”)。 我的应用程序(ClipMate)使用犰狳作为保护包装(共享软件包装)。当注册用户运行该应用程序时,它会检查同一网络上的其他计算机是否正在使用相同的密钥。它基本上说:“我使用的是 1234 许可证,你呢?”它等待回复(我在启动期间在单独的线程中执行此操作,因此我不会阻止我的启动)。如果其他工作站报告他们正在使用相同的密钥,我会根据许可证中包含的席位数量检查计数。我不完全确定它在 Windows7 上是否强大......

      【讨论】:

      • funkypuppy.com 有一个简单的邮件槽实现,它在 Delphi 7 中运行良好。
      • 邮件插槽听起来很有希望。我尝试了 funkypuppy 的实现,但我似乎不能有超过 2 个程序在同一台计算机上接收消息。也许我做错了?
      • 尽管 Windows 邮槽被“宣传”为一种广播机制,它指的是不同机器上的接收器。在一台机器上,只有一个进程可以拥有和读取特定名称的邮槽。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多