我正在尝试使用UDP多播设置自动发现,并且正在使用来自互联网的一些示例代码。当我在同一台机器上运行客户端和服务器时,这似乎工作正常,但是当我在不同的机器上运行它们时,无论是在我的机器上的VM中运行的机器(virtualBox)还是在其他“真正的”机器上运行它们网络然后其他机器似乎永远不会收到正在广播的消息。
经过一些谷歌搜索后,似乎可能是路由器(SpeedTouch 780)可能正在丢弃数据包的罪魁祸首。我怎样才能检查是否是这种情况?他们可以检查其他事情以尝试追踪问题吗?可能它完全是另一回事吗?
代码:服务器代码
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);
}
}
}
}
和客户:
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);
}
}
编辑
因此,它似乎是出于某种原因在VirtualBox主机网络接口上发布UDP数据包,而不是所有机器连接到的无线网络。只需要弄清楚如何让它不那样做...... 所以在答案中添加了分辨率......
答案 0 :(得分:5)
所以问题是因为我有超过1个活动网络连接,它选择了一个并使用它,这导致UDP数据包在客户端正在侦听的不同网络连接上发送出去。因为我已经安装了虚拟机盒,它已经安装并激活了VirtualBox仅主机网络适配器,因此可以支持仅主机网络连接。当我将VirtualBox切换到仅主机模式时,数据包开始被接收。禁用VirtualBox适配器并切换回桥接连接也有效。
答案 1 :(得分:2)
如果你有多个接口,那么正确的答案就是听取所有接口,如果你没有正确的定义,就不要试着选择一个。
以下是我实现UDP发现服务的方法。它原本打破了,因为我的Virtual Box接口妨碍了在随机IP子网(192.168.56.x)而不是我的实际以太网连接(192.168.0.x)上吞下UDP广播。所以我根据Guge的答案改进了它。它有点冗长,我可能没有以最整洁的方式编写它,但它现在有效。然后,我在所有接口上广播
在所有接口上接收数据(循环),直到超时或单个响应(如果justFindOne = true
)。
由于某种原因,IPv6接口使UDP部分崩溃,所以我只过滤掉IPv4地址。如果有办法解决这两个问题,请纠正我。
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;
}
答案 2 :(得分:1)
我会尝试Wireshark。
答案 3 :(得分:1)
这里有一些问题需要考虑。
首先是:你确定多播是最好的方法吗?我认为广播会更好地为你服务。
另一种是:路由器一般不转发组播或广播,交换机和集线器都可以。
看看以下两个问题: Why are (UDP multicast) packets not being received?和UDP Multicast over the internet?
编辑:
创建UdpClient时,您可以指定要从哪个本地端点发送。 http://msdn.microsoft.com/en-us/library/k227d11f.aspx
答案 4 :(得分:1)
在您的代码中,您没有为调用UdpClient设置TTL。因此,如果默认TTL为1,那么您的数据包将无法通过第一个路由器。