【问题标题】:Why UDP socket subscribed to a multicast group is picking up a non-multicast message?为什么订阅多播组的 UDP 套接字正在接收非多播消息?
【发布时间】:2009-07-21 15:30:52
【问题描述】:

概述:我已经设置了一个服务器和一个客户端,两者都尝试使用 UDP 发现彼此。当服务器启动时,它会发送一条多播消息 (239.1.1.1),表明它还活着。当客户端启动时,它会发送一条多播消息 (239.1.1.2),表明它是活动的。服务器和客户端都订阅了彼此的多​​播消息以接收它们的传输。这样,无论哪个应用程序(服务器或客户端)首先启动,都会通知其中一个或另一个它们的存在。

在客户端我执行以下操作:

  1. 设置侦听套接字以订阅和接收来自服务器的多播消息。
  2. 设置接收套接字以接收服务器对客户端多播的响应
    以下 #3 的消息。
  3. 发送一条客户端正在运行的多播消息(供服务器接收和响应)。
  4. 接收服务器对 #3 中发送的客户端多播消息的响应。

问题:一切正常,除了两个接收套接字最终都获得了服务器(非多播)对客户端的响应。我不清楚这是否是预期的行为。我可以将两个接收插座减少到一个吗? #1 订阅了服务器的多播,而#2 只是在同一端口上侦听来自服务器的直接传输(来自服务器的非多播消息)。我可以安全地移除第二个接收插座吗?

请参阅下面的源代码(为了简化代码演示,我删除了异常处理)。

客户端代码:

// 1. Set up a socket and asynchronously listen for server startup multicasts.
Socket listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram,
    ProtocolType.Udp);
listenSocket.SetSocketOption(SocketOptionLevel.Socket,
    SocketOptionName.ReuseAddress, 1);
listenSocket.Bind(new IPEndPoint(IPAddress.Any, 50000));
listenSocket.SetSocketOption(SocketOptionLevel.IP,SocketOptionName.AddMembership,
    new MulticastOption(IPAddress.Parse("239.1.1.1")));
EndPoint clientEndPoint = new IPEndPoint(0, 0);
listenSocket.BeginReceiveFrom(receiveBuffer, 0, receiveBuffer.Length,
    SocketFlags.None, ref clientEndPoint,
    new AsyncCallback(OnServerMessageReceived), (object)this);

// 2. Set up socket to receive the server's response to client's multicast.
Socket receiveSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram,
    ProtocolType.Udp);
receiveSocket.SetSocketOption(SocketOptionLevel.Socket,
    SocketOptionName.ReuseAddress, 1);
receiveSocket.Bind(new IPEndPoint(IPAddress.Any, 50000));
receiveSocket.ReceiveTimeout = 3000; // Timeout after 3 seconds.

// 3. Send a multicast message for server to respond to.
Socket sendSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram,
    ProtocolType.Udp);
EndPoint multicastEndPoint = new IPEndPoint(IPAddress.Parse("239.1.1.2"), 50000);
sendSocket.SendTo(packet, packet.Length, SocketFlags.None, multicastEndPoint);

// 4. Wait for server to respond to the multicast message (timeout = 3 seconds).
byte[] receiveBuff = new byte[2048];
EndPoint serverEndPoint = new IPEndPoint(0, 0);
int bytesRead = receiveSocket.ReceiveFrom(receiveBuff, ref serverEndPoint);

服务器代码:

// Receive multicast message sent from client (in asynchronous callback method).
EndPoint clientEndPoint = new IPEndPoint(0, 0);
int bytesRead = listenSocket.EndReceiveFrom(asyncResult, ref clientEndPoint);

// Send response back to the client (change port to 50000).
EndPoint destination = new IPEndPoint((clientEndPoint as IPEndPoint).Address,
    50000);
Socket responseSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram,
    ProtocolType.Udp);
responseSocket.SendTo(response, response.Length, SocketFlags.None, destination);

【问题讨论】:

  • 在多播环境中,为什么服务器甚至需要知道客户端?
  • 我使用多播的唯一原因是在所有客户端和单个服务器之间建立发现。发现完成后,我切换到 TCP/IP (WCF netTcpBinding),然后服务器可以将消息发送到客户端。客户端还可以向服务器发送某些客户端事件的通知。
  • 您提到了不同的(多播)客户端地址。你是说客户 1 有一个地址,客户 2 有另一个地址?
  • 如果您使用多播进行发现,为什么不使用 WCF 发现?它似乎要简单得多,这似乎就是您所需要的:msdn.microsoft.com/en-us/library/dd456791(v=vs.110).aspx

标签: c# sockets udp multicast discovery


【解决方案1】:

您的问题的答案是“是的,这是预期的行为”。您无需打开单独的套接字即可在同一端口上接收单播数据包。

附言

让你的服务器加入一个多播组来监听新客户端似乎有点过头了——你可以让服务器定期向客户端多播地址发送一个信标,说“我在这里”(例如,每 30 秒一次) .

【讨论】:

  • IPAddress.Any 在您发送到 Bind 的 IPEndPonint 对象中意味着 - 您可以将此套接字绑定到您拥有的任何网络接口上的端口 50000。如果您有多个接口并且想要绑定到特定接口,则可以指定该接口的 ip 来代替 IPAddress.Any。这并不意味着“此套接字可以接收发往任何 IP 地址的任何 UDP 数据包”。
  • 感谢您的回复。 1)我认为订阅多播会专门并且只接收发送到订阅地址的多播。单播消息是否因为单播消息的目标地址是在同一端口上侦听的同一台机器而被拾取? 2)我有一台服务器正在监听新客户。重复的信标不会导致不必要的网络负载吗?一旦所有客户端完成发现信标就不再需要了。服务器不知道存在多少客户端。但是,客户端可以继续尝试,直到成功连接到服务器。
  • 1) 是的 - 就像您将套接字选项设置为接收广播一样,您仍将继续接收单播。 2) 维护多播组也会产生网络负载,这将大大简化客户端和服务器逻辑。
【解决方案2】:
receiveSocket.Bind(new IPEndPoint(IPAddress.Any, 50000));

您的接收套接字绑定到任何地址,这意味着它们将接收单播、广播和多播流量。您可以绑定到接口地址以仅接收单播流量,您可以仅绑定到多播组以仅接收多播流量。

发送 UDP 数据报时,您可以指定可以是多播或单播的目标地址。因此,您可以将服务器和客户端代码分别减少到一个套接字。

【讨论】:

    【解决方案3】:

    虽然我不确定它是否解决了您的问题,但我希望客户端和服务器都使用 相同 IP 多播地址(例如 239.1.1.1)进行通信。目前,您似乎已经为客户端和服务器分别提供了一个地址,如果/当您引入新客户端时会发生什么?

    【讨论】:

    • 我故意给客户端和服务器不同的多播地址,这样客户端就不会接收到它发出的多播消息(以服务器为目标),反之亦然。客户端订阅来自服务器的多播消息,服务器订阅来自客户端的多播消息。每次启动一个新的客户端,它都会发送一个多播消息来搜索服务器。服务器以其 IP 地址和端口信息进行响应,然后完成发现过程并允许客户端和服务器建立 TCP 连接(使用 WCF)。
    【解决方案4】:

    更好的选择是使用像BonjourAvahi 这样的服务发现协议,而不是使用自己的协议,因为它们已经解决了很多问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-09-16
      • 2012-06-05
      • 1970-01-01
      • 2018-11-07
      • 1970-01-01
      • 2012-03-03
      • 1970-01-01
      • 2012-05-28
      相关资源
      最近更新 更多