我需要发送一个UDP信息到指定的IP和端口。
由于有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);
这实际上比听上去还要棘手,因为如果你有多个接口的广播将不会经常出去到所有的接口。 为了解决这个问题,我创建这个类。
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.Broadcast
和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);
此外,你应该注意,当您使用特定的ipaddress
,而不是广播的路由表只发送它的地址相匹配的接口。
因此,在您的例子中,使用单播。 您需要设置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);
由于路径被关闭,你可能会看到它的所有接口,但你将需要测试本作的单播情况。
如果你不关心发送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块的网络问题。
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
}
编辑:见上述变化具有多个接口,并且还以单播问题试图单播数据包到可用网络。
雷克斯的答案扩展。 这可以让你不必硬编码要播出的IP地址。 遍历所有的接口,检查是否他们都在涨,确保它具有IPv4的信息,以及IPv4地址与它关联。 只是改变了“数据”变量任何数据要播了,“目标”端口,一个你想要的。 小缺点是,如果接口有多个与之相关的IP地址,它会广播出每个地址。 注意:这也将尝试通过任何VPN适配器发送广播(通过网络和共享中心/网络连接,赢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);
}
}
}
}
}
我通过(使用绑定)从每个适配器发送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;
}
如果您要发送到特定的IP地址,然后你是单播,不广播。