C# 向所有可用网卡广播 UDP 消息
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1096142/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Broadcasting UDP message to all the available network cards
提问by Anuya
I need to send a UDP message to specific IP and Port.
我需要向特定的 IP 和端口发送 UDP 消息。
Since there are 3 network cards,
因为有3张网卡,
10.1.x.x
10.2.x.x
10.4.x.x
when i send a UDP message,i am receiving the message only in one network adapter...the rest of the ip's are not receiving.
当我发送 UDP 消息时,我只在一个网络适配器中接收消息……其余的 ip 没有接收。
I want to check for the network adapter while sending the message. How can I do that?
我想在发送消息时检查网络适配器。我怎样才能做到这一点?
Currently I am using the following:
目前我正在使用以下内容:
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);
采纳答案by Rex Logan
This is actually trickier than it sounds because if you have more than one interface the broadcasts will not always go out to all the interfaces. To get around this I created this class.
这实际上比听起来要棘手,因为如果您有多个接口,则广播不会总是传到所有接口。为了解决这个问题,我创建了这个类。
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);
}
}
Then to send the UDP packet via broadcast, I use something like the following. I am using IPAddress.Broadcast
and MyUdpClient
, which is different from your code.
然后通过广播发送 UDP 数据包,我使用如下内容。我正在使用IPAddress.Broadcast
and MyUdpClient
,这与您的代码不同。
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);
Also, you should note that when you use a specific ipaddress
instead of broadcast the route table only sends it out the interface that matches the address.
此外,您应该注意,当您使用特定ipaddress
而不是广播时,路由表仅将其发送到与地址匹配的接口。
So in your example, unicast is used. You need to set LocalIP
to the IP of the local interface you want to send out to. With three interfaces, you would have three local IP's and you need to pick the correct one to use.
因此,在您的示例中,使用了单播。您需要设置LocalIP
为要发送到的本地接口的 IP。使用三个接口,您将拥有三个本地 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);
Because route is turned off you might see it on all interfaces but you will need to test this for the unicast case.
由于路由已关闭,您可能会在所有接口上看到它,但您需要针对单播情况对此进行测试。
If you don't care about the send IP or port you can use the following code.
如果您不关心发送 IP 或端口,则可以使用以下代码。
IPEndPoint targetEndPoint = new IPEndPoint(TargetIP, iTargetPort);
MyUdpClient sendUdpClient = new MyUdpClient();
int numBytesSent = sendUdpClient.Send(CombineHeaderBody, CombineHeaderBody.Length, targetEndPoint);
or for broadcast
或广播
IPEndPoint targetEndPoint = new IPEndPoint(IPAddress.Broadcast, iTargetPort);
MyUdpClient sendUdpClient = new MyUdpClient();
int numBytesSent = sendUdpClient.Send(CombineHeaderBody, CombineHeaderBody.Length, targetEndPoint);
The problem with IPAddress.Broadcast
is that they will not route through any gateways. To get around this you can create a list of IPAddresses
and then loop through and send. Also since Send can fail for network issues that you cannot control you should also have a try/catch block.
问题IPAddress.Broadcast
在于它们不会通过任何网关进行路由。为了解决这个问题,您可以创建一个列表,IPAddresses
然后循环并发送。此外,由于发送可能会因您无法控制的网络问题而失败,因此您还应该有一个 try/catch 块。
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
}
Edit: see above change to unicast with multiple interfaces and also Problem Trying to unicast packets to available networks.
编辑:请参阅以上更改为具有多个接口的单播以及尝试将数据包单播到可用网络的问题。
回答by Simeon Pilgrim
If you are sending to a specific IP address then you are unicasting, not broadcasting.
如果您要发送到特定 IP 地址,那么您是单播,而不是广播。
回答by Rahly
Expansion of Rex's Answer. This allows you to not have to hard code the ip addresses that you want to broadcast on. Loops through all interfaces, checks if they are up, makes sure it has IPv4 information, and an IPv4 address is associated with it. Just change the "data" variable to whatever data you want to broadcast, and the "target" port to the one you want. Small drawback is that if an interface has multiple ip addresses associated with it, it will broadcast out of each address. Note: this will ALSO try to send broadcasts through any VPN adapter (via Network and Sharing Center/Network Connections, Win 7+ verified), and if you want to receive responses, you will have to save all the clients. You also will not need a secondary class.
扩展 Rex 的答案。这使您不必对要广播的 IP 地址进行硬编码。循环遍历所有接口,检查它们是否已启动,确保它具有 IPv4 信息,并且有一个 IPv4 地址与之关联。只需将“数据”变量更改为您想要广播的任何数据,并将“目标”端口更改为您想要的。一个小缺点是,如果一个接口有多个关联的 ip 地址,它将从每个地址广播出去。注意:这也将尝试通过任何 VPN 适配器发送广播(通过网络和共享中心/网络连接,Win 7+ 验证),如果您想接收响应,则必须保存所有客户端。您也不需要二级课程。
foreach( NetworkInterface ni in NetworkInterface.GetAllNetworkInterfaces() ) {
if( ni.OperationalStatus == OperationalStatus.Up && ni.SupportsMulticast && ni.GetIPProperties().GetIPv4Properties() != null ) {
int id = ni.GetIPProperties().GetIPv4Properties().Index;
if( NetworkInterface.LoopbackInterfaceIndex != id ) {
foreach(UnicastIPAddressInformation uip in ni.GetIPProperties().UnicastAddresses ) {
if( uip.Address.AddressFamily == AddressFamily.InterNetwork ) {
IPEndPoint local = new IPEndPoint(uip.Address.Address, 0);
UdpClient udpc = new UdpClient(local);
udpc.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
udpc.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontRoute, 1);
byte[] data = new byte[10]{1,2,3,4,5,6,7,8,9,10};
IPEndPoint target = new IPEndPoint(IPAddress.Broadcast, 48888);
udpc.Send(data,data.Length, target);
}
}
}
}
}
回答by merce_00
I solved this problem by sending the UDP broadcast from each adapter (using bind):
我通过从每个适配器发送 UDP 广播(使用绑定)解决了这个问题:
public static void SNCT_SendBroadcast(out List<MyDevice> DevicesList)
{
DevicesList = new List<MyDevice>();
byte[] data = new byte[2]; //broadcast data
data[0] = 0x0A;
data[1] = 0x60;
IPEndPoint ip = new IPEndPoint(IPAddress.Broadcast, 45000); //braodcast IP address, and corresponding port
NetworkInterface[] nics = System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces(); //get all network interfaces of the computer
foreach (NetworkInterface adapter in nics)
{
// Only select interfaces that are Ethernet type and support IPv4 (important to minimize waiting time)
if (adapter.NetworkInterfaceType != NetworkInterfaceType.Ethernet) { continue; }
if (adapter.Supports(NetworkInterfaceComponent.IPv4) == false) { continue; }
try
{
IPInterfaceProperties adapterProperties = adapter.GetIPProperties();
foreach (var ua in adapterProperties.UnicastAddresses)
{
if (ua.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
{
//SEND BROADCAST IN THE ADAPTER
//1) Set the socket as UDP Client
Socket bcSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); //broadcast socket
//2) Set socker options
bcSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
bcSocket.ReceiveTimeout = 200; //receive timout 200ms
//3) Bind to the current selected adapter
IPEndPoint myLocalEndPoint = new IPEndPoint(ua.Address, 45000);
bcSocket.Bind(myLocalEndPoint);
//4) Send the broadcast data
bcSocket.SendTo(data, ip);
//RECEIVE BROADCAST IN THE ADAPTER
int BUFFER_SIZE_ANSWER = 1024;
byte[] bufferAnswer = new byte[BUFFER_SIZE_ANSWER];
do
{
try
{
bcSocket.Receive(bufferAnswer);
DevicesList.Add(GetMyDevice(bufferAnswer)); //Corresponding functions to get the devices information. Depends on the application.
}
catch { break; }
} while (bcSocket.ReceiveTimeout != 0); //fixed receive timeout for each adapter that supports our broadcast
bcSocket.Close();
}
}
}
catch { }
}
return;
}