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

C# 如何使用UDP广播进行网络发现,c#,udp,broadcast,cdp,lldp,C#,Udp,Broadcast,Cdp,Lldp,我想在C#中使用UDP广播进行网络发现。我不知道怎么做。你能给我建议怎么做吗 我想这样做。用C做同样的事情很简单# 服务器: var Server = new UdpClient(8888); var ResponseData = Encoding.ASCII.GetBytes("SomeResponseData"); while (true) { var ClientEp = new IPEndPoint(IPAddress.Any, 0); var ClientReques

我想在C#中使用UDP广播进行网络发现。我不知道怎么做。你能给我建议怎么做吗


我想这样做。

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

我有同样的问题,但对我来说并不像@rufanov所说的那么容易

以下是我遇到的一些情况:

  • 由于我的应用程序在具有多个网络接口的计算机中正常运行,因此我遇到了一个问题,即广播消息仅在其中一个适配器中发送。为了解决这个问题,我必须首先获得所有网络适配器列表,然后逐个发送广播消息并接收应答消息
  • 将正确的localIpEndPoint绑定到适配器ip地址是很重要的,否则发送时广播地址会出现问题
经过一些研究和工作,我得到了这个解决方案。此代码对应于服务器端,将对响应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;
}
public static void SNCT\u SendBroadcast(列表外设备列表)
{
DeviceList=新列表();
字节[]数据=新字节[2];//广播数据
数据[0]=0x0A;
数据[1]=0x60;
IPEndPoint ip=新IPEndPoint(IPAddress.Broadcast,45000);//广播ip地址和相应的端口
NetworkInterface[]NIC=System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces();//获取计算机的所有网络接口
foreach(NIC中的网络接口适配器)
{
//仅选择以太网类型且支持IPv4的接口(对于最小化等待时间很重要)
如果(adapter.NetworkInterfaceType!=NetworkInterfaceType.Ethernet){continue;}
if(adapter.Supports(NetworkInterfaceComponent.IPv4)=false){continue;}
尝试
{
IPInterfaceProperties adapterProperties=adapter.GetIPProperties();
foreach(adapterProperties.UnicastAddresses中的var ua)
{
if(ua.Address.AddressFamily==System.Net.Sockets.AddressFamily.InterNetwork)
{
//在适配器中发送广播
//1) 将套接字设置为UDP客户端
Socket bcSocket=新套接字(AddressFamily.InterNetwork,SocketType.Dgram,ProtocolType.Udp);//广播套接字
//2) 设置socker选项
bcSocket.SetSocketOption(SocketOptionLevel.Socket,SocketOptionName.Broadcast,1);
bcSocket.ReceiveTimeout=200;//接收超时200ms
//3) 绑定到当前选定的适配器
IPEndPoint myLocalEndPoint=新IPEndPoint(ua.Address,45000);
bcSocket.Bind(myLocalEndPoint);
//4) 发送广播数据
bcSocket.SendTo(数据,ip);
//在适配器中接收广播
int BUFFER_SIZE_ANSWER=1024;
字节[]缓冲区应答=新字节[缓冲区大小应答];
做
{
尝试
{
bcSocket.Receive(bufferAnswer);
DeviceList.Add(GetMyDevice(bufferAnswer));//获取设备信息的相应函数。取决于应用程序。
}
捕捉{break;}
}while(bcSocket.ReceiveTimeout!=0);//修复了支持广播的每个适配器的接收超时
bcSocket.Close();
}
}
}
捕获{}
}
返回;
}

我知道它很老了,但有些人可能仍然需要它……公认的答案很好,但在服务器端做了一些小小的调整,它就更好了

修复Ilya Suzdalnitski评论(锁定第二个客户端。接收呼叫):


因为每次响应后,服务器都会关闭并重新创建,因此它可以无休止地工作而不锁定。

这里有一个不同的解决方案,它是无服务器的。我需要让一群树莓法律专业人士在网络上相互了解,但无法保证谁会活跃。因此,这种方法允许每个人都成为客户!GitHub上提供了完整的库(免责声明:我创建的),这使得整个过程对于UWP应用程序来说真的非常简单

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

一般机制:

发现你的衣服

建立你的听众

处理传入数据

发送消息

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

作为奖励,您可以让每个设备发送他们知道的设备列表。这允许您在发送方意识到您时不响应,从而最小化udp通信量。您甚至可以让接收者将列表与自己的列表进行比较,以发现其他设备


冗余是UDP的朋友,无法保证数据包会被发送。

有关工作示例,请参阅该项目:

服务器定期发送广播消息。客户端接收并处理它们。许多主机信息(操作系统版本、IP地址、网络接口等)发送错误。

它只是将一个包含指定数据的UDP包发送到255.255.255.255-本地网络的广播地址。如果您的计算机和服务器之间没有任何“智能硬件”(如路由器),则它必须响应此包。在所有网络上进行迭代对于意见来说是过分的-大多数发送的包无论如何都不会被交付。。但是,也可以通过遍历
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();
}
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();
        }
    }
}