2009-07-21 46 views
0

概述:我已经建立了一个服务器和一个客户端,在这两个服务器都尝试使用UDP发现彼此。当服务器启动时,它会发送一条多播消息(239.1.1.1),表明它处于活动状态。当客户端启动时,它发送一个多播消息(239.1.1.2),表明它处于活动状态。服务器和客户端都订阅对方的多播消息以接收其传输。这样,无论哪个应用程序(服务器或客户端)首先启动,其中一个或另一个将被通知它们的存在。为什么UDP套接字订阅一个多播组正在拾取一个非多播消息?

在客户端我做到以下几点:

  1. 建立一个监听套接字订阅和接收服务器发起的多播消息。
  2. 设置一个接收套接字来接收服务器对客户端组播的响应。
  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); 

Server代码:

// 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); 
+0

在多播环境中,为什么服务器甚至需要知道客户端? – MyItchyChin 2009-07-21 16:01:21

+0

我使用多播的唯一原因是在所有客户端和单个服务器之间建立发现。发现完成后,我切换到TCP/IP(WCF netTcpBinding),然后服务器可以将消息发送到客户端。客户端也可以向服务器发送某些客户端事件的通知。 – Elan 2009-07-22 19:25:35

+0

你已经提到了不同的(组播)客户端地址。你是说客户1将有一个地址,客户2将有另一个? – 2010-02-02 08:20:42

回答

3

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

PS

这似乎有点小题大做有您的服务器加入组播组听取新客户 - 你可以只是定期服务器发送信标到客户端的组播地址说:“我在这里” (比如每30秒一次)。

0

虽然我不知道它的解决您的问题,我希望客户端和服务器交谈的相同 IP组播地址(例如239.1.1.1)。目前看起来您已经为客户端和服务器分配了一个地址,以及在您引入新客户端时会发生什么?

0

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

2
receiveSocket.Bind(new IPEndPoint(IPAddress.Any, 50000)); 

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

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