Я пишу несколько тестов для классов, которые обрабатывают многоадресную связь UDP. Я разработал тесты для использования интерфейса loopback (127.0.0.1 )для тестов, потому что я не хочу, чтобы они мешали другим программам/устройствам в сети.
В моем «модульном тесте» у меня есть проверенный сокет, который присоединяется к данной группе многоадресной рассылки и привязывается к 127.0.0.1 и отправителю. сокет, который также присоединился к той же группе многоадресной рассылки и привязывается к 127.0.0.1, оба, конечно, в одном и том же процессе.
Чтобы убедиться, что сообщение отправлено, у меня есть еще одна тестовая программа (, а значит, еще один процесс ), который также присоединяется к группе многоадресной рассылки и выводит все, что ей отправляется.
Проблема в том, что мой проверенный сокет никогда не получает то, что отправил отправитель, НО тестовая программа (, поэтому другой процесс )получает это.
Есть ли какие-то ограничения на комбинацию нескольких сокетов/многоадресной рассылки/локального хоста?
Новая информация:
Моей ошибкой было считать, что UDP на локальном хосте может быть надежным. Приведенная ниже тестовая программа показывает, что первый 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());
}
}
}
}
}