2012-08-03 108 views
3

我正在爲處理UDP多播通信的類寫入一些測試。 我設計了測試,使用回送接口(127.0.0.1)進行測試,因爲我不希望它們干擾網絡上的其他程序/設備。UDP在同一進程中的兩個套接字之間的組播

以我「的單元測試」我有一個測試插座銷連接給定多播組並結合到127.0.0.1和發送 套接字還加入了相同的多播組並結合到127.0.0.1,二者當然在相同的過程。

爲了確保消息已發送,我有另一個測試程序(也是另一個進程),它也加入了多播組並輸出發送給它的所有內容。

問題是我的測試套接字永遠不會收到發送者發送的內容,但測試程序(所以另一個進程)收到它。

組合多個套接字/多播/本地主機是否存在一些限制?

新的信息:

我的錯誤是考慮到UDP在localhost上可能是可靠的。下面的測試程序顯示,第一個UDP數據包從來沒有被我的偵聽套接字(至少在我的計算機上)接收(但其他進程仍然收到它)。

在我的單元測試中,我正在發送一個數據包,並希望得到具體的答案:我無法負擔發送消息兩次並只接收一次答案。

如果我在發送第一個數據包之前等待第一個接收超時,它似乎可以可靠地工作。

有沒有人有一個想法,爲什麼第一個UDP數據包永遠不會到達?

下面是我在試驗中使用的代碼:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Net; 
using System.Net.Sockets; 
using System.Threading; 
using NUnit.Framework; 

namespace MulticastTest 
{ 
    [TestFixture] 
    public class Program 
    { 
     static void Main(string[] args) 
     { 
      new Program().Run(); 
      Console.WriteLine("Press any key to exit..."); 
      Console.ReadKey(); 
     } 

    [Test] 
    public void Run() 
    { 
     _waitFirstReadTiemout = new AutoResetEvent(false); 
     IPAddress lMulticastAddress = new IPAddress(0xFAFFFFEF); 
     IPEndPoint lRemoteEndPoint = new IPEndPoint(lMulticastAddress, 1900); 

     // Create sender socket 
     Socket lSendSocket = new Socket(AddressFamily.InterNetwork, 
          SocketType.Dgram, 
          ProtocolType.Udp); 

     // Allow to share the port 1900 with other applications 
     lSendSocket.SetSocketOption(SocketOptionLevel.Socket, 
           SocketOptionName.ReuseAddress, 
           true); 

     // Set TTL for multicast packets: socket needs to be bounded to do this 
     lSendSocket.SetSocketOption(SocketOptionLevel.IP, 
           SocketOptionName.MulticastTimeToLive, 
           2); 

     // Bind the socket to the local end point: this MUST be done before joining the multicast group 
     lSendSocket.Bind(new IPEndPoint(IPAddress.Loopback, 55236)); 

     // Join the multicast group 
     lSendSocket.SetSocketOption(SocketOptionLevel.IP, 
         SocketOptionName.MulticastLoopback, 
         true); 

     lSendSocket.SetSocketOption(SocketOptionLevel.IP, 
           SocketOptionName.AddMembership, 
           new MulticastOption(lMulticastAddress)); 

     // Create receiver and start its thread 
     Thread lReceiveThread = new Thread(ReceiveThread); 
     lReceiveThread.Start(); 

     int i = 0; 
     while (!fStop) 
     { 
      if (i == 0) 
       _waitFirstReadTiemout.WaitOne(10000); 

      byte[] lToSend = Encoding.ASCII.GetBytes(DateTime.Now.ToString("yyyyMMdd HHmmss")); 
      lSendSocket.SendTo(lToSend, lRemoteEndPoint); 
      Console.WriteLine("Sent #" + (i + 1) + ": " + DateTime.Now.ToString("yyyyMMdd HHmmss")); 
      Thread.Sleep(1000); 
      try 
      { 
       if (Console.KeyAvailable || i >= 10) 
        fStop = true; 
      } 
      catch (InvalidOperationException) 
      { 
       fStop = i >= 10; 
      } 
      finally 
      { 
       ++i; 
      } 
     } 
    } 

    private AutoResetEvent _waitFirstReadTiemout; 

    private bool fStop; 

    private void ReceiveThread() 
    { 
     Socket lSocket = new Socket(AddressFamily.InterNetwork, 
            SocketType.Dgram, 
            ProtocolType.Udp); 

     // Allow to share the port 1900 with other applications 
     lSocket.SetSocketOption(SocketOptionLevel.Socket, 
           SocketOptionName.ReuseAddress, 
           true); 

     // TTL not required here: we will only LISTEN on the multicast socket 
     // Bind the socket to the local end point: this MUST be done before joining the multicast group 
     lSocket.Bind(new IPEndPoint(IPAddress.Loopback, 1900)); 

     // Join the multicast group 

     // If the local IP is a loopback one, enable multicast loopback 
     lSocket.SetSocketOption(SocketOptionLevel.IP, 
        SocketOptionName.MulticastLoopback, 
        true); 

     lSocket.SetSocketOption(SocketOptionLevel.IP, 
           SocketOptionName.AddMembership, 
           new MulticastOption(
             new IPAddress(0xFAFFFFEF))); 

     lSocket.ReceiveTimeout = 1000; 

     byte[] lBuffer = new byte[65000]; 
     int i = 0; 
     while (!fStop) 
     { 
      try 
      { 
       int lReceived = lSocket.Receive(lBuffer); 
       ++i; 
       Console.WriteLine("Received #" + i + ": " + Encoding.ASCII.GetString(lBuffer, 0, lReceived)); 
      } 
      catch (SocketException se) 
      { 
       _waitFirstReadTiemout.Set(); 
       Console.WriteLine(se.ToString()); 
      } 
     } 
    } 
} 

}

+0

嘗試設置'udpClient.Client.MulticastLoopback' – 2012-08-03 10:27:57

回答

4

這很可能是您的發送和接收線程之間的競賽 - 您在接收方加入組之前發送第一個數據包。這解釋了爲什麼它在超時時間內工作。

+0

是的,你是對的:在發送第一個數據包之前增加一個睡眠有很大幫助。謝謝! – 2012-08-07 06:59:43

+0

你知道你可以接受答案,對吧? :) – 2012-08-07 12:11:12

+0

現在我知道是怎麼回事,謝謝! – 2012-08-08 06:01:12

2

您可能需要啓用插槽上的環回模式。

+0

對不起,我應該提到它我的郵件。我在兩個套接字上都將MulticastLoopback選項設置爲true。但非常感謝您的建議! – 2012-08-03 11:07:25

相關問題