С#: Организуем поиск устройств с помощью UDP-пакетов

Возникла новая задача — разослать всей сети UDP-пакеты и подождать откликнувшихся на них, затем отобразить список найденных устройств. Очень полезная штука. Все бы казалось просто — пропиши клиента и пошли пакет в подсеть, собственно так и было сделано:

UdpClient udp = new UdpClient(4800);
IPAddress ipaddress = IPAddress.Parse("192.168.9.255");
IPEndPoint ipendpoint = new IPEndPoint(ipaddress, 4800);
byte[] message = "Who";
int sended = udp.Send(message, message.Length, ipendpoint);

Все работает отлично, но надо иногда искать устройства и в другой подсети, а для этого нужна маска «255.255.255.255», заменяем «192.168.9.255» на «255.255.255.255» и происходит чудо — не приходит ответ.

С помощью WireShark было установлено — что уходит пакет на первый сетевой адаптер, а нам надо на другой, сказывается Windows 8 и установленная виртуальная машина, которая в систему еще добавляет сетевых адаптеров.
Пришлось дописывать программу, так чтобы она умела рассылать UDP-пакеты по всем сетевым адаптерам с TCP/IP v.4
Собственно не буду сильно расписывать, а приведу только то, что получилось:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Threading;
namespace UDPclient
{
public class UDPWrapper
{
private bool stop_service = false;
List ar = new List();
public List st = new List();
public int cnt_rec = 0;
public UDPWrapper()
{
IPAddress[] ips = Dns.GetHostEntry(Dns.GetHostName()).AddressList;
UdpClient udp_;
foreach (IPAddress curAdd in ips)
{
if (curAdd.AddressFamily == AddressFamily.InterNetwork)
{
IPEndPoint ipSRCpoint = new IPEndPoint(curAdd, 4800);
udp_ = new UdpClient(ipSRCpoint);
udp_.EnableBroadcast = true;
ar.Add(udp_);
ReceiveMessages(udp_);
}
}
}
public void Close()
{
stop_service = true;
foreach (UdpClient udp in ar)
{
udp.Close();
}
}
public int UDP_find()
{
st.Clear();
IPAddress ipaddress = IPAddress.Parse("255.255.255.255");
IPEndPoint ipendpoint = new IPEndPoint(ipaddress, 4800);
byte[] message = "Who";
foreach (UdpClient udp in ar)
{
udp.Send(message, message.Length, ipendpoint);
}
int cnt;
do
{
cnt = cnt_rec;
Thread.Sleep(200);
} while (cnt != cnt_rec);
return cnt_rec;
}
public static bool messageReceived = false;
class UdpState
{
public IPEndPoint e;
public UdpClient u;
}
public void ReceiveCallback(IAsyncResult ar)
{
UdpClient u = (UdpClient)((UdpState)(ar.AsyncState)).u;
IPEndPoint end = (IPEndPoint)((UdpState)(ar.AsyncState)).e;
try
{
Byte[] receiveBytes = u.EndReceive(ar, ref end);
string receiveString = Encoding.ASCII.GetString(receiveBytes);
st.Add(receiveString);
cnt_rec++;
}
catch (Exception e)
{
}
if (stop_service == false)
ReceiveMessages(u);
}
public void ReceiveMessages(UdpClient u)
{
IPEndPoint e = new IPEndPoint(IPAddress.Any, 4800);
UdpState s = new UdpState();
s.e = e;
s.u = u;
u.BeginReceive(new AsyncCallback(ReceiveCallback), s);
}
}
}

А теперь как это использовать:

UDPclient.UDPWrapper udp_finder = new UDPclient.UDPWrapper();
udp_finder.UDP_find();
udp_finder.Close();
// тут парсим udp_finder.st разбия строку как нам надо

Собственно — это мой второй опыт использования C#, но думаю пригодится. Чуть позже выложу сервер, который будет ждать приема данных и отвечать на запрос.