[英]How to do Network discovery using UDP broadcast
It's very simple to make same thing in C# 在C#中做同样的事情非常简单
Server: 服务器:
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();
Here is a different solution that is serverless. 这是一个无服务器的不同解决方案。 I had a need to have a bunch of raspberry pis be aware of each other on a network, but had no guarantees of who would be active. 我需要让一堆覆盆子在网络上相互了解,但不能保证谁会活跃。 So this approach allows everyone to be a client! 所以这种方法可以让每个人都成为客户! The complete library is available on GitHub (disclaimer: I created) and that makes this whole process really reaaaally easy for UWP apps. 完整的库可以在GitHub上找到(免责声明:我创建),这使得整个过程对于UWP应用来说真的很容易。
https://github.com/mattwood2855/WindowsIotDiscovery https://github.com/mattwood2855/WindowsIotDiscovery
This solution assumes that device names are unique and that you want to use JSON strings as the communication protocol, but you could easily just send any other format. 此解决方案假设设备名称是唯一的,并且您希望使用JSON字符串作为通信协议,但您可以轻松地发送任何其他格式。 Also, in practice try-catch everything ;) 此外,在实践中尝试捕捉一切;)
The general mechanism: 一般机制:
Discover your IpAdress 发现你的IpAdress
public string IpAddress
{
get
{
var hosts = NetworkInformation.GetHostNames();
foreach (var host in hosts)
{
if (host.Type == HostNameType.Ipv4) return host.DisplayName;
}
return "";
}
}
Set up your listener 设置你的听众
var udpPort = "1234";
var socket = new DatagramSocket();
socket.MessageReceived += ReceivedDiscoveryMessage;
await socket.BindServiceNameAsync(udpPort);`
Handle incoming data 处理传入的数据
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
}
}
Send a 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();
}
}
}
The idea would be to send a discovery message containing your ip address and name. 想法是发送包含您的IP地址和名称的发现消息。 Then in the receive message function add the ip-name pairs to a List of devices. 然后在接收消息功能中将ip-name对添加到设备列表中。 Add a little logic to avoid duplicates and update Ip address if the ip changes for a given name. 添加一点逻辑以避免重复,并在ip更改给定名称时更新IP地址。
As a bonus, you can have each device send the list of devices they know about. 作为奖励,您可以让每台设备发送他们了解的设备列表。 This allows you to minimize udp traffic by not responding when the sender is aware of you. 这允许您通过在发件人意识到您时不响应来最小化udp流量。 You can even have the receiver compare the list against their own list to discover other devices. 您甚至可以让接收器将列表与其自己的列表进行比较以发现其他设备。
Redundancy is your friend with UDP, there is no guarantee that a packet will be delivered. 冗余是您与UDP的朋友,无法保证将传送数据包。
I had the same question but it was not that easy for me as the answer that @rufanov suggests. 我有同样的问题但对我来说并不是那么容易,因为@rufanov建议的答案。
Here some situation I had: 我有一些情况:
After some reserch and work I got to this solution. 经过一些研究和工作后,我得到了这个解决方案。 This code corresponds to the server side and will make the network discovery of all devices answering to the braodcast 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;
}
I know it's old but someone may still need this...The accepted answer is great but with this little tweak on the server side it's even better. 我知道它已经老了,但有人可能仍然需要这个......接受的答案很棒,但是在服务器端进行这一小调整就更好了。
Fix for the Ilya Suzdalnitski comment (locks up on the second Client.Receive call): 修复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();
}
Because after each response the server is closed and recreated, it can work endlessly without locking. 因为在每次响应之后服务器被关闭并重新创建,它可以无限制地工作而不会锁定。
For working example, see that project: https://github.com/xmegz/MndpTray 有关工作示例,请参阅该项目: https : //github.com/xmegz/MndpTray
The server periodically sends broadcast messages. 服务器定期发送广播消息。 The client side receive and process them. 客户端接收并处理它们。 Many host information (Os version, IP address, Network interface, etc..) send trought. 许多主机信息(Os版本,IP地址,网络接口等)发送。 udp broadcast cdp lldp udp broadcast cdp lldp
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.