2012-02-23 138 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