c# - 向所有可用网卡广播 UDP 消息

标签 c# udp udpclient multihomed

我需要向特定 IP 和端口发送 UDP 消息。

由于有3张网卡,

10.1.x.x
10.2.x.x
10.4.x.x

当我发送一条 UDP 消息时,我只在一个网络适配器中接收消息...其余的 ip 没有接收到。

我想在发送消息时检查网络适配器。我该怎么做?


目前我使用的是:

IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Parse(LocalIP), 0);
IPEndPoint targetEndPoint = new IPEndPoint(TargetIP, iTargetPort);
UdpClient sendUdpClient = new UdpClient(localEndPoint);
int numBytesSent = sendUdpClient.Send(CombineHeaderBody, CombineHeaderBody.Length, targetEndPoint);

最佳答案

这实际上比听起来更棘手,因为如果您有多个接口(interface),广播将不会总是发送到所有接口(interface)。为了解决这个问题,我创建了这个类。

public class MyUdpClient : UdpClient
{
   public MyUdpClient() : base()
   {
      //Calls the protected Client property belonging to the UdpClient base class.
      Socket s = this.Client;
      //Uses the Socket returned by Client to set an option that is not available using UdpClient.
      s.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
      s.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontRoute, 1);
   }

   public MyUdpClient(IPEndPoint ipLocalEndPoint) : base(ipLocalEndPoint)
   {
      //Calls the protected Client property belonging to the UdpClient base class.
      Socket s = this.Client;
      //Uses the Socket returned by Client to set an option that is not available using UdpClient.
      s.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
      s.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontRoute, 1);
   }

}

然后通过广播发送 UDP 数据包,我使用类似下面的东西。我正在使用 IPAddress.BroadcastMyUdpClient,这与您的代码不同。

IPEndPoint  localEndPoint  = new IPEndPoint(IPAddress.Parse(LocalIP), 0);
IPEndPoint  targetEndPoint = new IPEndPoint(IPAddress.Broadcast, iTargetPort);
MyUdpClient sendUdpClient  = new MyUdpClient(localEndPoint);
int numBytesSent = sendUdpClient.Send(CombineHeaderBody, CombineHeaderBody.Length, targetEndPoint);

此外,您应该注意,当您使用特定的 ipaddress 而不是广播时,路由表只会将其发送出与地址匹配的接口(interface)。

因此在您的示例中,使用了单播。您需要将 LocalIP 设置为您要发送到的本地接口(interface)的 IP。使用三个接口(interface),您将拥有三个本地 IP,您需要选择正确的一个来使用。

IPEndPoint  localEndPoint  = new IPEndPoint(IPAddress.Parse(LocalIP), 0);
IPEndPoint  targetEndPoint = new IPEndPoint(TargetIP, iTargetPort);
MyUdpClient sendUdpClient  = new MyUdpClient(localEndPoint);
int numBytesSent = sendUdpClient.Send(CombineHeaderBody, CombineHeaderBody.Length, targetEndPoint);

因为路由已关闭,您可能会在所有接口(interface)上看到它,但您需要针对单播情况进行测试。

如果您不关心发送 IP 或端口,您可以使用以下代码。

IPEndPoint  targetEndPoint = new IPEndPoint(TargetIP, iTargetPort);
MyUdpClient sendUdpClient  = new MyUdpClient();
int numBytesSent = sendUdpClient.Send(CombineHeaderBody, CombineHeaderBody.Length, targetEndPoint);

或广播

IPEndPoint  targetEndPoint = new IPEndPoint(IPAddress.Broadcast, iTargetPort);
MyUdpClient sendUdpClient  = new MyUdpClient();
int numBytesSent = sendUdpClient.Send(CombineHeaderBody, CombineHeaderBody.Length, targetEndPoint);

IPAddress.Broadcast 的问题在于它们不会通过任何网关进行路由。要解决这个问题,您可以创建一个 IPAddresses 列表,然后循环发送。此外,由于发送可能因您无法控制的网络问题而失败,因此您还应该有一个 try/catch block 。

ArrayList ip_addr_acq = new ArrayList();

ip_addr_acq.Add(IPAddress.Parse("10.1.1.1")); // add to list of address to send to

try
{
   foreach (IPAddress curAdd in ip_addr_acq) 
   {
       IPEndPoint  targetEndPoint = new IPEndPoint(curAdd , iTargetPort);
       MyUdpClient sendUdpClient  = new MyUdpClient();
       int numBytesSent = sendUdpClient.Send(CombineHeaderBody, CombineHeaderBody.Length, targetEndPoint);

       Thread.Sleep(40); //small delay between each message
    }
 }
 catch
 {
 // handle any exceptions
 }

编辑:见上文更改为具有多个接口(interface)的单播以及Problem Trying to unicast packets to available networks.

关于c# - 向所有可用网卡广播 UDP 消息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1096142/

相关文章:

c# - 如何生成随机值以在 wpf 中绘制条形图?

c# - 序列化对象消失(BinaryFormatter)

c# - Webmatrix 检查项目是否在集合中,返回 bool 值

c# - 如何增加 Linq2Entities 中的超时时间?

c# - 如何确定哪个 EndPoint 导致错误代码 10054 的 SocketException? ("An existing connection was forcibly closed by the remote host.")

c - C中的服务监听返回-1

c# - 是否应处置 UdpClient?

udp - 本地主机上 UDP 的可靠性

go - 如何在服务器的GoLang CoAP中编写服务端点PUT请求方法?

linux - 客户端 UDP 套接字绑定(bind)