如何获取本地网络上主机的 IP 地址 运行 我的程序

How to get IP addresses of hosts on local network running my program

我构建了一个点对点 C# 视频会议应用程序,它使用特定的 TCP 端口 (17500) 进行音频通信。目前,在我的应用程序界面上,我输入了另一个打开了程序的IP地址,以便进行通信。我想做的是自动找到IP地址。

所以,我认为实现此目的的最佳方法是获取使用相同 TCP 端口号 17500 的本地 IP 地址。我该怎么做?或者是否有任何其他方法使用相同的应用程序获取 IP 地址?

我相信如果您使用点对点应用程序交换数据包,当您需要知道是否有人 "Is Online and Ready for connection" 时,您需要发送广播。我们可以使用 UDP 连接轻松完成。

我将 post 一个使用两种方法的示例:一种在广播消息中向整个网络询问准备就绪的客户端,另一种将启动一个侦听器来回复广播询问消息,或者如果 "i am here" 类型的响应出现,则启动连接。

希望对您有所帮助!

public sealed class UdpUtility
{
    // Our UDP Port
    private const int broadcastPort = 11000;

    // Our message to ask if anyone is ready for connection
    private const string askMessage = "ARE ANYONE OUT THERE?";

    // Our answer message
    private const string responseMessage = "I AM HERE!";

    // We use this method to look for a client to connect with us.
    // It will send a broadcast to the network, asking if any client is ready for connection.
    public void SendBroadcastMessage()
    {
        var udp = new UdpClient(broadcastPort);
        var endpoint = new IPEndPoint(IPAddress.Broadcast, broadcastPort);

        try
        {
            var bytes = Encoding.ASCII.GetBytes(askMessage);
            udp.Send(bytes, bytes.Length, endpoint);
        }
        catch (Exception ex)
        {
            // Treat your connection exceptions here!
        }
    }

    // This method will start a listener on the port.
    // The client will listen for the ask message and the ready message.
    // It can then, answer back with a ready response, or start the TCP connection.
    public void ListenBroadcastMessage()
    {
        var udp = new UdpClient(broadcastPort);
        var endpoint = new IPEndPoint(IPAddress.Broadcast, broadcastPort);

        bool received = false;

        try
        {
            while (!received)
            {
                // We start listening broadcast messages on the broadcast IP Address interface.
                // When a message comes, the endpoing IP Address will be updated with the sender IP Address.
                // Then we can answer back the response telling that we are here, ready for connection.
                var bytes = udp.Receive(ref endpoint);
                var message = Encoding.ASCII.GetString(bytes);

                if (message == askMessage)
                {
                    // Our client received the ask message. We must answer back!
                    // When the client receives our response, his endpoint will be updated with our IP Address.
                    // The other client can, then, start the TCP connection and do the desired stuff.
                    var responseBytes = Encoding.ASCII.GetBytes(responseMessage);
                    udp.Send(responseBytes, responseBytes.Length, endpoint);
                }
                else if (message == responseMessage)
                {
                    // We received a connection ready message! We can stop listening.
                    received = true;

                    // We received a response message! 
                    // We can start our TCP connection here and do the desired stuff.
                    // Remember: The other client IP Address (the thing you want) will be on the
                    // endpoint object at this point. Just use it and start your TCP connection!
                }
            }
        }
        catch (Exception ex)
        {
            // Treat your connection exceptions here!
        }
    }
}

调用命令提示符执行 "netstat -n" 并提取输出。

这是从我编写的程序中提取的一段代码,经过修改以满足您的要求。您仍然需要进一步处理数据以获得 IP 地址

        Process netP = new Process();
        ProcessStartInfo netPI = new ProcessStartInfo();
        netPI.FileName = "cmd";
        netPI.UseShellExecute = false;
        netPI.RedirectStandardOutput = true;
        netPI.RedirectStandardInput = true;
        netPI.RedirectStandardError = true;
        netPI.CreateNoWindow = true;
        netP.StartInfo = NetPI;
        netP.Start();
        while (!netP.Start())
            Thread.Sleep(100);
        StreamWriter sW = netP.StandardInput;
        StreamReader sR = netP.StandardOutput;
        sW.WriteLine("netstat -n")
        sW.Close();
        string data = sR.ReadToEnd();
        sR.Close();
        //Do some further processing to filter out the addresses and extract

如评论中所述,您需要某种对等发现协议。

由于许多多媒体设备、路由器等使用基于多播的发现协议,例如 SSDP,我创建了一个类似的 发现服务 示例。

用法很简单。只需使用

Discoverer.PeerJoined = ip => Console.WriteLine("JOINED:" + ip);
Discoverer.PeerLeft= ip => Console.WriteLine("LEFT:" + ip);

Discoverer.Start();

您的所有客户都将使用相同的代码。


using System;
using System.Net;
using System.Net.Sockets;
using System.Runtime.Caching; // add this library from the reference tab
using System.Text;
using System.Threading.Tasks;

namespace SO
{
    public class Discoverer
    {
        static string MULTICAST_IP = "238.212.223.50"; //Random between 224.X.X.X - 239.X.X.X
        static int MULTICAST_PORT = 2015;    //Random

        static UdpClient _UdpClient;
        static MemoryCache _Peers = new MemoryCache("_PEERS_");

        public static Action<string> PeerJoined = null;
        public static Action<string> PeerLeft = null;

        public static void Start()
        {
            _UdpClient = new UdpClient();
            _UdpClient.Client.Bind(new IPEndPoint(IPAddress.Any, MULTICAST_PORT));
            _UdpClient.JoinMulticastGroup(IPAddress.Parse(MULTICAST_IP));


            Task.Run(() => Receiver());
            Task.Run(() => Sender());
        }

        static void Sender()
        {
            var IamHere = Encoding.UTF8.GetBytes("I AM ALIVE");
            IPEndPoint mcastEndPoint = new IPEndPoint(IPAddress.Parse(MULTICAST_IP), MULTICAST_PORT);

            while (true)
            {
                _UdpClient.Send(IamHere, IamHere.Length, mcastEndPoint);
                Task.Delay(1000).Wait();
            }
        }

        static void Receiver()
        {
            var from = new IPEndPoint(0, 0);
            while (true)
            {
                _UdpClient.Receive(ref from);
                if (_Peers.Add(new CacheItem(from.Address.ToString(), from),
                               new CacheItemPolicy() { 
                                    SlidingExpiration = TimeSpan.FromSeconds(20),
                                    RemovedCallback = (x) => { if (PeerLeft != null) PeerLeft(x.CacheItem.Key); }
                               }
                             )
                )
                {
                    if (PeerJoined != null) PeerJoined(from.Address.ToString());
                }

                Console.WriteLine(from.Address.ToString());
            }
        }
    }
}

现在简单介绍一下算法:

  • 每个客户端每秒多播一个数据包。

  • 如果接收方(每个客户端都有)从不在其缓存中的 IP 获取数据包,它将触发 PeerJoined 方法。

  • 缓存将在 20 秒后过期。如果客户端在这段时间内没有从缓存中的另一个客户端接收到数据包,它将触发 PeerLeft 方法。