如何使用UDP广播进行网络发现

我想在C#中使用UDP Broadcast进行网络发现。 我不知道该怎么做。 你能告诉我怎么做的建议吗?

我想做这个教程 。

在C#中做同样的事情非常简单

服务器:

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); } 

客户:

 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(); 

这是一个无服务器的不同解决方案。 我需要让一堆树莓派在网络上相互了解,但不能保证谁会活跃。 所以这种方法可以让每个人都成为客户! 完整的库可以在GitHub上找到(免责声明:我创建),这使得整个过程对于UWP应用程序来说真的很容易。

https://github.com/mattwood2855/WindowsIotDiscovery

此解决方案假定设备名称是唯一的,并且您希望使用JSON字符串作为通信协议,但您可以轻松地发送任何其他格式。 此外,在实践中尝试抓住一切;)

一般机制:

发现你的IpAdress

 public string IpAddress { get { var hosts = NetworkInformation.GetHostNames(); foreach (var host in hosts) { if (host.Type == HostNameType.Ipv4) return host.DisplayName; } return ""; } } 

设置你的听众

 var udpPort = "1234"; var socket = new DatagramSocket(); socket.MessageReceived += ReceivedDiscoveryMessage; await socket.BindServiceNameAsync(udpPort);` 

处理传入的数据

 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 } } 

发送消息

 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(); } } } 

想法是发送包含您的IP地址和名称的发现消息。 然后在接收消息function中将ip-name对添加到设备列表中。 添加一点逻辑以避免重复,并在ip更改给定名称时更新IP地址。

作为奖励,您可以让每台设备发送他们了解的设备列表。 这允许您通过在发件人意识到您时不响应来最小化udp流量。 您甚至可以让接收器将列表与其自己的列表进行比较以发现其他设备。

冗余是您与UDP的朋友,无法保证将传送数据包。

我有同样的问题但对我来说并不是那么容易,因为@rufanov建议的答案。

我有一些情况:

  • 由于我的应用程序在具有多个网络接口的计算机中正常运行,因此我遇到了广播消息仅在其中一个适配器中发送的问题。 为了解决这种情况,我必须首先获得所有网络适配器列表,然后逐个发送广播消息并接收应答消息。
  • 将正确的localIpEndPoint绑定到适配器的IP地址非常重要,否则您将通过发送来解决广播地址问题。

经过一些研究和工作后,我得到了这个解决方案。 此代码对应于服务器端,并将使所有设备的网络发现回应braodcast消息。

 public static void SNCT_SendBroadcast(out List DevicesList) { DevicesList = new List(); 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; } 

我知道它已经老了,但是有人可能仍然需要这个……接受的答案很棒,但是在服务器端进行这个小调整就更好了。

修复Ilya Suzdalnitski评论(锁定第二个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(); } 

因为在每次响应之后服务器被关闭并重新创建,它可以无限制地工作而不会锁定。