c# - 查找监听本地网络上特定端口的服务器

标签 c# networking tcp

我有一个服务器应用程序。我也有一个客户端应用程序。当两个应用程序碰巧在同一网络上时,我能够在应用程序之间建立 tcp 连接。所以假设运行服务器应用程序的计算机正在监听端口 2121 上的新连接,并且它的 LAN ip 地址为 192.168.0.120。在另一台运行客户端应用程序的计算机上,我将能够通过提供端口号 2121 和 IP 地址 192.168.0.120 来建立连接。

有没有办法找到网络上所有正在监听端口 2121 的计算机?

我现在想到的一个算法是这样的:

  • 获取当前计算机的 ip 地址,假设它显示为 192.168.0.145。

  • 现在服务器很可能会监听 IP 地址 192.168.0。?

  • 然后在端口 2121 上 ping 192.168.0.1,然后在端口 2121 上 ping 192.168.0.2 ... 然后继续。

我不知道这种方法是否有效。此外,服务器可能恰好正在监听 IP 地址 192.168.1.x

那么我必须对我的服务器和客户端应用程序进行哪些更改,以便客户端能够找到所有监听端口 2121 的服务器?

最佳答案

您提出的算法正是您所需要的。一个问题是候选 IP 地址的动态生成。

通常,可能的 IP 地址范围是子网掩码给出的范围 ( http://en.wikipedia.org/wiki/Subnetwork )。更确切地说,IP 的变化部分是在子网掩码中有 0 位(总是在掩码末尾)时的那部分。

在你的例子中:

  • 如果掩码是 255.255.255.0,那么您可能的 IP 地址范围是 192.168.0.*。
  • 如果 IP 也可以是 192.168.1.* 那么掩码可能应该是 255.255.0.0
  • 你也可以使用像 255.255.255.128 这样的掩码,范围是 192.18.1.[1-126]。您实际上可以使用 http://www.subnet-calculator.com/ 了解更多信息

我认为具有这些不同范围的唯一导致您的问题的其他可能性是:

  • 你的网络中有更多的 DHCP 服务器,这真的很糟糕,因为你会有“竞争条件”。这里的解决方案是通过删除除 1 个 DHCP 服务器之外的所有服务器来修复您的基础架构
  • 您已经手动设置了 IP 地址(可能是在笔记本电脑上)。解决方案是更改为 DHCP(如果您需要始终分配给特定计算机的特定 IP,请使用静态 DHCP)

回到检查“某物”是否正在监听特定端口的问题,ICMP 协议(protocol)在这里并不是最好的,因为大多数防火墙都会过滤广播 ICMP 和单个 ICMP。 如果我们真的在谈论服务器,很可能您必须手动打开您要查找的端口。此外,即使所有计算机都响应,您仍然不知道它们是否托管您想要的服务


下面的解决方案涉及计算候选 IP 地址的可能范围。之后,您遍历它们以查看是否可以连接到您的端口

在这个实现中,我按顺序进行测试,事实证明这非常慢,因为如果主机未打开,连接超时为 30 秒。对于数百名候选人来说,这听起来不太好。但是,如果大多数主机可用(即使他们不托管您的服务),一切都会快几倍。

您可以通过找出如何减少此超时来改进程序(我无法在分配的时间内找到方法)或使用自定义超时 How to configure socket connect timeout .您还可以使用多线程并添加在线程安全集合中工作的地址并从那里使用它。

此外,您之前可以尝试 ping (ICMP),但您可能会错过有效的服务器


    static void Main(string[] args)
    {

        Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        int wantedPort = 21;    //this is the port you want

        byte[] msg = Encoding.ASCII.GetBytes("type msg here");


        foreach (NetworkInterface netwIntrf in NetworkInterface.GetAllNetworkInterfaces())
        {

            Console.WriteLine("Interface name: " + netwIntrf.Name);

            Console.WriteLine("Inteface working: {0}", netwIntrf.OperationalStatus == OperationalStatus.Up);

            //if the current interface doesn't have an IP, skip it
            if (! (netwIntrf.GetIPProperties().GatewayAddresses.Count > 0))
            {
                break;
            }

            //Console.WriteLine("IP Address(es):");

            //get current IP Address(es)
            foreach (UnicastIPAddressInformation uniIpInfo in netwIntrf.GetIPProperties().UnicastAddresses)
            {
                //get the subnet mask and the IP address as bytes
                byte[] subnetMask = uniIpInfo.IPv4Mask.GetAddressBytes();
                byte[] ipAddr = uniIpInfo.Address.GetAddressBytes();

                // we reverse the byte-array if we are dealing with littl endian.
                if (BitConverter.IsLittleEndian)
                {
                    Array.Reverse(subnetMask);
                    Array.Reverse(ipAddr);
                }

                //we convert the subnet mask as uint (just for didactic purposes (to check everything is ok now and next - use thecalculator in programmer mode)
                uint maskAsInt = BitConverter.ToUInt32(subnetMask, 0);
                //Console.WriteLine("\t subnet={0}", Convert.ToString(maskAsInt, 2));

                //we convert the ip addres as uint (just for didactic purposes (to check everything is ok now and next - use thecalculator in programmer mode)
                uint ipAsInt = BitConverter.ToUInt32(ipAddr, 0);
                //Console.WriteLine("\t ip={0}", Convert.ToString(ipAsInt, 2));

                //we negate the subnet to determine the maximum number of host possible in this subnet
                uint validHostsEndingMax = ~BitConverter.ToUInt32(subnetMask, 0);
                //Console.WriteLine("\t !subnet={0}", Convert.ToString(validHostsEndingMax, 2));

                //we convert the start of the ip addres as uint (the part that is fixed wrt the subnet mask - from here we calculate each new address by incrementing with 1 and converting to byte[] afterwards 
                uint validHostsStart = BitConverter.ToUInt32(ipAddr, 0) & BitConverter.ToUInt32(subnetMask, 0);
                //Console.WriteLine("\t IP & subnet={0}", Convert.ToString(validHostsStart, 2));

                //we increment the startIp to the number of maximum valid hosts in this subnet and for each we check the intended port (refactoring needed)
                for (uint i = 1; i <= validHostsEndingMax; i++)
                {
                    uint host = validHostsStart + i;
                    //byte[] hostAsBytes = BitConverter.GetBytes(host);
                    byte[] hostBytes = BitConverter.GetBytes(host);
                    if (BitConverter.IsLittleEndian)
                    {
                        Array.Reverse(hostBytes);
                    }

                    //this is the candidate IP address in "readable format" 
                    String ipCandidate = Convert.ToString(hostBytes[0]) + "." + Convert.ToString(hostBytes[1]) + "." + Convert.ToString(hostBytes[2]) + "." + Convert.ToString(hostBytes[3]);
                    Console.WriteLine("Trying: " + ipCandidate);


                    try
                    {
                        //try to connect
                        sock.Connect(ipCandidate, wantedPort);
                        if (sock.Connected == true)  // if succesful => something is listening on this port
                        {
                            Console.WriteLine("\tIt worked at " + ipCandidate);
                            sock.Close();
                            sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                        }
                        //else -. goes to exception
                     }
                    catch (SocketException ex)
                    { 
                        //TODO: if you want, do smth here
                        Console.WriteLine("\tDIDN'T work at " + ipCandidate);
                    }
                }
            }
            Console.ReadLine();
        }
        sock.Close();
    }

关于c# - 查找监听本地网络上特定端口的服务器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7287179/

相关文章:

python - python 的 recvfrom() 队列数据包吗?

c++ - 绑定(bind)到 127.0.0.2

c - 是否可以在未安装 TOR 的情况下连接到 TOR?

c# - 如何基于发布或调试构建模式运行一些代码?

c# - 无法使用 LINQ to XML 读取 XML 注释

C# 获取泛型对象内部的对象

database - 如果我们需要在 cassandra 和 bigcouch 之间进行选择,我们应该考虑哪个标准?

c# - 如何正确和完全关闭/重置 TcpClient 连接?

创建我的第一个 Unix 服务器/客户端,但出现 "shmget: Invalid argument"错误甚至更多。 [C]

c# - 如何将数据表转换为泛型