问题
I need to send a UDP message to specific IP and Port.
Since there are 3 network cards,
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.
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);
回答1:
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.
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.
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.
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.
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.
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.
回答2:
I solved this problem by sending the UDP broadcast from each adapter (using bind):
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;
}
回答3:
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.
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);
}
}
}
}
}
回答4:
If you are sending to a specific IP address then you are unicasting, not broadcasting.
来源:https://stackoverflow.com/questions/1096142/broadcasting-udp-message-to-all-the-available-network-cards