问题
I am trying to set up auto discovery using UDP multicasting, and am using some sample code from the internet. this seems to work ok when I run the client and the server on the same machine, but when I run them on different machines, either with a machine running in a VM on my machine (virtualBox) or on other 'real' machines on the network then the other machines never seem to receive the messages being broadcast.
After some googling it seems the likely culprit would be the router (SpeedTouch 780) which might be dropping the packets. How can I check if this is the case? Are their other things which I can check to try and track down the problem? Might it be something else entirely?
teh codez:
server code
using System;
using System.Net.Sockets;
using System.Text;
internal class StockPriceMulticaster
{
private static string[] symbols = {"ABCD", "EFGH", "IJKL", "MNOP"};
public static void Main ()
{
using (UdpClient publisher = new UdpClient ("230.0.0.1", 8899))
{
Console.WriteLine ("Publishing stock prices to 230.0.0.1:8899");
Random gen = new Random ();
while (true)
{
int i = gen.Next (0, symbols.Length);
double price = 400*gen.NextDouble () + 100;
string msg = String.Format ("{0} {1:#.00}", symbols, price);
byte[] sdata = Encoding.ASCII.GetBytes (msg);
publisher.Send (sdata, sdata.Length);
System.Threading.Thread.Sleep (5000);
}
}
}
}
and the client:
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
class StockPriceReceiver{
public static void Main(){
UdpClient subscriber = new UdpClient(8899);
IPAddress addr = IPAddress.Parse("230.0.0.1");
subscriber.JoinMulticastGroup(addr);
IPEndPoint ep = null;
for(int i=0; i<10;i++){
byte[] pdata = subscriber.Receive(ref ep);
string price = Encoding.ASCII.GetString(pdata);
Console.WriteLine(price);
}
subscriber.DropMulticastGroup(addr);
}
}
EDIT
So it seems that it is publishing the UDP packets on the VirtualBox host only network interface for some reason rather than the wireless network that all the machines are connected to. Just need to figure out how to make it not do that... So added the resolution in an answer instead...
回答1:
So the issue turned out to be that as I had more than 1 active network connection it was choosing one and using that and that was causing the UDP packets to be sent out on a different network connection that the client was listening on. As i had installed Virtual box it had installed and activated the VirtualBox Host-only network adapter, so that host only network connections could be supported. When I switched VirtualBox over to host only mode the packets started to be received. Disabling the VirtualBox adapter and switching back to a bridged connection also worked.
回答2:
If you have multiple interfaces, the right answer is to listen to all of them, and not try to pick one if you do not have a definition of what is right.
Here's how I implemented a UDP discovery service. It broke, originally, because my Virtual Box interfaces got in the way and swallowed up the UDP broadcasts on a random IP subnet (192.168.56.x) instead of my actual ethernet connection (192.168.0.x). So I improved it, based on the answer from Guge. It's a little verbose and I probably didn't code it in the most neat way, but it works now. I broadcast on all interfaces, then
receive the data (round-robin) on all interfaces until the timeout, or single response (if justFindOne = true
).
For some reason, IPv6 interfaces crash the UDP part, so I just filter out IPv4 addresses. Please correct me if there is a way for this to work on both.
const int iPort = 7611;
const int IP_TIMEOUT = 1000;
private static List<DiscoveryServer> FindIPAddresses(string filter, bool justFindOne)
{
List<DiscoveryServer> ipNames = new List<DiscoveryServer>();
byte[] message = new byte[2] { 17, 2 };
string hostname = Dns.GetHostName();
IPHostEntry entry = Dns.GetHostEntry(hostname);
List<UdpClient> clients = new List<UdpClient>();
try
{
// send out UDP packets on all IPv4 interfaces.
foreach (var ipAddress in entry.AddressList)
{
if (ipAddress.AddressFamily == AddressFamily.InterNetwork)
{
IPEndPoint ipLocalEndPoint = new IPEndPoint(ipAddress, iPort);
UdpClient udpC = new UdpClient(ipLocalEndPoint);
clients.Add(udpC);
udpC.EnableBroadcast = true;
udpC.Client.ReceiveTimeout = IP_TIMEOUT;
int response1 = udpC.Send(message, 2, new IPEndPoint(IPAddress.Broadcast, iPort));
}
}
if (clients.Count == 0)
{
throw new Exception("There are no IPv4 network interfaces available");
}
System.DateTime startTime = System.DateTime.Now;
double timeout = IP_TIMEOUT / 1000;
IPEndPoint remEP = new IPEndPoint(IPAddress.Broadcast, iPort);
while (System.DateTime.Now.Subtract(startTime) < TimeSpan.FromSeconds(timeout) &&
!(justFindOne && ipNames.Count() > 0))
{
foreach (var udpC in clients)
{
if (udpC.Available > 0)
{
byte[] response = udpC.Receive(ref remEP);
string name;
if (response.Length > 2)
{
name = System.Text.Encoding.ASCII.GetString(response, 3, response[2]);
if (filter == "" || name.Contains(filter))
{
DiscoveryServer ds = new DiscoveryServer(name, remEP.Address);
ipNames.Add(ds);
if (justFindOne) break;
}
}
}
}
}
}
finally
{
foreach (var udpC in clients)
{
udpC.Close();
}
}
return ipNames;
}
回答3:
I'd try Wireshark.
回答4:
There are a few issues to look into here.
The first is: are you sure multicast is the best way of doing this? I think broadcast would serve you better.
The other is: routers generally don't forward multicast or broadcast, switches and hubs do.
Take a look at the following two questions: Why are (UDP multicast) packets not being received? and UDP Multicast over the internet?
EDIT:
When you create your UdpClient you can specify which local endpoint you will be sending from. http://msdn.microsoft.com/en-us/library/k227d11f.aspx
回答5:
In your code, you do not setup the TTL for your call to UdpClient. So if the default TTL is 1, then your packets won't get past the first router.
来源:https://stackoverflow.com/questions/4036975/why-are-my-udp-multicast-not-reaching-machines-on-the-network