【问题标题】:How to get IP addresses of hosts on local network running my program如何获取本地网络上运行我的程序的主机的 IP 地址
【发布时间】:2015-11-13 05:48:57
【问题描述】:

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

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

【问题讨论】:

  • 我不明白。为什么需要本地IP?你不需要远程地址吗?
  • @Eser 他们说本地 IP 地址es 这对我来说意味着本地网络。
  • 听起来你指的是端口扫描......这令人不快。
  • 我会改为实现 UDP 广播。您的应用程序将 UDP 数据报发送到 255.255.255.255 广播地址。然后这个数据报被发送到本地网络中的每个主机(当你向 255.255.255.255 发送数据报时会发生这种情况)。您的应用程序还会监听这些 UDP 广播并做出相应的响应。对于每个适当响应的 IP 地址,您可以假设它是您的应用程序,您可以尝试在您的端口上使用 TCP 连接。看看msdn.microsoft.com/en-us/library/tst0kwb1(v=vs.110).aspx

标签: c# sockets tcp port p2p


【解决方案1】:

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

由于许多多媒体设备、路由器等使用基于多播的发现协议,例如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 方法。

【讨论】:

  • 这段代码就像一个魅力!谢谢你。唯一的问题是当一方离开时,控制台上显示的 IP 地址不是离开者的地址,而是其余对等方的 IP 地址。
  • 对于那些想知道如何使用第一个代码段的人,请在应用程序加载后运行它。
  • @0014 您对这个小错误的看法是正确的。我应该在调用PeerLeft 时使用RemovedCallback 的参数,而不是使用捕获的值(from)。我把它留给未来的读者......
  • 我尝试应用您提到的内容,但没有成功。您是否有机会纠正您提到的那个小错误?
【解决方案2】:

我相信如果您正在使用点对点应用程序交换数据包,当您需要知道某人是否“在线并准备好连接”时,您需要发送广播。我们可以使用 UDP 连接轻松完成。

我将发布一个示例,其中您使用两种方法:一种在广播消息中向整个网络询问准备好的客户端,另一种将启动侦听器以回复广播询问消息,或者在响应时启动连接“我在这里”类型的来了。

希望对你有帮助!

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

【讨论】:

    【解决方案3】:

    调用命令提示符执行“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
    

    【讨论】:

    • netstat -n 会给我我正在使用的我已经知道的端口。我需要使用我的应用程序的设备的 IP 地址。我想如何使用这些信息找到 IP 地址?
    • 如果您现在在命令提示符下执行 netstat -n,您将知道要删除和过滤什么。 1.删​​除输出的标题(拒绝第一行) 2.删除所有重复 127.0.0.1 两次的行 3.获取包含:17500 的行 4.只接受带有字符串“TCP”和“ESTABLISHED”的行 5.删除字符串“TCP”、“ESTABLISHED”、、“:17500”,并修剪它
    • 您必须在您的服务器上运行该代码。如果您使用的是点对点(无服务器)。您需要使用端口扫描,列出您要扫描的子网中的所有 IP 地址(一些可以列出子网中所有可能 IP 地址的算法)并扫描开放端口 17500。那些开放端口是运行您的应用程序。您可以在程序中调用一个端口扫描工具nmap.org
    • 对不起,我很好奇并尝试了您的建议,不幸的是它不起作用。我在同一本地网络中的两台不同计算机上打开了我的应用程序,然后在两台计算机上都输入了命令提示符 netstat -n。除了自己之外没有其他电脑的IP数据...
    • 只有当你有一个服务器并且你在服务器上做它时它才能工作
    猜你喜欢
    • 1970-01-01
    • 2012-10-28
    • 2015-11-18
    • 1970-01-01
    • 1970-01-01
    • 2012-09-29
    • 2015-03-01
    • 1970-01-01
    • 2010-09-14
    相关资源
    最近更新 更多