2012-02-23 135 views
4

我有以下代码发送多路广播消息,然后等待响应发送到消息来自的地址。如果我观察Wireshark中的流量,我可以看到消息发送正常,并且响应返回到正确的IP和端口,但是套接字永远不会从接收线返回,就像没有收到响应一样。如何发送消息并在同一个套接字上接收响应

var multicastAddress = IPAddress.Parse("239.255.255.250"); 
    var multicastPort = 1900; 
    var unicastPort = 1901;   

    using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)) 
    { 
     socket.Bind(new IPEndPoint(IPAddress.Any, unicastPort)); 
     socket.Connect(new IPEndPoint(multicastAddress, multicastPort)); 
     var thd = new Thread(() => 
      { 
       try 
       { 
        while (true) 
        { 
         var response = new byte[8000]; 
         EndPoint ep = new IPEndPoint(IPAddress.Any, unicastPort); 
         socket.ReceiveFrom(response, ref ep); 
         var str = Encoding.UTF8.GetString(response); 
         Devices.Add(new SsdpDevice() {Location = str}); 
        } 
       } 
       catch 
       { 
        //TODO handle exception for when connection closes 
       } 
      }); 
     socket.Send(broadcastMessage, 0, broadcastMessage.Length, SocketFlags.None); 
     thd.Start(); 
     Thread.Sleep(30000); 
     socket.Close(); 
    } 

我知道我应该使用的插座类的异步方法,需要停止依靠的Thread.Sleep但我只是希望得到一个简单的例子,之前的工作我整理代码。

+0

请问你空的catch实际上捕获错误? – Smudge202 2012-02-24 08:11:42

+0

当连接关闭并且仍在等待响应时抛出SocketException – Gavin 2012-02-24 08:15:43

回答

9

加文,检查了这一点:

  • 不要使用不同的端口。你如何期望在一个上多播并在另一个上接收?
  • 不要使用Connect(),多播是无连接消息(就像广播一样)。
  • Bind()之后,将套接字选项设置为多播。
  • 使用SendTo()而不是Send(),在这种情况下不起作用。
  • 首先开始接收(即使在阻塞模式下,它是一个不同的端点),然后发送。

和一个简单的工作示例:

var broadcastMessage = Encoding.UTF8.GetBytes("Hello multicast!"); 
var multicastAddress = IPAddress.Parse("239.255.255.250"); 
var signal = new ManualResetEvent(false); 
var multicastPort = 1900; 

using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)) 
{ 
    var multicastEp = new IPEndPoint(multicastAddress, multicastPort); 
    EndPoint localEp = new IPEndPoint(IPAddress.Any, multicastPort); 

    // Might want to set this: 
    //socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, 1); 
    socket.Bind(localEp); 
    socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(multicastAddress, IPAddress.Any)); 
    // May want to set this: 
    //socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 0); // only LAN 
    var thd = new Thread(() => 
     { 
      var response = new byte[8000]; 
      socket.ReceiveFrom(response, ref localEp); 
      var str = Encoding.UTF8.GetString(response).TrimEnd('\0'); 
      Console.WriteLine("[RECV] {0}", str); 
      signal.Set(); 
      Console.WriteLine("Receiver terminating..."); 
     }); 
    signal.Reset(); 
    thd.Start(); 

    socket.SendTo(broadcastMessage, 0, broadcastMessage.Length, SocketFlags.None, multicastEp); 
    Console.WriteLine("[SEND] {0}", Encoding.UTF8.GetString(broadcastMessage)); 
    signal.WaitOne(); 
    Console.WriteLine("Multicaster terminating..."); 
    socket.Close(); 
    Console.WriteLine("Press any key."); 
    Console.ReadKey(); 
} 
+0

NoDelay选项对于UDP有什么作用?我知道它禁用了Nagle的TCP算法,但我认为UDP套接字并不适用。 – 2014-09-16 13:46:01

+1

已删除。感谢您指出了这一点。其实NoDelay仅用于TCP。当时我不确定,所以我写了'你可能想用'。问题是,如果你将它谷歌,那么人们使用UDP + NoDelay编写的代码很多。这是我把它列入我的答案,但注释掉了,因为我没有仔细研究它。 – 2014-09-17 19:04:58

+0

啊,不错。世界仍然对我有意义:)。还有1个问题。网络设备不会转发TTL为0的数据包吗?这意味着将TTL设置为0是毫无意义的,因为第一个网络设备只会收到您的数据包并丢弃它。 – 2014-09-18 01:21:04