Je souhaite effectuer une découverte de réseau à l'aide de la diffusion UDP en C #. Je ne sais pas comment faire ça. Pouvez-vous me donner des conseils sur la façon de le faire?
Je veux faire comme ceci tutorial .
C'est très simple de faire la même chose en C #
Serveur:
var Server = new UdpClient(8888);
var ResponseData = Encoding.ASCII.GetBytes("SomeResponseData");
while (true)
{
var ClientEp = new IPEndPoint(IPAddress.Any, 0);
var ClientRequestData = Server.Receive(ref ClientEp);
var ClientRequest = Encoding.ASCII.GetString(ClientRequestData);
Console.WriteLine("Recived {0} from {1}, sending response", ClientRequest, ClientEp.Address.ToString());
Server.Send(ResponseData, ResponseData.Length, ClientEp);
}
Client:
var Client = new UdpClient();
var RequestData = Encoding.ASCII.GetBytes("SomeRequestData");
var ServerEp = new IPEndPoint(IPAddress.Any, 0);
Client.EnableBroadcast = true;
Client.Send(RequestData, RequestData.Length, new IPEndPoint(IPAddress.Broadcast, 8888));
var ServerResponseData = Client.Receive(ref ServerEp);
var ServerResponse = Encoding.ASCII.GetString(ServerResponseData);
Console.WriteLine("Recived {0} from {1}", ServerResponse, ServerEp.Address.ToString());
Client.Close();
Voici une solution différente sans serveur. J'avais besoin que plusieurs pépites de framboises se connaissent sur un réseau, mais je n'avais aucune garantie quant à savoir qui serait actif. Donc, cette approche permet à chacun d’être un client! La bibliothèque complète est disponible sur GitHub (disclaimer: j'ai créé), ce qui rend ce processus vraiment très facile pour les applications UWP.
https://github.com/mattwood2855/WindowsIotDiscovery
Cette solution suppose que les noms de périphérique sont uniques et que vous souhaitez utiliser des chaînes JSON comme protocole de communication, mais vous pouvez simplement envoyer tout autre format. Aussi, dans la pratique essayez-attrapez tout;)
Le mécanisme général:
Découvrez votre adresse IP
public string IpAddress
{
get
{
var hosts = NetworkInformation.GetHostNames();
foreach (var Host in hosts)
{
if (Host.Type == HostNameType.Ipv4) return Host.DisplayName;
}
return "";
}
}
Configurez votre auditeur
var udpPort = "1234";
var socket = new DatagramSocket();
socket.MessageReceived += ReceivedDiscoveryMessage;
await socket.BindServiceNameAsync(udpPort);`
Gérer les données entrantes
async void ReceivedDiscoveryMessage(DatagramSocket socket, DatagramSocketMessageReceivedEventArgs args)
{
// Get the data from the packet
var result = args.GetDataStream();
var resultStream = result.AsStreamForRead();
using (var reader = new StreamReader(resultStream))
{
// Load the raw data into a response object
var potentialRequestString = await reader.ReadToEndAsync();
// Ignore messages from yourself
if (args.RemoteAddress.DisplayName == IpAddress) return;
// Get the message
JObject jRequest = JObject.Parse(potentialRequestString);
// Do stuff with the data
}
}
Envoyer un message
public async void SendDataMessage(string discoveryMessage)
{
// Get an output stream to all IPs on the given port
using (var stream = await socket.GetOutputStreamAsync(new HostName("255.255.255.255"), udpPort))
{
// Get a data writing stream
using (var writer = new DataWriter(stream))
{
// Write the string to the stream
writer.WriteString(discoveryMessage);
// Commit
await writer.StoreAsync();
}
}
}
L'idée serait d'envoyer un message de découverte contenant votre adresse IP et votre nom. Ensuite, dans la fonction de réception de message, ajoutez les paires ip-name à une liste de périphériques. Ajoutez un peu de logique pour éviter les doublons et mettez à jour l'adresse IP si l'adresse IP change pour un nom donné.
En prime, chaque appareil peut envoyer la liste des appareils qu’il connaît. Cela vous permet de minimiser le trafic udp en ne répondant pas lorsque l'expéditeur a connaissance de vous. Vous pouvez même demander au destinataire de comparer la liste avec sa propre liste pour découvrir d'autres périphériques.
La redondance est votre ami avec UDP, il n'y a aucune garantie qu'un paquet sera livré.
J'avais la même question, mais ce n'était pas si facile pour moi, comme le suggère la réponse de @rufanov.
Voici une situation que j'ai eue:
Après quelques recherches et travaux, je suis arrivé à cette solution. Ce code correspond au côté server et fera la découverte du réseau de tous les périphériques répondant au message braodcast.
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;
}
Je sais que c'est vieux mais que quelqu'un peut encore en avoir besoin ... La réponse acceptée est excellente, mais avec ce petit Tweak côté serveur, c'est encore mieux.
Correction du commentaire Ilya Suzdalnitski (se bloque sur le deuxième appel Client.Receive):
var responseData = Encoding.ASCII.GetBytes("someData");
while (true)
{
var server = new UdpClient(8888);
var clientEp = new IPEndPoint(IPAddress.Any, 0);
var clientRequestData = server.Receive(ref clientEp);
var clientRequest = Encoding.ASCII.GetString(clientRequestData);
Console.WriteLine($"Recived {clientRequest} from {clientEp.Address}, sending
response: {responseData}");
server.Send(responseData, responseData.Length, clientEp);
server.Close();
}
Parce qu'après chaque réponse, le serveur est fermé et recréé, il peut fonctionner sans fin, sans verrouillage.